我试着到处寻找这个问题的答案,但似乎找不到。我正在尝试用Python编写一个解析器,使用PLY作为一种合成语言。我的BNF的简化版本如下所示:
statement-list -> statement ',' statement-list |
'print' expr
statement -> ident 'was' 'a' type |
ident 'became' expr
type -> 'number' | 'letter'
expr -> factor |
expr '+' factor |
expr '-' factor
factor -> number | letter | ident其中数字和字母类似于int和char。
Yacc文档(http://www.dabeaz.com/ply/ply.html#ply_nn23)只显示了简单算术表达式的语法,其中很清楚p应该是什么。
def p_expression_plus(p):
'expression : expression PLUS term'
p[0] = p[1] + p[3]我的问题是,我的BNF中的语句表是怎么做的?我有:
def p_statement_list_comma(p):
'statement-list : statement COMMA statement-list'但我真的不确定下一步该放什么。任何帮助都将不胜感激!
发布于 2011-10-27 19:52:16
这真的取决于你如何构造你的代码,以及你想要如何评估它。如果您正在进行计算,只要它以正确的顺序进行计算,您就不会想要在p_statement_list_comma文档字符串之后的任何东西,例如,就像您拥有它一样-语句将无论如何都会被计算,如果需要,您可以保留一个变量的全局字典或类似的东西来跟踪一些状态,如标识符值。
如果你想构建一个解析树,例如,如果你不喜欢ply的求值顺序,那么你可以这样做:
def p_statement_list_comma(p):
'statement-list : statement COMMA statement-list'
p[0] = [p[1]] + p[3]
def p_statement_print_expr(p):
'statement-list : PRINT expr'
p[0] = [p[2]]这将为您提供一个语句列表,列表中的最后一个元素是一个表达式。为了简单起见,这里使用了列表;如果你愿意,你也可以使用你自己的类--只要给任何你想要p的python对象赋值,它就会在上面的级别中可用。
如果您希望从yacc.parse返回打印表达式的结果(解析树顶层的值将从yacc.parse返回),您可以这样做:
def p_statement_list_comma(p):
'statement-list : statement COMMA statement-list'
p[0] = p[3]
def p_statement_print_expr(p):
'statement-list : PRINT expr'
p[0] = p[2]发布于 2011-10-27 13:40:53
我不能为PLY解决方案说话,但这里有一个使用pyparsing的解决方案。有时,一个pyparsing示例非常有用,即使您最终希望使用其他库来实现解析器,也可以将其作为快速实用的原型/练习。不幸的是,这个示例大量使用了operatorPrecedence方法,它埋没了很多中缀解析的魔力,所以我不知道您将如何轻松地转换它。在名为fourFn.py的示例页面(http://pyparsing.wikispaces.com/Examples)上的pyparsing wiki上可以找到一个更传统的expr/term/factor解析器示例。
bnf = """
statement-list -> statement ',' statement-list
statement -> ident 'was' 'a' type |
ident 'became' expr |
'print' expr |
'if' conditional-expr statement
type -> 'number' | 'letter'
expr -> factor |
expr '+' factor |
expr '-' factor
factor -> number | letter | ident
"""
from pyparsing import (CaselessKeyword, Word, nums, alphas, alphanums, operatorPrecedence,
Forward, MatchFirst, opAssoc, oneOf, Group, delimitedList)
PRINT, WAS, A, BECAME, NUMBER, LETTER, IF, ELSE, TRUE, FALSE, AND, OR, NOT = map(
CaselessKeyword,
"print was a became number letter if else true false and or not".upper().split())
keyword = MatchFirst([PRINT, WAS, A, BECAME, NUMBER, LETTER, IF, ELSE, TRUE, FALSE, AND, OR, NOT])
typeSpecifier = NUMBER | LETTER
number = Word(nums)
ident = ~keyword + Word(alphas, alphanums+'_')
operand = number | ident
expr = operatorPrecedence(operand,
[
('-', 1, opAssoc.RIGHT),
(oneOf('* /'), 2, opAssoc.LEFT),
(oneOf('+ -'), 2, opAssoc.LEFT),
])
comparisonExpr = operatorPrecedence(expr,
[
("!", 1, opAssoc.RIGHT),
(oneOf("< > = <= >= !="), 2, opAssoc.LEFT),
])
booleanExpr = operatorPrecedence(TRUE | FALSE | comparisonExpr,
[
(NOT, 1, opAssoc.RIGHT),
(AND, 2, opAssoc.LEFT),
(OR, 2, opAssoc.LEFT),
])
statement = Forward()
printStmt = PRINT + expr
wasaStmt = ident + WAS + A + typeSpecifier
becameStmt = ident + BECAME + expr
ifStmt = IF + booleanExpr + statement
statement << Group(printStmt | wasaStmt | becameStmt | ifStmt)
statementList = delimitedList(statement)
tests = """\
x was a number
y became 2+5
print y
print 100*(5+2)
print 100*5+2
if 5 > y print 1000
if y < 10 y became y+1, print y
""".splitlines()[:-1]
for t in tests:
print t.strip()
for s in statementList.parseString(t).asList():
print(s)
print打印:
x was a number
['x', 'WAS', 'A', 'NUMBER']
y became 2+5
['y', 'BECAME', ['2', '+', '5']]
print y
['PRINT', 'y']
print 100*(5+2)
['PRINT', ['100', '*', ['5', '+', '2']]]
print 100*5+2
['PRINT', [['100', '*', '5'], '+', '2']]
if 5 > y print 1000
['IF', ['5', '>', 'y'], ['PRINT', '1000']]
if y < 10 y became y+1, print y
['IF', ['y', '<', '10'], ['y', 'BECAME', ['y', '+', '1']]
['PRINT', 'y']我随意添加了print作为一种语句,这样它就可以出现在程序主体中的任何地方。此外,我还尝试添加一个IF-THEN语句,这确实显示了添加这样的控制流语句如何开始将您带到编写递归语法的道路上(不需要递归只是为了'was a',‘take’和'print')。
https://stackoverflow.com/questions/7908898
复制相似问题