Студопедия

КАТЕГОРИИ:


Архитектура-(3434)Астрономия-(809)Биология-(7483)Биотехнологии-(1457)Военное дело-(14632)Высокие технологии-(1363)География-(913)Геология-(1438)Государство-(451)Демография-(1065)Дом-(47672)Журналистика и СМИ-(912)Изобретательство-(14524)Иностранные языки-(4268)Информатика-(17799)Искусство-(1338)История-(13644)Компьютеры-(11121)Косметика-(55)Кулинария-(373)Культура-(8427)Лингвистика-(374)Литература-(1642)Маркетинг-(23702)Математика-(16968)Машиностроение-(1700)Медицина-(12668)Менеджмент-(24684)Механика-(15423)Науковедение-(506)Образование-(11852)Охрана труда-(3308)Педагогика-(5571)Полиграфия-(1312)Политика-(7869)Право-(5454)Приборостроение-(1369)Программирование-(2801)Производство-(97182)Промышленность-(8706)Психология-(18388)Религия-(3217)Связь-(10668)Сельское хозяйство-(299)Социология-(6455)Спорт-(42831)Строительство-(4793)Торговля-(5050)Транспорт-(2929)Туризм-(1568)Физика-(3942)Философия-(17015)Финансы-(26596)Химия-(22929)Экология-(12095)Экономика-(9961)Электроника-(8441)Электротехника-(4623)Энергетика-(12629)Юриспруденция-(1492)Ядерная техника-(1748)

Синтаксические диаграммы и функции распознавания цепочек для нетерминальных символов




Лекция 7

Приведенные выше регулярные выражения, как уже говорилось, описывают полный синтаксис языка SPL. Теперь необходимо написать такую программу на языке Си, которая читала бы символ за символом слева направо программы на языке SPL и осуществляла синтаксический анализ текста программы. Рассматривая весь текст программы на SPL как одну цепочку символов, программа синтаксического анализа должна решить, принадлежит ли эта цепочка (программа на SPL) языку, описываемому грамматикой, представленной тринадцатью регулярными выражениями. В случае наличия синтаксической ошибки программа должна выдать сообщение о том, в какой строке программ на SPL имеется ошибка, какая лексема и с какой не совпадает. После этого анализ прекращается. В случае отсутствия ошибок, должно появиться сообщение, что ошибок нет.

Перед тем как изучить последующий материал, следует повторить материал по синтаксическим диаграммам: что это такое и зачем, как обозначаются дуги и правила прохождения дуг, помеченных терминальными и нетерминальными символами. Суть в том, что по каждому регулярному выражению изображается соответствующая синтаксическая диаграмма, а по ней пишется текст функции на Си для распознавания цепочек, выводимых для рассматриваемого нетерминального символа. В этих функциях часто вызывается функция get (), которая возвращает лексему lex. Кроме того, при прохождении дуг, помеченных терминальными символами, необходимо сравнивать имеющуюся в данный момент лексему lex с ожидаемой лексемой lx. Для этого служит функция exam (). В случае совпадения lex и lx считывается новая лексема (вызывается get ()). При несовпадении выдается сообщение об этом и прекращается работа программы. Текст функции exam () приводится ниже.

void exam (int lx)

{

if (lex!=lx)

{

printf (“Не совпадают лексемы lex=%i и lx=%i в строке nst=%i \n”, lex, lx, nst);

exit (1);

}

get ();

return;

}

Текст программы part2.c на Си, которая осуществляет лексический и синтаксический анализ, приведен на рис. В эту программу полностью входит рассмотренная ранее программа лексического анализа part1.c. Однако в ней имеются одно дополнение и одно изменение. В функции main() после вызова get(); следует также вызвать функцию вывода для главного нетерминального символа prog();

Изменение внесено в самом начале функции get(). Вместо

while (nch!=EOF)

{ …

}

следует

if (nch = = EOF)

{

lex = EOF;

return;

}

………

Таким образом, функцией get() при каждом обращении к ней выдается только одна – очередная лексема.

Кроме того, part2. cотличается от part1.c наличием функций, соответствующих каждому нетерминальному символу. Как уже сказано выше, для их написания используются синтаксические диаграммы, полученные в строгом соответствии с регулярными выражениями. Ниже рассмотрим, как это делается конкретно. Первым должен рассматриваться главный нетерминальный символ PROG.

1) PROG → (DCONST |DVARB |DFUNK) * eof

void prog()

{

while (lex!=EOF)

{

switch (lex)

{

case IDEN: dfunc(); break;

case INTL: dvarb(); break;

case CONSTL: dconst(); break;

default: printf(“Ошибка синтаксиса в строке nst=%i. Лексема lex=%i \n”, nst, lex);

}

}

 

return;

}

По диаграмме видно, что если lex!=EOF, то реализуется разветвление по нескольким ветвям в зависимости от lex. Лексема lex может быть IDEN, если описывается функция, INTL при описании переменных и CONSTL – констант. Естественно, производится вызов одной из функций: dfunc(), dvarb(), dconst().

 

