Министерство образования и науки Российской Федерации Омский государственный университет им. Ф.М. Достоевского
УДК 519...
11 downloads
415 Views
377KB Size
Report
This content was uploaded by our users and we assume good faith they have the permission to share this book. If you own the copyright to this book and it is wrongfully on our website, we offer a simple DMCA procedure to remove your content from our site. Start by pressing the button below!
Report copyright / DMCA form
Министерство образования и науки Российской Федерации Омский государственный университет им. Ф.М. Достоевского
УДК 519.682 ББК 32.973-018я73 Ч 188 Рекомендовано к изданию в качестве учебного пособия учебно-методическим советом математического факультета Рецензенты: канд. физ.-мат. наук, доцент С.В. Зыкин, канд. физ.-мат. наук, доцент А.Л. Агафонов
Ч 188
О.Г. Чанышев Основные элементы языка программирования Icon
Чанышев О.Г. Основные элементы языка программирования Icon: Учебное пособие. – Омск: Изд-во ОмГУ, 2004. – 55 с. ISBN 5-7779-0523-4 Пособие является первой публикацией на русском языке, посвященной мощному средству быстрой разработки программ для систем ИИ, особенно для автоматического анализа естественно-языковых текстов – языку Icon. В основу положена книга Thomas W. Christopher «Icon Programming Language Handbook», однако данное пособие – не перевод. Автор опирается на собственный опыт работы с языком; примеры программ в подавляющем большинстве оригинальны. Для студентов математического факультета.
Учебное пособие
УДК 519.682 ББК 32.973-018я73
Изд-во ОмГУ
Омск 2004
© Чанышев О.Г., 2004 © Омский госуниверситет, 2004
ISBN 5-7779-0523-4 2
ОГЛАВЛЕНИЕ Введение ......................................................................................................... 5 1. О синтаксисе, переменные, декларации ............................................ 11 2. Генераторы 2.1. Every, to, every do............................................................................. 13 2.2. !e – генерация элементов................................................................. 15 2.3. Оператор & – and ............................................................................. 15 2.4. Backtracking и неуспех .................................................................... 15 2.5. Проверка на &null ............................................................................ 16 2.6. Альтернатива |.................................................................................. 16 2.7. Повторы с ограничением. Функция генерации последовательностей.................................................................................... 17 2.8. Coevaluation – «Совычисления» ..................................................... 17 2.9. Множественные арифметические операции сравнения ............... 18 3. Управляющие структуры 3.1. if......................................................................................................... 19 3.2. case of ................................................................................................ 19 3.3. while do ............................................................................................. 19 3.4. until do ............................................................................................... 20 3.5. repeat – повторять до бесконечности. ............................................ 20 4. Символьные множества 4.1. Операции с множествами символов............................................... 21 4.2. Принадлежит ли символ множеству? Функция any ..................... 21 5. Строки ..................................................................................................... 22 5.1. Подстроки......................................................................................... 22 5.2. Операторы для работы со строками............................................... 23 5.3. Функции для преобразования строк............................................... 23 5.4. Функции сканирования строк ......................................................... 24 5.5. Более мощные варианты функций сканирования ......................... 27 6. Списки 6.1. Создание списков............................................................................. 29 6.2. Индексированный доступ к элементам списков ........................... 29 6.3. Операции со списками..................................................................... 29 6.4. Функции для работы со списками.................................................. 30 6.5. Списки как стеки или очереди........................................................ 30 7. Таблицы ................................................................................................... 31 7.1. Сортировка таблиц .......................................................................... 32 7.3. Некоторые другие функции ............................................................ 33 8. Множества ............................................................................................... 34 9. Записи ....................................................................................................... 35 3
10. Процедуры 10.1. Вызов процедур ............................................................................. 36 10.2. Выход из процедуры...................................................................... 38 11. Основные функции для работы с файлами..................................... 39 12. Немного о совыражениях – coexpression .......................................... 41 13. Графический интерфейс 13.1. Атрибуты окна ............................................................................... 44 13.2. Текст – запись в окно и чтение из ................................................ 46 13.3. Диалоги........................................................................................... 47 13.4. Создание меню............................................................................... 48 13.5. Чтение и запись изображений ...................................................... 50 Заключение.................................................................................................. 51 Задачи для закрепления материала........................................................ 52 Список используемой литературы.......................................................... 54
4
Введение В предисловии к одной из лучших монографий, посвященных Прологу [1], И. Братко писал: «В средние века знание латинского и греческого языков являлось существенной частью образования любого ученого. Ученый, владеющий только одним языком, неизбежно чувствовал себя неполноценным, поскольку он был лишен той полноты восприятия, которая возникает благодаря возможности посмотреть на мир сразу с двух точек зрения. Таким же неполноценным ощущает себя сегодняшний исследователь в области искусственного интеллекта, если он не обладает основательным знакомством как с Лиспом, так и с Прологом – этими двумя основополагающими языками искусственного интеллекта, без знания которых невозможен более широкий взгляд на предмет исследования». С полной уверенностью могу добавить к этим языкам и Icon, который прост и могуч во многом потому, что наследует идеологию мощного семейства языков SNOBOL, первые представители которых появились еще в начале 60-х. Название языка не имеет ничего общего с «иконками», а является сокращением от слова «iconoclastic» (иконоборец) [1], используемом в смысле борьбы с конформизмом в разработке языков программирования. Настоящий материал следует рассматривать как введение в программирование на Icon’е. Это – не учебник по программированию, он рассчитан на студентов, уже имеющих опыт программирования на Си или Паскале. «Императивная» внешность Icon’а способствует быстрому усвоению языка. Простота синтаксиса, небольшое, но функционально мощное множество структур данных делают его очень удобным языком быстрого прототипирования, т. е. за более короткое время, чем программирование на Си, можно написать и отладить программу, при помощи которой проверяются основные идеи концепции. Сохраняя внешне стиль императивных языков, на самом деле Icon имеет много инструментов, роднящих его с языками логического программирования. Например, «бэктрекинг», или генераторы. Christopher [2] пишет: «Самое большое различие между Icon'ом и другими языками программирования – это то, что выра5
жения Icon'а – генераторы». Выражения генерируют последовательности значений, используя «бэктрекинг». Пример использования генератора: procedure main() L:=["mmm","nnnnn","oooooo"] # Список строк every writes(" ",! L) end Выход: mmm nnnnn oooooo Icon не является строго типизированным (тип имеют константы, но не переменные). Это и не плохо и не хорошо, но чаще всего удобно. Будьте внимательны и следуйте модульному стилю программирования. Icon обладает мощными встроенными типами данных для организации сложно структурированной информации: ассоциативные таблицы, списки, записи, множества по модулю 2 (автоматически исключающие дублирование), символьные множества. Почти любой тип из этого перечня может быть элементом другого типа. Например, элементами таблиц могут быть списки. Списки могут состоять из записей и т. п. Только не надо специально усложнять структуры. Все должно быть ЦЕЛЕСООБРАЗНЫМ. («Красота – это целесообразность» – Иван Ефремов (?)). Процедуры в Icon'е «относятся к величинам первого класса (first class values, что означает возможность присваивания переменным значений самих процедур, а не результатов их выполнения). В Icon встроен механизм «совыражений» (co-expression) – почти независимо выполняющихся частей программы, что дает возможность как создавать классические сопрограммы, так и реализовывать произвольные псевдопараллельные алгоритмы. Icon поддерживает автоматическую конверсию типов. Icon включает кросс-платформенные графические возможности. Мой собственный опыт подтверждает, что программы на Icon'е быстро разрабатываются, быстро и надежно работают. Я даже стал задумываться: а не изменить ли моей старой любви – Prolog'у?! (Тем более что Icon распространяется свободно (не для коммерческого использования!) и Вы можете свободно распро-
6
Может быть, единственное, что мне не нравится в Icon'е, это семантическая многозначность операционных символов (разрешаемая контекстно). Вот цитата из Cristophera [2, с. 41]:
"The vertical bar, "|", read "«or»", looks like a binary operator but does not behave like one". Другой пример: символ "\" в выражениях "\x" и "|(z to y)\x" обозначает различные операторы (в первом случае проверяется, имеет ли значение переменная x, а во втором – является ли ограничителем генерируемых значений). У Icon’а есть сложности с кириллицей. Он «не понимает» кириллические имена файлов при стандартном открытии f:=open(“имя_моего_файла”,”rt”) либо когда имя файла передается в командной строке icon_prog.exe имя_моего_файла procedure main(args)) f:=open(args[1],”rt”) ………………………. end Чтобы обойти эту сложность, следует работать в графическом режиме и обращаться к соответствующему «диалогу». Большинство проблем при парсировании кириллического текста Вы можете обойти, создав собственное множество символов: allRus:='АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЬЪЫЭ ЮЯабвгдеёжзийклмнопрстуфхцчшщьъыэюя' И при необходимости можете создать объеденное множество: allLetters:= &ascii++allRus ……………………………………………………………….. Теперь несколько слов о математических возможностях Icon’а (которые меня не очень интересуют и в дальнейшем изложении специально не рассматриваются). Язык обладает вполне достаточным набором операторов и функций для того, чтобы быть алгоритмически полным и в «вычислительном» смысле. Он работает с целыми и реальными числами. Имеет специальные средства для манипулирования коплексными и рациональными числами. Бинарные операторы: * – умножение / – деление % – остаток (5%2=1) + – сложение - – вычитание
7
8
странять собственные выполняемые модули (exe – файлы), в отличие от PDC Visual Prolog.) Приведем несколько «программулек» для иллюстрации: procedure main() #Перезапись файла f:=open("x.txt","r")|stop("cannot open x.txt") f2:=open("y.txt","w")|stop("cannot open y.txt") # Классический стиль while s:=read(f) do write(f2,s) close(f) close(f2) end В стиле Icon'а подчеркнутые элементы кода заменит выражение every write(f2,!f) link graphics procedure main() # Простейший вариант открытия графического окна: WOpen("size=400,300") | stop("can't open window") Font("Times New Roman,18") # Устанавливаем шрифт L:=["Линия 1","Линия 2","Линия 3"] case SelectDialog("Выберите линию",L,L[1]) of { "Okey": { GotoRC(1,1) WWrite(dialog_value) # Печатаем выбранную строку WDone() } "Cancel": {} } end
Следует помнить, что звездочка (*), используемая как префиксный оператор, возвращает длину объекта. Информацию о языке, а также дистрибутивы самого языка можно получить по адресу http://www.cs.arizona.edu/icon. Установите Icon (и «пропишите»!). Для написания простых программ (файл с исходным текстом должен иметь расширение.icn) можете пользоваться любым текстовым редактором. Если у Вас сложный проект, состоящий из нескольких icnфайлов, то предварительно компилируются отдельные части программы: wicont –c <имя_файла>.icn Затем для компиляции и получения исполняемого модуля: wicont <имя_главного_файла>.icn Главный icn-файл содержит procedure main(…) и декларативы link с именами файлов проекта: link <имя_1>.icn ………………… link <имя_N>.icn …………………. procedure main(…) …… end procedure p1(…) ……… end procedure pn(…) ……… end
и Idol (объектно-ориентированное раширение Icon. – О.Ч.), распространяемые в исходных текстах. В любом случае изучение этих языков доставит удовольствие и вооружит вас мощнейшим инструментом как быстрого прототипирования сложных программ, так и "реактивного" создания целого класса очень нужных приложений, для которых любой другой инструментарий не подходит из-за слишком больших трудозатрат».
Некоторые книги на английском языке доступны в pdfформате по адресу http://www.cs.arizona.edu/icon/books.htm. Литературные источники по данной теме на русском языке мне не известны, за исключением сотни строк в статье А. Зубинского [2], цитатой из которой я и завершу введение: «Заинтересовавшимся… можно порекомендовать отличную online-версию книги Icon Programming Language Handbook Томаса Кристофера (пригодный к чтению на любых платформах pdf-формат) и сами системы Icon 9
10
1. О синтаксисе, переменные, декларации Возможно, Вы уже обратили внимание на то, что синтаксис языка Icon очень прост. Операторы языка разделяются либо символом перевода строки, либо точкой с запятой (;). Например: every {writes(" ",1 to 5);writes(" ",6 to 10)} или every { writes(" ",1 to 5) writes(" ",6 to 10) } Запятая используется для разделения элементов в разного рода перечислениях. Группы операторов, например, в выражениях if {} then {} else ограничиваются фигурными скобками. Квадратные скобки [] служат, преимущественно, для индексирования выражений (L[3] обозначает третий элемент некоторой структуры). В круглые скобки обычно заключается список параметров или выражения в «совычислениях» – coavaluation. Объявления процедуры начинаются со слова procedure, за которым следует либо main(...), либо <имя_процедуры>(p1,...,pn) с формальными параметрами. Процедура заканчивается словом "end". Процедуры не могут быть вложенными. Все ключевые слова пишутся с маленькой латинской буквы. Имена переменных могут состоять из латинских букв, цифр и знаков подчеркивания. Имена переменных, буквы которых набраны в различных регистрах – разные имена (naMe и name, Name – разные имена).
global – создание переменной, известной всем процедурам (global x,y). procedure <имя_процедуры> – начинает объявление процедуры. record <имя_записи>(<список_имен_полей>) – создает структуру данных, называемых «записью» (record r(x,y,z)). link <имя_внешней_процедуры> указывает редактору, что данная программа использует внешнюю процедуру. invocable <имя_процедуры> – позволяет обращаться к процедуре по имени-строке ("f"(x)). Декларации global, record, link, invocable должны появляться только в начале программы (в преамбуле), до первого объявления какой-либо процедуры. Договоримся на дальнейшее, что, следуя Christopher'у, латинской e или ei, где i – целое, будем обозначать произвольные выражения.
Декларации local – создание переменной, известной только внутри процедуры и существующей до выхода управления из данной процедуры (local x,y). static – создание переменной, известной только внутри процедуры и сохраняющей последнее присвоенное значение в течение выполнения программы в целом (static x,y). 11
12
2. Генераторы Генераторами называются операторы (и выражения), производящие множество значений в контексте генерации. Чтобы понять, как работают генераторы, следует иметь в виду: во-первых, общую для всех языков основную последовательность выполнения выражений – слева направо и сверху вниз с учетом приоритета операторов; во-вторых, возврат назад для того, чтобы найти подвыражение, генерирующее более одного значения, взять новое значение и повторить процесс. Этот возврат с перебором называется бэктрекингом. Прототипами бэктрекинга являются различные конструкции, организующие циклы. Бэктрекинг – «главный кит» Пролога, наряду с подстановкой и унификацией. Он использует его, как нечто само собой разумеющееся. Например, человек, знакомый только с Си, не сможет понять, что предикат p: p:-fact1(_,_,X,_),fact2(_,Y,_), X
Оператор to может генерировать серию значений. Например, в случае 100 to 103 мог бы сгенерировать значения 100, 101, 102, 103, если ему это позволят. В случае write(10 to 20) печатается единственное значение 10. Но every write(1 to 3) напечатает 123. Вариант to by очевиден, by задает шаг. Примеры: every i:=1 to 100 by 10 do write(i) Выход: 1 11 21 .... 91 every {writes(" ",1 to 5); writes(" ",6 to 10)} Выход: 1 6 7 8 9 10 Но every (writes(" ",1 to 5), writes(" ",6 to 10)) дает на выходе: 1 6 7 8 9 10 2 6 7 8 9 10 3 6 7 8 9 10 4 6 7 8 9 10 5 6 7 8 9 10 В данном случае (every (e1,e2)): 1. После генерации первого из возможных значений выражения e1 управление передается выражению e2. 2. e2 генерирует все возможные значения. 3. Затем e1 генерирует следующее значение и т. д. e1 и e2 могут быть успешными и неуспешными. every i:=1 to 5 do writes(" ",i) S:=4 every S<4 do writes(" ",17 to 18) Выход: нет выхода. Если же мы напишем every S<4, то будет напечатано число 17.
14
2.2. !e – генерация элементов Если e – некоторая структура, то !e берет первый элемент структуры, а в контексте генерации генерирует множество элементов этой структуры. Примеры: L:=[1,2];every writes(" ",!L).#Выход: 1 2 s:="cat";every writes(" ",!s).#Выход: c a t Бинарные операции, содержащие генераторы: every writes(" ",5 to 6)+(10 to 20)) напечатает 15 25 16 26 2.3. Оператор & – and e1&e2 Этот оператор возвращает значение правого операнда и имеет наинизший приоритет. every i:=|seq(1,2)\3 & j:=|seq(2,2)\3 & i~= j & writes(" ",i+j) Выход: 3 5 7 5 7 9 7 9 11 2.4. Backtracking и неуспех Перебор прекращается, когда перебирать уже нечего, и управление переходит к следующему выражению. Например, напечать 12345 можно так (не рассматривая очевидный вариант write("12345")): every writes (1 to 5). Этот же результат можно получить, если использовать встроенное в Icon выражение &fail, которое всегда порождает неуспех. write (1 to 5) + &fail. write("\n","O'key") Знак ‘+’ нужен только для конструирования синтаксически правильного выражения, т. е. контекст генерции задается "неуспехом". Тогда мы можем использовать чисто «прологовский» стиль: procedure main() S:="tak pit hochetsa, chto perenochevat negde\n" (sim:=!S, writes(sim),sim=="\n") write("O'key") 15
end Выход: – исходная строка S и O'key с новой строки. Проверка каждого символа на равенство символу перевода строки порождает неуспех вплоть до последнего символа, что заставляет первое подвыражение (sim:=!S) генерировать новые символы. В итоге напечатается строка S, а затем O'key. 2.5. Проверка на &null Унарный оператор ‘\’ успешен, если его операнд имеет значение, отличное от &null, а ‘/’ – в противном случае, т. е. мы можем написать if \x & \y then...". Если x не присвоено значение, мы не можем написать if ~x…, но должны написать if /x … . 2.6. Альтернатива | Вертикальная черта ‘|’, читаемая как «или», смотрится как бинарный оператор, но появляется и в ином контексте. Выражение: e1 | e2 означает генерацию всех элементов e1, а затем – всех e2. procedure main() local x,y,z L:=["Vera","Manja","Tanja"] x:=1 if (\x | \y) then z:=10 (writes(" ",!L) | write(" ",z)) every (writes(" ",!L) | write(" ",z)) #while (writes(" ",!L)) | write(" ",z)) end Выход: Vera Vera Manja Tanja 10 Если раскомментировать выражение перед end, то получим бесконечную печать слова Vera.
16
every writes(" ",(!S,1 to 3)) write() every writes(" ",(!S & 1 to 3)) end Выход: qqqwwweeerrrtttyyyuuu 123123123123123123123 123123123123123123123
2.7. Повторы с ограничением. Функция генерации последовательностей Генератор «с перезарядкой» |e позволяет генерировать все значения e, затем происходит реинициализация и процесс повторяется бесконечно. Чтобы избежать бесконечного повторения процесса, используется ограничитель числа повторений: |e\n. Например: every |(writes(7))\7 выведет 7777777, так же, как и every (writes(|7\7)), и every i:=1 to 7 do writes(7). Специальная функция seq() предназначена для генерации бесконечных рядов значений seq() генерирует 1,2,3,............. seq(i) генерирует i,i+1,i+2........ seq(i,j) генерирует i+j,i+2j,i+3j.. every writes(" ",seq(2,2)\5) выведет 2 4 6 8 10 как и every writes(" ",seq(2,2))\5
2.9. Множественные арифметические операции сравнения Такие операции, как ay или x>:=y
2.8. Coevaluation – «Совычисления» В общем виде совычисления представляются так: e0(e1,e2,...,eN), где e0 – выражение, вычисляющее номер выражения в скобках, которое генерирует значения, и может быть переменной, значение которой есть целое число, вычисляемое где-то в другом месте программы. Действия остальных заключаются в активации бэктрекинга. «Вырожденная» форма: (e1,e2,...,eN) эквивалентна N(e1,e2,...,eN) или (e1&e2&...&eN). Пример: procedure main() K:=1 S:="qwertyu" every writes(" ",K(!S,1 to 3)) write() 17
18
3. Управляющие структуры 3.1. if... if e1 then e2 else e3 if e1 then e2 e1 может генерировать не более одного значения e3 могут генерировать столько значений, сколько позволяет контекст. 3.2. case of
3.4. until do until e1 do e2 Эквивалентно while not e1 do e2 Пример: Печать чисел Фибоначчи procedure main() local i,j i:=1;j:=1 until i>100 do {write(i,j);i+:=j;i:=:j} end 3.5. repeat – повторять до бесконечности.
case e1 of { e2 : e3
i:=1 repeat { if i<10 then {write("i меньше 10");i:=i+1} else break }
e4 : e5 ... e2n : e2n+1 default : e2n+2 } 3.3. while do while e1 do e2 while e1 Генерируется одно значение e1, и если НЕ ЛОЖЬ, то выполняется e2. Пример: i:=0 while i<2 do {writes(" ",i);i+:=1} Выход: 0 1 В следующем примере будут бесконечно «печататься» на экране вводимые Вами строки символов: while write(read( ))
19
20
4. Символьные множества Множества символов заключается в апострофы: 'abcd'. В Icon'е существуют следующие встроенные множества символов: &ascii – 128 символов ASCII. &cset – 256 символов. &digits – цифры ('0123456789'). &lcase – множество символов латиницы в нижнем регистре. &ucase – множество символов латиницы в верхнем регистре. &letters – все символы латиницы (объединение &lcase и &ucase). 4.1. Операции с множествами символов -c – производит множество cset, состоящее из символов, не встречающихся в c. *c – число элементов c. c1**c2 – пересечение c1 с c2. c1++c2 – объединение c1 и c2. c1--c2 – «разность» между c1 и c2. Итоговое множество включает только те символы из c1, которых нет в c2. 4.2. Принадлежит ли символ множеству? Функция any any(c,s) – возвращает 2, если s[1] существует и является элементом множества c. any(c,s,i) – возвращает i+1, если s[i] существует и является элементом множества c.
21
5. Строки S:="This is string" Для того чтобы выбрать i-ый символ строки, следует рассматривать строку как массив символов s:=S[i]. Вы можете присвоить иное значение символу в строке, заданной переменной, но не можете сделать то же самое для строки – литерала: S[1]:="t" – допустимо. "This is string"[1]:="t" – недопустимо. Значение индекса может быть отрицательным целым. procedure main() S:="This is string" writes(S[1]) writes(" ",S[14]) writes(" ",S[-1]) end Выход: T g g 5.1. Подстроки Выделяя подстроки индексированием, следует иметь в виду неочевидное: при указании индексов слева направо первый индекс есть номер левого символа подстроки, второй – правый выбираемый символ, указываемый как <порядковый номер> + 1; при указании подстроки справа налево с использованием отрицательных значений, 0 – есть крайний правый символ, -(n+1) указывает на крайний левый выбираемый символ (n-ый справа). ………………………………………………. S:="This is string" write(S[9:15])# Получим на выходе string. write(S[0:-6])# Получим на выходе string. write(S[15:9])# Получим на выходе string. #Как видим, таким способом подстрока не реверсируется. write(S[2:0])# Получим на выходе his is string write(S[-1:1])# Получим на выходе This is strin write(S[9:12])" Получим на выходе str 22
Вы можете подстроке строки, заданной переменной, присвоить подстроку, но не литералу: S[9:15]:="xxxxxx" – нормально, но не "This is string"[9:15]:="xxxxxxx". S[i+:j] эквивалентно S[i:i+j], S[i-:j] эквивалентно S[i:i-j], 5.2. Операторы для работы со строками procedure main() s1:="String 1" s2:="String 2" s3:="String 3" s4:="String 2" s5:="STRING 2" s7:="string string string" write(s1||" "||s2||" "||s3||" "||s4||" "||"STRING 2") if s1==s2 then write("s1==s2") # Не верно if s1==s3 then write("s1==s3") # Не верно if s2==s4 then write("s2==s4") # Верно if s1»s2 then write("s1»s2") # # Не верно if s1»s2 then write("s1»s2") # Верно if s5»s4 then write(s5»s4) # Верно every write(" ",!s3) # ! – выбор первого символа every write(s3[1 to *s3]) # эквивалентно write(?s3) # ?s3 – выбор произвольного символа end 5.3. Функции для преобразования строк center(s,i) – выравнивание по центру на длину i, если i>*s, то функция возвращает i центральных символов. Работает с кириллицей. center(s,i,s2) – выравнивание по центру на длину i с добавлением слева и справа символов из строки s2. char(i) – возвращает односимвольную строку, соответствующую представлению символа в виде целого числа (от 0 до 255). map(s) – удобно использовать для преобразования строки из верхнего в нижний регистр. 23
map(s1,s2,s3) – каждый символ в s1, встречающийся в s2 в позиции j, заменяется на s3[j]. mapstrs(s,L1,L2) – замена подстрок, L1 и L2 – списки подстрок. Каждая подстрока в s, являющаяся элементом L1, заменяется на соответствующий элемент L2. (Следуют подключить модуль mapstrs из библиотеки Icon'а, т. е. link mapstrs). replace(s1,s2,s3) – каждое появление s2 в s1 заменяется на s3. repl(s,i) – i раз повторяет строку s: s||s...||s. revers(s) – реверсирует s. string(x) – преобразует число или множество символов (cset) в строку. trim(s) – удаляет концевые пробелы из s. 5.4. Функции сканирования строк Общая форма функций сканирования строк: function(x,s,i,j), где x – это то, что мы ищем, s – просматриваемая строка, i – позиция начала поиска, j – позиция завершения поиска. Некоторые функции возвращают первую позицию найденного, другие – все позиции вхождения. any(c,s) – возвращает 2, если s[1] существует и является символом в множестве (cset) , иначе – неуспех. any(c,s,i) – возвращает i+1, если s[i] существует и является символом в множестве (cset) c, иначе – неуспех. any(c,s,i,j) – возвращает i+1 (i<j) , если s[i] существует и является символом в множестве (cset) c, иначе – неуспех. find(s1,s2) – возвращает все начальные позиции вхождения s1 в s2. в пределах от 1 до *s2-*1 (естественно, в контексте генерации, иначе возвращает только позицию первого вхождения). Пример: procedure main() s:="1D2a3b4c5d2a12342a" every writes(" ",find("2a",s)) end Выход: 3 11 17 24
many(c,s) – возвращает позицию, следующую за наиболее длинной подстрокой в s, все символы которой принадлежат символьному множеству c. Возвращает *s+1, если все символы из s принадлежат c. Неуспешна, если s[1] не принадлежит c. many(c,s,i) – все то же, только поиск начинается с позиции i. many(c,s,i,j) – все то же, только рассматривается подстрока s[i:j] (состоящая из символов s[1],s[2],…,s[j-1]). Примеры s:=”abcd”; write(many(&lcase,s)) Выход: 5 s:=”abcD”; write(many(&lcase,s)) Выход: 4 s:=”Dabcd”; if many(&lcase,s) then write(“O’KEY”) else write(“NO!!”) Выход: NO!! match(s1,s2) – возвращает *s1+1, если s2[1:*s1+1]==s1 match(s1,s2,i) – возвращает *s1+I, если s2[i:*s1+i]==s1 match(s1,s2,i,j) – то же самое, только j ограничивает поиск справа. upto(c,s) – возвращает позиции в s от 1 to *s, которые содержат символы из c. Пример: s:=”1D2a3b4c5d” every writes(upto(&digits,s)) Выход 13579 upto(c,s,i) – то же, только поиск в s начинается с позиции i. upto(c,s,i,j) – поиск в s начинается с позиции i и заканчивается в позиции j. В [3] приведен пример программы, выделяющий из строки правильные идентификаторы – цепочки символов, состоящие только из букв латиницы, знаков подчеркивания и цифр (не в первой позиции): #generate identifiers in string 25
procedure idents(s) local i, j, initIdChars, idChars initIdChars := &letters++’_’ idChars := initIdChars++&digits i := 1 while j := upto(initIdChars,s,i) & not any(idChars,s[j-1]) & k := many(idChars,s,j) do { suspend s[j:k] i:=k } end Давайте изменим эту программу так, чтобы она работала и с кириллицей и выводила информацию в файл: global allRus procedure main() allRus:='АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЬЪЫЭ ЮЯабвгдеёжзийклмнопрстуфхцчшщьъыэюя' s:="Это кириллические идентификаторы с первым неправильным: 17и а_85 б56" s1:="a111_d t75" my_file:=open("idents.txt","wt") every write(my_file,idents(s)) end procedure idents(s) local i, j, initIdChars, idChars initIdChars := &letters++'_'++allRus idChars := initIdChars++&digits s ? suspend tab(upto(initIdChars)) & pos(1) | (move(-1),tab(any(~idChars))) & tab(many(idChars)) end Выход: Это кириллические идентификаторы с первым неправильным а_85 б56
26
5.5. Более мощные варианты функций сканирования Функции any, many, match, find не слишком удобны, поскольку требуют сохранять позицию в строке, а также имя строчной переменной. Улучшить ситуацию позволяет оператор сканирования строки ‘?’, используемый в виде s ? e, где s – строка, а e – некоторое выражение. Вычисляя выражение e, Icon использует специальные переменные &subject и &pos. При этом Icon делает следующее: Устанавливает конкретное значение s. Сохраняет предшествующие значения &subject и &pos. &subject присваивает значение s, а &pos устанавливает на 1. Вычисляет e. Восстанавливает сохраненные на шаге 2 значения &subject и &pos. Возвращает значение e. В случае использования оператора ‘?’ наилучший способ изменения &pos – это использование функций tab(i) и move(j). Первая присваивает &pos некоторое абсолютное значение i, а вторая «перемещает» позицию на &pos+j. Обе функции возвращают подстроку между начальной и новой позициями. Примеры: procedure main() s:="aaabbbccc" s ? write(tab(4)) end Выход: aaa
s ? {writes(tab(4));writes(move(4))} end Выход: aaa bbbc Теперь с использованием оператора сканирования строки подпрограмма выделения идентификаторов будет выглядеть так [3, с. 78]: #generate identifiers in string procedure idents(s) local i, j, initIdChars, idChars initIdChars := &letters++’_’ idChars := initIdChars++&digits s ? suspend tab(upto(initIdChars)) & pos(1) | (move(-1),tab(any(~idChars))) & tab(many(idChars)) end
procedure main() s:="aaabbbccc" s ? write(move(4)) end Выход: aaab procedure main() s:="aaabbbccc" 27
28
6. Списки Список – последовательность элементов, разделенных запятой и заключенных в квадратные скобки. Элементами одного списка могут быть различные структуры данных, допустимые в Icon'е, в том числе и списки. 6.1. Создание списков Списки могут быть созданы следующими способами: L:=[] – создается пустой список. L:=list() – создается пустой список. L:=[e1,e2,...,eN] – создается список из N элементов. L:=list(N) – создается список из N элементов, инициализированных значением &null (специальная константа, означающая отсутствие значения у какого-либо элемента). L:=list(N,Val) – создается список из N элементов, каждый из которых имеет значение Val. 6.2. Индексированный доступ к элементам списков Индексированный доступ к элментам списка вполне похож на доступ к элементам строки. L[1], L[2], ...L[*L] – элементы списка от 1-го до последнего. L[5][2] – второй элемент пятого подсписка в списке L. L[3:5] – подсписок из двух элементов (3-й и 4-й). 6.3. Операции со списками !L Возвращает первый элемент списка. В соответствующем контексте генерирует все элементы списка: ?L возвращает случайный элемент списка. L ||| M объединение списков. L === M операция сравнения на равенство успешна, если списки одинаковы. L ~=== M операция сравнения на не равенство успешна, если списки различны.
29
6.4. Функции для работы со списками copy(L) – создает копию L (L1:=copy(L)). set(L) – создает множество из списка (seT:=set(L)). sort(L) – создает новый отсортированный список. Элементы одного типа группируются вместе, составные объекты размещаются в своих группах в порядке их создания. sortf(L,i) – создает новый список. При этом записи и списки с числом полей не больше i располагаются в порядке возрастания их i-х полей. Пример: procedure main() L:=[[1,7,5],[7,6,9],[11,67,7]] every L1:=!sortf(L,2) do every write(" ",!L1) end Выход: 7 6 9 1 7 5 11 67 7 6.5. Списки как стеки или очереди Следующие функции позволяют работать со списками как со стеками или очередями. get(L) – возвращает и удаляет из списка первый элемент. pop(L) – то же самое. pull(L) – возвращает и удаляет из списка последний элемент. push(L,x) – момещает x в список L в качестве 1-го элемента, смещая остальные на одну позицию вправо. push(L,x1,x2,...,xN) – эквивалентно многократному использованию push с двумя аргументами. put(L,x),put(L,x1,x2,...,xN) – вставка элементов в конец списка. Пример: вариант объединения списков L и M: every put(L,!M).
30
7. Таблицы Таблицы – структуры данных, на верхнем уровне иерархии представленные парой «ключ-значение». Ключ может быть любым неструктурированным типом данных. Значение – любым типом: записью, списком, множеством. Создание таблицы: t:=table() Присвоение ключа и значения: t[k]:=v Проверка на наличие ключа: \t[k] – утверждение успешно, если ключ k существует. /t[k] – утверждение успешно, если ключ k не существует. Приведем пару примеров работы с таблицами.
every eL:=Tab1[keY] do every WWrite(!eL) WWrite("###################") } WDone() end Выход: ################### КЛЮЧ овощи капуста картофель лук ################### КЛЮЧ фрукты яблоки виноград груши ###################
Первый пример еще и демонстрирует создание простого графического интерфейса. Мы создаем графическое окно, чтобы кириллические символы выводились в читаемом виде. link graphics procedure main() tab1:=table() names_obj_table1:=["овощи","фрукты"] listEl:=[["капуста","картофель","лук"],["яблоки","виноград"," груши"]] every i:=1 to *names_obj_table1 do { tab1[names_obj_table1[i]]:=list() tab1[names_obj_table1[i]]:=listEl[i] } w:=WOpen("size=400,300")# создаем окно размером 300 на 400 пиксел. Font("Times New Roman,16") # устанавливаем шрифт WWrite("###################") # пишем в графическое окно # Функция key генерирует ключи every keY:=key(tab1) do { WWrite("КЛЮЧ ",keY)
Для сортировки таблиц используется функция sort(t,k)". k=1|2|3|4 Если Вы хотите отсортировать по ключам, параметр k должен быть опущен: sort(t), в противном случае сортировка производится по значениям. Если k=1|2, то результат сортировки представляется в виде [[key1,val1],[key2,val2],...[keyN,valN]]
31
32
Пример из книги Thomas'а W. Christopher'а. Пусть s – строка и мы хотим создать таблицу, ключом в которой будут символы, а значениями – список их номеров в строке. t:=table() every i:=1 to *s & x:=s[i] do { /t[x]:=[] put(t[x],i) } 7.1. Сортировка таблиц
Если k=1|2, то [key1,val1,key2,val2,...,keyN,valN] Если Вы хотите представить таблицу в виде списка списков, не сортируя, сделайте нечто подобное следующему: tab1:=table() s:="Я не хочу тебя видеть, пока ты не умоешься!" every i:=1 to *s & x:=s[i] do { /tab1[x]:=[] put(Tab1[x],i) } list1:=[] # list1 будет содержать ключ-символ в качестве первого элемента # и список(!) номеров позиций его вхождения в строку в качестве следующих # элементов. every list1:=[k:=key(Tab1),tab1[k]] do { every el:=!list1 do every WWrites(" ",!el) WWrite() } WDone() End
8. Множества Мы уже познакомились с объектами типа множество, рассматривая символьные множества. Множество в Icon'е – неупорядоченная «коллекция» объектов без дублирования. Если Вы пытаетесь включить уже существующий объект, он просто не включится. Операции над множествами мы тоже рассмотрели. Остается познакомиться с функциями, ориентированными на роботу со множествами. copy(S) – создает копию множества S. delete(S,x) – удаляет элемент x. insert(S,x) – включает x. member(S,x) – проверяет на принадлежность элемента x множеству S. set() – создает пустое множество. set(L) – создает множество из элементов списка L. sort(S) – создает список из множества S. Однотипные элементы собираются вместе и располагаются в порядке создания. sortf(S,i) – то же самое, только записи и списки сортируются по i-м полям.
Для символа 'т', например, получите: т 11 20 29 7.3. Некоторые другие функции copy(tab) – создает копию таблицы. delete(tab,x) – удаляет из таблицы ключ вместе со значением. insert(tab,x,y) то же, что и T[x]:=y. member(tab,x) – проверка, является ли x ключом в tab.
33
34
9. Записи Запись в Icon'е – именованная структура, состоящая из множества полей. Записи объявляются на самом верхнем уровне, как глобальные объекты или функции. Объявление записи: record r(f1,f2,f3,f4,...), где r – имя записи, f1,f2,f3,f4,... – имена полей записи. r является и конструктом записей. Запись в любом месте программы (очевидно, в пределах какой-либо процедуры) создается следующим образом rec:=r(a,b,c,d,...). В данном случае a,b,c,d,... конкретные начения полей. Доступ к полю записи: r.f2 или r.f3. Если f3 – список, то доступ к элементу списка: r.f3[i]. Но имя поля можно рассматривать как ключ таблицы, и тогда функционально аналогичным выражением будет r["f3"][i]. Возможно и такое выражение pole:=r[2], эквивалентное pole:=r.f2 и pole:=r["f2"] Очевидным образом к записям применяются уже знакомые нам операции (*,!,?) и функция copy. Приведем пример, в котором процедуре передаются значения полей записи: record r(nb,name) procedure main() r1:=r(1,"JOHN") every proc_print(!r1) end procedure proc_print(I) write(I) end
10. Процедуры 10.1. Вызов процедур Наиболее общая форма вызова процедуры: (e0)(e1,e2,...,eN), где: e0 – выражение, вычисляющее имя процедуры, а e1,e2,...,eN – выражения, вычисляющие фактические параметры. Пример invocable "proc1" invocable "proc2" invocable "proc3" procedure main() L:=["proc1","proc2","proc3"] every i:=1 to 3 do L[i](L[i]) end procedure proc1(X) writes(" ",X) end procedure proc2(X) writes(" ",X) end procedure proc3(X) writes(" ",X) end Выход: proc1 proc2 proc3 procedure main() (proc1|proc2|proc3)("O'KEY") end procedure proc1(X) writes(" ",X||"&proc1") end
35
36
procedure proc2(X) writes(" ",X||"&proc2") end
10.2. Выход из процедуры Процедура может быть завершена тремя способами. 1. Процедура завершает работу, когда управление достигнет
procedure proc3(X) writes(" ",X||"&proc3") end Выход: O'KEY&proc1 O'KEY&proc2 O'KEY&proc3 Пример со встроенными функциями: procedure main() f:=open("outp2.txt","wt") plist:=[sin,cos,tan] every i:=1 to 3 do write(f,plist[i](0.5)) end В файл outp2.txt будет выведено: 0.479425538604203 0.8775825618903728 0.5463024898437905
end. 2. Процедура возвращает значение при помощи return. return может возвращать конкретное значение, переменную или &null. Значение может вычисляться «в теле» "return". Примеры: return, return x, return x+y. 3. Процедура возвращает множество значений по одному. Для этого используется оператор suspend. Пример: procedure main() every writes(“ “,proc1()) end procedure proc1() suspend seq()\7 end Выход: 1 2 3 4 5 6 7
Множество параметров процедуры (f) можно представить в виде списка (L) и тогда вызовы процедуры: f(L) f!L "f"(L) "f" ! L Список формальных параметров может быть пустым, их число может быть больше или меньше формальных параметров. Лишние параметры игнорируются, пропущенным или недостающим присваивается значение &null. Пропуск параметров обозначается лишней запятой: f(x,,z). Заметим, что Icon всегда ожидает, когда параметрам-переменным будет присвоено окончательное значение: writes(X:=3," ",X:=4," ",X:=5) напечатает 5 5 5. Но writes(X:=3,Y:=4,Z:=5) напечатает 345 37
38
11. Основные функции для работы с файлами !f – генерирует все строки входного файла в контексте генератора. close(f) – закрывает файл. flush(f) – принудительно разгружает буфер. open(s1,s2) – открывает файл с именем s1 для доступа «в моде» s2. Неуспешна, если файл не может быть открыт.
xdecode(f) – читает из f и декодирует некоторую структуру, которая предварительно была записана в f при помощи xencode(x,f). Для использования этих функций программу необходимо скомпилировать с модулем xcode, т. е. использовать link xcode.
Моды: "a" – открыть файл для дозаписи, "b" – открыть файл для чтения и записи, "c" – создать файл, "r" – открыть для чтения (по умолчанию), "w" – открыть для записи, "t" – транслировать символ конца строки в символ перевода строки, "u" – не транслировать. open(s1) – эквивалентно (s1,"rt"), read() – читать со стандартного входа, read(f) – читать строку из файла f, reads(f) – читать символ из файла f, reads() – читать символ со стандартного входа, reads(f,i) – читать i символов из файла f, seek(f,i) – установить указатель в файле в позицию i, where(f) – получить текущую позицию в файле, write(x1,x2,x3,...,xn) – запись либо на стандартное устройство вывода, либо в файл (файлы), если одно или несколько из xi являются файлами. Например: procedure main() f1:=open("fout1.txt","w") f2:=open("fout2.txt","w") writes(f1,1," ",2,f2,3," ",4) close(f1) close(f2) end
39
40
12. Немного о совыражениях – coexpression В отличие от генераторов, рассмотренных ранее, coexpression генерирует новое значение, если это возможно, при каждом новом обращении к нему. Правда, так называемые «регенерационные» совыражения могут генерировать от начала, но это достигается за счет создания нового совыражения. Coexpression нужно создать при помощи оператора create, а затем активировать при помощи @, чтобы получить результат: procedure main() s:="qwertyuiop" x:=create(!s) writes(" ",*x) writes(" ",@x) writes(" ",*x) writes(" ",@x) writes(" ",*x) end Выход: 0 q 1 w 2 В данном случае *x – дает число сгенерированных значений.
return(@C) end Вызов proc{e1,e2,...,eN} эквивалентен proc([e1,e2,...,eN]), где все ei – совыражения.
Совыражения могут передаваться в процедуры в качестве параметров: ............... proc1(create !s) .............. procedure proc1(C)
Для того чтобы понять, как работают «совыражения» в режиме псевдопараллельного выполнения, приведем два примера, не пожалев места на странице. ......................... S1:="0123456789" S2:="abcdefghik" a:=create !S1 b:=create !S2 while sim1:=@a do { writes(" ",sim1) while sim2:=@b do writes(" ",sim2) write() } ......................... Выход: 0abcdefghik 1 2 3 4 5 6 7 8 9 Совыражение b мы разрядили в один прием, и далее печатаются только значения совыражения a. А теперь заменим второе while на every: ......................... while sim1:=@a do
41
42
Пример. Пронумеруем строки входного файла, перезаписывая их в выходной файл outf.txt: procedure main(args) f:=open(args[1]) outf:=open("outf.txt","wt") x1:=create(seq()) while Sf:=!f do write(outf,@x1," ",Sf) end
{ writes(" ",sim1) every sim2:=@b do writes(" ",sim2) write() } ......................... Выход: 0a 1b 2c 3d 4e 5f 6g 7h 8i 9k Все дело в том, что coexpression – не классический генератор и every «зря старается», создавая контекст генерации. Получим тот же результат, если: while sim1:=@a do{writes(" ",sim1);do writes(" ",@b);write()}
13. Графический интерфейс Для того чтобы работать с графикой в Icon'е, Вашу программу следует «отлинковать» с модулем graphics: link graphics. Основным понятием графического интерфейса, площадкой, на которой развертываются «графические» события, является окно. Окно определяется множеством атрибутов, большая часть которых приведена в нижеследующей таблице (Шаблон: i – значение задается, o – значение берется): 13.1. Атрибуты окна Шаблон Атрибут Комментарий o, i label метка окна o, i pos, posx, posy позиция окна на экране o, i resize флаг возможности изменения размеров пользователем. Значения "on", "off" (по умолчанию). o, i size, height, width размер окна в пикселах o, i lines, columns размер окна в символах i image Имя файла, содержащего рисунок, который явится начальным содержанием окна. -----------------------------------------------------------o, i canvas атрибут, задающий состояние видимости. «hidden», «iconic», «normal», «maximal». Начальное значение: "normal". i iconpos строка, содержащая пару координат ("X1,Y1"), определяющих положение окна с иконкой. o, i iconlabel метка «иконки» o, i iconimage имя файла, содержащего рисунок «иконки». -----------------------------------------------------------o, i echo атрибут, определяющий, будет ли отображаться на экране текст,
43
44
который затем учтется при помощи WRead или WReads. Значения "on","off" (по умолчанию).
"verylight", "white","vertical", "diagonal", "horizontal", "grid", "trellis", "checkers", "grains", "scales", "waves". По умолчанию – "black". -----------------------------------------------------------o, i clipx, clipy верхний левый угол прямоугольника отсечения o, i clipw, cliph ширина и высота прямоугольника отсечения o, i dx, dy смещение для каждой пары координат, добавляемые перед интерпретацией. По умолчанию – 0. Атрибуты в WOpen обычно задаются <имя_атр>=<значение>. Приведем пример создания графического окна. .......... font := "Times New Roman,20" WOpen("label=Пример окна","size=600,400","bg=very light
o, i cursor атрибут, определяющий видимость текстового курсора на экране. Значения "on","off" (по умолчанию). o, i x, y позиция курсора в пикселах o, i row, col позиция курсора в символах ------------------------------------------------------------o, i pointer вид указателя мыши o, i pointerx, pointery позиция укателя в пикселах o, i pointerrow, pointercol позиция укателя в символах ------------------------------------------------------------o displayheight высота экрана в пикселах o displaywidth ширина экрана в пикселах Атрибуты графического контекста --------------------------------------------------------o, i fg цвет основной (линий или текста) П.у. – "black" o, i bg цвет фона. П.у. – "white" --------------------------------------------------------o, i font цвет текста o fheight, fwidth высота и ширина шрифта --------------------------------------------------------o, i linewidth ширина линии в пикселах. П. у. – 1. o, i linestyle стиль линии. Значения – "solid", "dashed", "striped". По умолчанию – "solid". o, i fillstyle атрибут, определяющий, будет ли использоваться pattern при рисовании. Значения "solid", "textured", "masked". o, i pattern шаблон для заливки допустимого пространства при рисовании, когда атрибут "fillstyle" имеет значение "textured" или "masked". Значения "black", "verydark", "darkgray", "gray", "lightgray", 45
gray", "font="||font) | stop("can't open window") .......... 13.2. Текст – запись в окно и чтение из Для операций текстового ввода-вывода в графическом режиме предназначены функции WWrite, WWrites, WRead, WReads, являющиеся аналогами write, writes, read, reads. Запись и чтение производится, начиная с текущей позиции курсора. Курсор может быть установлен при помощи GotoRC(R,C) и Gotoxy(X,Y). Следует иметь в виду, что установка echo=on не работает для кириллических символов. Отображаются при вводе только символы латиницы. При выводе для кириллицы проблем не возникает при соответствующем выборе шрифта. Но единственный способ ввести строку в кириллице – это обратиться к WRead и вводить без «эха». 46
Строки можно записать на экран также при помощи функций: DrawString(x,y,s), CenterString(x,y,s), LeftString(x,y,s) и RightString(x,y,s) В данном случае s – выводимая строка, а x,y – координаты начала вывода, центра строки, крайнего левого символа и крайнего правого символа соответственно. 13.3. Диалоги Для краткого сообщения пользователю используется Notice(S). Выбрать файл (name и path могут быть записаны в кириллице) Вы можете при помощи функции: OpenDialog(caption, filename). Параметры можно опустить. Выбранное имя файла будет загружено в глобальную переменную dialog_value. Например: case OpenDialog("Выберите файл","*.txt") of { "Okay": { f:=open(dialog_value);WWrite(read(f));close(f);Notice("Вы выбрали файл"||dialog_value) EraseArea(1, 1, 600, 400) } "Cancel": {} } Перед установкой цвета Вы можете выбрать его из палитры при помощи ColorDialog(). case ColorDialog() of { "Okay": Notice("Цвет: "||dialog_value) "Cancel": {} } Функции Dialog(W,caption,L1,L2,L3,L4,i) и 47
TextDialog(W,caption,L1,L2,L3,L4,L5,i) позволяют вводить текстовые строки в латинице. caption – это список строк оглавления диалогового окна, L1 – наименования текстовых боксов, L2 – значения боксов по умолчанию, L3 – максимальная ширина боксов в символах, L4 – наименования кнопок. i – номер кнопки по умолчанию, либо 0 – нет кнопок по умолчанию. Функции возвращают имена кнопок, а глобальная переменная dialog_value содержит введенные значения. Пример: case TextDialog("Выберите нужное", ["Строка 1","Строка 2", "Строка 3"],,[32,32,32], ["Okey", "cancel"], 2) of { "Okey": { GotoRC(4,1) every i:=1 to 3 do WWrite(i," "||dialog_value[i]) } "Cancel": {} } 13.4. Создание меню Меню создается функцией WinMenuBar, вызов которой может выглядеть следующим образом: WinMenuBar(W, ["&File", "&Open", "&Save", "E&xit"], ["&Edit", "C&ut", "&Paste", "C&opy"],["&Help", "&About"]) Однако Вы можете создать список, описывающий меню, а затем создать меню: menu := [ ["&Open","E&xit","Т&екстовый диалог","П&росто диалог"], ["&Options", "&Font...","&Залить фоновым цветом"], ["&Help", "&Wi Programming Environment", 48
"Icon &Обзор возможностей учителя", Icon &Language Reference", "I&dol Reference", "Icon &Graphics Facilities Reference", "Icon &Program Library Reference", "&Visual Interface Builder Reference", "&Frequently Asked Questions", "&About..."] ] WinMenuBar ! menu |{GotoRC(5,1);WWrite("Не могу создать меню")} mainloop() Пример обработки команд меню: procedure mainloop() while e := Event() do case e of { ........................................ "&Залить фоновым цветом": { dflt:=&null ColorDialog(,dflt) WAttrib("bg="||dialog_value) EraseArea(&window, 1, 1, 600, 400) } "Т&екстовый диалог": { WAttrib("fg=black") SS:=TextDialog(&window, ["Введите в поля что угодно"], ["1","2","3"], [], [24,24,24], ["Yes","CANCEL"], i) if SS=="Yes" then { D:=dialog_value[1] GotoRC(5,3) WWrite(D) } } 49
"П&росто диалог": { EraseArea(&window, 1, 1, 600, 400) WAttrib("fg=black") GotoRC(1,1);WWrite("Введите строку") WAttrib("echo=on") GotoRC(2,1);SU:=WRead() GotoRC(3,1);WWrite(SU) } .......................................... 13.5. Чтение и запись изображений Для чтения и записи изображений используются функции ReadImage(W,s1,x,y) и WriteImage(W,s,x,y,w,h), s1 и s – файлы, w,h – ширина и высота, W – окно. Работают с *.gif и *.bmp форматами.
50
Заключение
Задачи для закрепления материала
Даже наш краткий обзор возможностей языка Icon дает представление о его мощности и универсальности. Если говорить об эффективности, то могу привести следующий пример (задачи решались на компьютере с процессором Seleron 1700 и оперативной памятью в 512 Мб): последовательный просмотр строк двух текстовых файлов по 14 Mb каждый (~207000 строк) с целью выявления строк, которые удовлетворяют хотя бы одному из шести условий, занимает 2 сек; это не рекорд, но более чем приемлемый результат. Для быстрого создания прототипов сложных систем людьми, привыкшими к императивному стилю в программировании, Icon незаменим.
Задача 1. Напишите программу преобразования русских слов в нижний регистр, предполагая, что Icon не имеет соответствующей встроенной функции для кириллицы. Задача 2. Напишите программу, выделяющую цепочки символов кириллицы (верхний и нижний регистр) из входного текстового файла и выводящие их в некий выходной файл. При этом главная процедура для получения каждого следующего слова в цикле обращается к процедуре чтения строк файла и выделения слов. Последняя возвращает слова, используя для возврата значения оператор suspend. Задача 3. Предположим, что цепочки типа <ФИО> могут быть заданы как «Петров П.П.» и «П.П. Петров». Выделите из входного текста все такие цепочки и преобразуйте их в список записей. Каждая запись содержит поля: фамилия, первый инициал, второй инициал. Распечатайте список. Задача 4. Файл DICT1.txt содержит некоторый словарь на русском языке, каждая статья которого начинается с 3-й позиции с буквы в верхнем регистре. Напишите программу, перезаписи в файл GORA.txt статей, первые строки которых содержат хотя бы одну из подстрок: «горная», «ГОРЫ», «ГОРА». Используйте функции find и any. Задача 5. Создание словаря текста. На входе имеем текст жанра деловой или художественной прозы (файл text.txt), а также «стоп-словарь» stopW.txt. В каждой строке этого файла содержится только одно слово. Напишите программу составления словаря текста, содержащую слова, не принадлежащие «стоп-словарю». Словарь текста составляется в виде таблицы, ключом которой является слово, а значение есть запись, состоящая из номера слова и частоты встречаемости в тексте. Используйте написанную ранее программу преобразования регистров. Задача 6. Напишите программу, в графическом режиме изменяющую шрифт вывода сообщений. Задача 7. В графическом режиме создайте окно, содержащее строку меню, а в основном поле разместите рисунок, представленный файлом im.gif
51
52
Задача 8. Предполагая, что предложения текста ограничиваются точкой, вопросительным или восклицательным знаками, за которыми следует слово «с большой буквы», напишите программу, которая делает следующее: – определяет границы предложений; – выделяет слова и подсчитывает их частоты – число повторение слов в различных предложениях; – для каждого предложения рассчитывает его вес, равный сумме частот входящих слов; – строит и выводит (в графическом режиме) график весов предложений. Усложните программу, введя «стоп-словарь» для исключения служебных слов языка.
53
Список используемой литературы 1. Братко И. Программирование на языке Пролог для искусственного интеллекта. М.: Мир, 1990. 2. Зубинский А. Инструменты скриптинга // Компьютерное обозрение. 2000. № 41. 25–31 октября. 3. Thomas W. Christopher. Icon Programming Language Handbook. http://www.cs.arizona.edu/icon/books.htm
54
Учебное издание
О.Г. Чанышев Основные элементы языка программирования Icon Учебное пособие
Технический редактор Н.В. Москвичёва Редактор Л.Ф. Платоненко Подписано в печать 11.11.04. Формат бумаги 60х84 1/16. Печ. л. 3,4. Уч.-изд. л. 3,1. Тираж 100 экз. Заказ 581. Издательство Омского государственного университета 644077, г. Омск-77, пр. Мира, 55а, госуниверситет
55
56