19

我正在为一种名为 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
4

1 回答 1

33

1) 更改Literal("if")Keyword("if")(依此类推,下至Literal("void")),以防止匹配名为 的变量的前导“if” "ifactor"

2) nums, alphas, andalphanums不是表达式,它们是字符串,可以与 Word 类一起使用,在定义“单词”时定义一些典型的字符集,例如“数字是由 nums 组成的单词”或“标识符”是一个以字母开头,后跟零个或多个字母数字的单词。” 所以而不是:

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 ;".

希望这些提示中的一些能让你继续前进。您是否阅读过任何在线 pyparsing 文章或教程?请查看在线示例。您需要很好地掌握 、 、 等如何Word执行Literal它们Combine各自的解析任务。

5)您错误地实现了术语和语句的递归定义。不要分配''给他们,而是写:

term = Forward()
statement = Forward()

然后,当您使用它们的递归定义实际定义它们时,请使用<<运算符(并确保将 RHS 括在()'s 中)。

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

您可以在此处找到递归解析器的示例,并在此处找到有关基本 pyparsing 用法的演示- 请参阅标题为“解析列表”的部分,了解有关如何处理递归的更多分步信息。

于 2009-12-01T01:55:18.137 回答