2) DCONST → constl CONS (‘,’ CONS)* ‘;’

 

void dconst()

{

// Нет неиспользованной “свежей” лексемы

// Ее нужно получить, вызвав get();

do

{

get();

cons();

} while (lex = = ‘,’);

exam (‘;’);

return;

}

Вначале происходит проход дуги, помеченной терминальным символом constl. Проверка того, что лексема lex была равна constl, осуществляется в функции prog(). Именно там по switch (lex) в случае case CONSL была вызвана функция dconst(). Перед прохождением следующей дуги, обозначенной нетерминальным символом CONS, согласно правилу прохождения дуг синтаксической диаграммы должен быть прочитан очередной терминальный символ (лексема). Напомним, что лексема constl уже использована. “Свежей” лексемы нет. Поэтому в функции dconstl перво-наперво считывается новая лексема (вызов get()), а затем уже вызывается функция

cons(), соответствующая нетерминальному символу CONS. Цикл осуществляется пока lex = =’,’. В случае выхода из цикла проверяется условие, что lex==’;’. Для этого вызывается exam (‘;’). Если это условие выполняется, то функция exam() в конце вызывает get() и, таким образом, поставляет “свежую” лексему, необходимую для дальнейшего синтаксического анализа.

 

 

3) CONS → iden ’=’ [ ‘+ ’| ’-’ ] numb

 

 

//“Свежая” лексема есть

void cons()

{

exam (IDEN);

exam (‘=’);

if (lex = = ‘+’ || lex = = ‘-‘)

get();

exam (NUMB);

return;

}

При прохождении дуги, помеченной терминальным символом, проверяется совпадение имеющейся лексемы lex с той, которая должна быть. Это делает функция exam(). При совпадении происходит чтение следующей лексемы и т.д. Здесь проверяется, чтобы была лексема IDEN, затем ‘=’. Далее необязательный знак ‘+’ или ‘-‘ и в конце – NUNB.

 

4) DVARB → intl iden (‘,’ iden) * ‘;’

 

 

// “Свежей” лексемы нет. Лексема INTL была использована в функции prog() в // switch (lex). По ней была вызвана функция dvarb().

void dvarb()

{

do

{

get();

exam(IDEN);

} while(lex = = ‘,’);

exam(‘;’);

return;

}

В связи с отсутствием “свежей” лексемы необходимо вызвать get(). Затем проверяется условие, является ли полученная лексема IDEN. В случае совпадения в конце функции exam() следует вызов get(). Если будет прочитана лексема ”запятая”, то вновь в цикле do while повторяются get() и exam(IDEN). После того, как очередная лексема не будет равной ‘,’, происходит выход из цикла и проверяется наличие ‘;’.

 

5) DFUNC → iden PARAM BODY

 

 

 

 

// Лексема IDEN была использована в функции prog() в switch(lex). Нужно //вызвать get() для получения новой лексемы.

void dfunc()

{

get(); // получение новой лексемы

param();

body();

return;

}

 

6) PARAM → ‘(’ [ iden (‘,’ iden) *] ‘)’

 

Перед вызовом функции param() из dfunc() был вызов get(). Следовательно, “свежая” лексема имеется.

void param()

{

exam (‘(‘);

if (lex!=’)’)

{

exan (IDEN);

while (lex = =’,’)

{

get();

exam (IDEN);

}

}

exam (‘)’);

return;

}

В соответствии с синтаксической диаграммой вначале проверяется условие, является ли прочитанная лексема левой скобкой ‘(‘. Это делает exam(‘(’). При совпадении в функции (‘)’). В случае совпадения функция exam() вызывает get() и поставляет новую лексему. Если это не ’)’, то должна быть IDEN. И вновь-таки, если после проверки лексемы IDEN была прочитана лексема ‘,’, то в цикле выполняется exam (IDEN). После выхода из цикла лексема должна быть ‘)’ и никакая другая.

 

7) BODY → beginl (DCONST |DVARB) * STML endl

 

 

Функция bоdy() вызывается из dfunc() после param(). Функция param() заканчивается вызовом exam(‘)’). Следовательно, в случае успешной проверки будет вызвана get(), и появится новая лексема. Она должна быть BEGINL.

void body()

{

exam (BEGINL);

while(lex = = INTL || lex = = CONSTL)

if (lex = = INTL) dvarb();

else

dconst();

stml();

exam(ENDL);

return;

}




Поделиться с друзьями:


Дата добавления: 2015-06-27; Просмотров: 401; Нарушение авторских прав?; Мы поможем в написании вашей работы!


Нам важно ваше мнение! Был ли полезен опубликованный материал? Да | Нет



studopedia.su - Студопедия (2013 - 2024) год. Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав! Последнее добавление




Генерация страницы за: 0.026 сек.