Некоторое время я пытался узнать, как работают парнеры LL, и, если я это правильно понимаю, при написании парсера с рекурсивным спусканием сверху вниз я должен создать функцию для каждого не- символ терминала. Так что для этого примера:Грамматика и синтаксический анализ сверху вниз
S -> AB
A -> aA|ε
B -> bg|dDe
D -> ab|cd
я должен был бы создать функцию для каждого S, A, B и D, как это:
Token B()
{
if (Lookahead(1) == 'b')
{
Eat('b');
Eat('g');
}
else if (Lookahead(1) == 'd')
{
Eat('d');
D();
Eat('e');
}
else
{
Error();
}
return B_TOKEN;
}
Но тогда я пытаюсь сделать то же самое с следуя грамматику, которую я создал, чтобы генерировать тот же язык (а | б | в) * регулярное выражение:
S -> Ma
M -> aM|bM|cM|ε
Это дает мне следующие функции:
Token S()
{
char Ch = Lookahead(1);
if (Ch == 'a' || Ch == 'b' || Ch == 'c')
{
M();
Eat('a');
}
else
{
Error();
}
return S_TOKEN;
}
Token M()
{
char Ch = Lookahead(1);
if (Ch == 'a' || Ch == 'b' || Ch == 'c')
{
Eat(ch);
M();
}
return M_TOKEN;
}
И это не кажется хорошим, потому что для ввода «bbcaa» M будет потреблять все, и после этого S не найдет последний «a» и не сообщит об ошибке, даже если грамматика принимает его. Похоже, что M отсутствует в случае с ε, или, может быть, это неправильно, но я не уверен, как с этим справиться. Может ли кто-нибудь помочь?
Добавьте тег для используемого языка, пожалуйста. – Downvoter
@Downvoter: речь идет не о конкретном языке. Ему не нужен тег. –
Ну, ваша функция S должна вызвать M, проверить принятие, а затем проверить, но это не то, что вы написали. См. Мой ответ SO о том, как написать рекурсивный парсер спуска: http://stackoverflow.com/questions/2245962/is-there-an-alternative-for-flex-bison-that-is-usable-on-8-bit -блочные системы/2336769 # 2336769 –