如何在 LL(1) 解析器中区分标识符和函数调用

How to differentiate identifier from function call in LL(1) parser

我和我的研究生正在研究一个训练编译器,我们将用它来教授学生 "Compilers and Interpreters"。 输入程序语言是Java语言的有限子集,编译器实现语言是Java。

输入语言句法的文法为LL(1),因为更容易被学生理解和实现。我们在解析器实现中有以下一般问题。如何在解析过程中区分标识符和函数调用?

例如我们可能有:

b = sum(10,5) //sum is a function call  

b = a //a is an identifier  

在这两种情况下,在 = 符号之后我们都有一个标识符。
是否可以区分我们在等号 = 之后有什么样的构造(函数调用或标识符)?

可能在 LL(1) 解析器中是不可能的,因为我们只能向前看 1 个符号?如果这是真的,您建议如何在语法中定义函数调用?也许在函数调用之前需要一些额外的符号,例如b = @sum(10,5)

您认为这个符号会让学生感到困惑吗?什么样的函数调用符号才合适?

您确实不能在 LL(1) 语法中为函数调用和变量制定单独的规则,因为那样需要额外的前瞻性。对此的常见解决方案是将它们组合成一个匹配标识符的规则,可选地后跟一个参数列表:

primary_expression ::= ID ( "(" expression_list ")" )?
                     | ...

在函数可以是任意表达式而不仅仅是标识符的语言中,您需要像对待任何其他后缀运算符一样对待它:

postfix_expression ::= primary_expression postfix_operator*

postfix_operator ::= "++"
                   | "--"
                   | "[" expression "]"
                   | "(" expression_list ")"