Отладка Pyparsing грамматики
Вопрос
Я создаю парсер для воображаемого языка программирования, называемого C-- (не фактический язык C--). Я достиг стадии, когда мне нужно перевести грамматику языка в то, что может принять Pyparsing. К сожалению, когда я прихожу, чтобы проанализировать мою входную строку (которая является правильной и не должна вызывать ошибку Pyparsing), это не правильно анализирует. Боюсь, это связано с ошибками в моей грамматике, но, поскольку я впервые запускаю Pyparsing, я не могу понять, в чем дело.
Я загрузил грамматику, которую я перевожу с сюда , чтобы люди могли прочитайте.
РЕДАКТИРОВАТЬ: Обновлено с учетом рекомендаций Пола.
Это грамматика, которая у меня сейчас есть (две верхние строчки определения синтаксиса мне ужасно плохи, я знаю):
# Lexical structure definition
ifS = Keyword('if')
elseS = Keyword('else')
whileS = Keyword('while')
returnS = Keyword('return')
intVar = Keyword('int')
voidKeyword = Keyword('void')
sumdiff = Literal('+') | Literal('-')
prodquot = Literal('*') | Literal('/')
relation = Literal('<=') | Literal('<') | Literal('==') | \
Literal('!=') | Literal('>') | Literal('=>')
lbrace = Literal('{')
rbrace = Literal('}')
lparn = Literal('(')
rparn = Literal(')')
semi = Literal(';')
comma = Literal(',')
number = Word(nums)
identifier = Word(alphas, alphanums)
# Syntax definition
term = ''
statement = ''
variable = intVar + identifier + semi
locals = ZeroOrMore(variable)
expr = term | OneOrMore(Group(sumdiff + term))
args = ZeroOrMore(OneOrMore(Group(expr + comma)) | expr)
funccall = Group(identifier + lparn + args + rparn)
factor = Group(lparn + expr + rparn) | identifier | funccall | number
term = factor | OneOrMore(prodquot + factor)
cond = Group(lparn + expr + relation + expr + rparn)
returnState = Group(returnS + semi) | Combine(returnS + expr + semi)
assignment = Group(identifier + '=' + expr + semi)
proccall = Group(identifier + lparn + args + rparn + semi)
block = Group(lbrace + locals + statement + rbrace)
iteration = Group(whileS + cond + block)
selection = Group(ifS + cond + block) | Group(ifS + cond + block + elseS + block)
statement = OneOrMore(proccall | assignment | selection | iteration | returnState)
param = Group(intVar + identifier)
paramlist = OneOrMore(Combine(param + comma)) | param
params = paramlist | voidKeyword
procedure = Group(voidKeyword + identifier + lparn + params + rparn + block)
function = Group(intVar + identifier + lparn + params + rparn + block)
declaration = variable | function | procedure
program = OneOrMore(declaration)
Я хотел бы знать, есть ли какие-либо ошибки, которые я допустил при переводе грамматики, и какие улучшения я мог бы сделать, чтобы упростить ее, придерживаясь предложенной мной грамматики.
РЕДАКТИРОВАТЬ 2: Обновлено, чтобы включить новую ошибку.
Вот входная строка, которую я анализирую:
int larger ( int first , int second ) {
if ( first > second ) {
return first ;
} else {
return second ;
}
}
void main ( void ) {
int count ;
int sum ;
int max ;
int x ;
x = input ( ) ;
max = x ;
sum = 0 ;
count = 0 ;
while ( x != 0 ) {
count = count + 1 ;
sum = sum + x ;
max = larger ( max , x ) ;
x = input ( ) ;
}
output ( count ) ;
output ( sum ) ;
output ( max ) ;
}
И это сообщение об ошибке, которое я получаю при запуске моей программы из терминала:
/Users/Joe/Documents/Eclipse Projects/Parser/src/pyparsing.py:1156: SyntaxWarning: null string passed to Literal; use Empty() instead
other = Literal( other )
/Users/Joe/Documents/Eclipse Projects/Parser/src/pyparsing.py:1258: SyntaxWarning: null string passed to Literal; use Empty() instead
other = Literal( other )
Expected ")" (at char 30), (line:6, col:26)
None
Решение
1) Измените Literal("if")
на Keyword("if")
(и так далее, вплоть до Literal("void")
), чтобы предотвратить совпадение с начальным " if " переменной с именем "ifactor"
.
2) nums
, alphas
и alphanums
не являются выражениями, это строки, которые можно использовать с классом Word для определения некоторых типичных наборов символов при определении " words Quot; например, " число - это слово, состоящее из nums " или " идентификатор - это слово, начинающееся с буквы, за которой следует ноль или более букв. " Так что вместо:
number = nums
identifier = alphas + OneOrMore(alphanums)
вы хотите
number = Word(nums)
identifier = Word(alphas, alphanums)
3) Я думаю, что вместо Combine
вы хотите Group
. Используйте "3.14"
, если хотите, чтобы совпадающие токены были смежными без пробелов, и объединят токены и вернут их в виде одной строки. ['3', '.', '14']
часто используется в таких случаях:
realnum = Combine(Word(nums) + "." + Word(nums))
Без '3.14'
синтаксический анализ 3.14
вернет список строк 'The answer is 3. 10 is too much.'
, поэтому мы добавляем "3. 10"
, чтобы анализируемый результат для realnum был "int x;"
(который затем можно было бы передать в действие разбора для преобразовать в фактическое плавающее значение "int x ;"
). Применение Word
отсутствия промежуточных пробелов также не позволяет нам случайно выполнить синтаксический анализ Literal
и думать, что ''
представляет собой действительное число.
4) Это не должно вызывать вашу ошибку, но во входной строке есть много лишних пробелов. Если ваша грамматика работает, вы сможете анализировать <<
так же хорошо, как и ()
.
Надеюсь, что некоторые из этих советов помогут вам. Вы читали какие-нибудь статьи или учебники по онлайн-анализу? И, пожалуйста, просмотрите онлайн примеры. Вам нужно хорошо понять, как <=>, <=>, <=> и т. Д. Выполняют свои отдельные задачи анализа.
5) Вы неправильно реализовали рекурсивные определения для термина и выражения. Вместо назначения <=> им напишите:
term = Forward()
statement = Forward()
Затем, когда вы действительно захотите определить их с помощью их рекурсивных определений, используйте оператор <=> (и обязательно добавьте RHS в <=>).
term << (... term definition ...)
statement << (... statement definition ...)
Вы можете найти пример рекурсивного парсера здесь , а также презентацию по базовому использованию механизма разбора здесь - см. раздел " Парсинг списков " подробнее о том, как обрабатывается рекурсия.