Отладка Pyparsing грамматики - PullRequest
       8

Отладка Pyparsing грамматики

19 голосов
/ 01 декабря 2009

Я создаю парсер для воображаемого языка программирования, называемого 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 Ответ

32 голосов
/ 01 декабря 2009

1) Измените Literal("if") на Keyword("if") (и так далее, вплоть до Literal("void")), чтобы предотвратить совпадение с начальным "if" переменной с именем "ifactor".

2) nums, alphas и alphanums не являются выражениями, это строки, которые можно использовать с классом Word для определения некоторых типичных наборов символов при определении «слов», таких как «число слово, составленное из чисел ", или" идентификатор - это слово, которое начинается с буквы, за которой следует ноль или более букв ". Так что вместо:

number = nums
identifier = alphas + OneOrMore(alphanums)

хочешь

number = Word(nums)
identifier = Word(alphas, alphanums)

3) Вместо Combine, я думаю, вы хотите Group. Используйте Combine, если хотите, чтобы совпадающие токены были смежными без пробелов, и объединят токены и вернут их как одну строку. Combine часто используется в таких случаях:

realnum = Combine(Word(nums) + "." + Word(nums))

Без Combine, синтаксический анализ "3.14" вернет список строк ['3', '.', '14'], поэтому мы добавим Combine, чтобы проанализированный результат для realnum был '3.14' (который затем можно было бы передать в действие разбора для преобразовать в фактическое плавающее значение 3.14). Применение Combine отсутствия промежуточных пробелов также удерживает нас от случайного разбора 'The answer is 3. 10 is too much.' и думает, что "3. 10" представляет действительное число.

4) Это не должно вызывать вашу ошибку, но ваша входная строка содержит лотов лишних пробелов. Если ваша грамматика работает, вы сможете анализировать "int x;" так же, как и "int x ;".

Надеюсь, некоторые из этих подсказок помогут вам. Вы читали какие-нибудь статьи или учебники по онлайн-анализу? И, пожалуйста, просмотрите онлайн примеры. Вам нужно хорошо понять, как Word, Literal, Combine и т. Д. Выполняют свои отдельные задачи синтаксического анализа.

5) Вы неправильно реализовали рекурсивные определения для термина и выражения. Вместо присвоения им '' напишите:

term = Forward()
statement = Forward()

Затем, когда вы действительно захотите определить их с помощью их рекурсивных определений, используйте оператор << (и обязательно добавьте RHS в ()).

term << (... term definition ...)
statement << (... statement definition ...)

Вы можете найти пример рекурсивного синтаксического анализатора здесь и презентацию по базовому использованию синтаксического разбора здесь - более подробно см. В разделе «Списки синтаксического анализа» о том, как обрабатывается рекурсия.

...