如何在 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 ")"
我和我的研究生正在研究一个训练编译器,我们将用它来教授学生 "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 ")"