我不能代表 PLY 解决方案,但这是一个使用 pyparsing 的解决方案。有时,即使您最终想使用其他库来实现解析器,pyparsing 示例也会很有用,作为快速而简单的原型/练习。不幸的是,这个例子大量使用了这个operatorPrecedence
方法,它隐藏了很多中缀解析魔法,所以我不知道你能多容易地翻译它。可以在示例页面 ( http://pyparsing.wikispaces.com/Examples ) 上的 pyparsing wiki 上找到更传统的 expr/term/factor 解析器示例,标题为fourFn.py。
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'、'became '和'打印')。