是C#';s lambda表达式语法LALR(1)?
我想问的问题在标题中已简明扼要地给出。让我举一个有关语法的例子:是C#';s lambda表达式语法LALR(1)?,c#,parsing,lalr,C#,Parsing,Lalr,我想问的问题在标题中已简明扼要地给出。让我举一个有关语法的例子: identifier_list : identifier | identifier_list identifier; lambda_arguments : '(' identifier_list ')' | identifier; lambda : lambda_arguments '=>' expression 然后我们加入正常的C表达式语法-特别是 primary_expre
identifier_list
: identifier
| identifier_list identifier;
lambda_arguments
: '(' identifier_list ')'
| identifier;
lambda
: lambda_arguments '=>' expression
然后我们加入正常的C表达式语法-特别是
primary_expression
: '(' expression ')'
| identifier
| lambda;
真正的问题是,这个语法LALR(1)是可分析的,也就是说,能够被自动解析器生成器解析吗?或者它需要手动或GLR解析器吗?请注意,我希望具体了解本小节,而不是上下文相关的关键字或任何其他部分
我现在想的是,如果解析器看到(“identifier”)
,这有两个有效的解析,因此如果解析器看到identifier
,向前看)”
,它将无法决定下一个解析树。不过,这可能只是一个移位/减少冲突,我可以通过指定一些任意的优先级(可能倾向于使用“(“identifier”)”
)来消除它
编辑:事实上,我正在考虑在一种新语言中使用这段语法来实现类似的功能。我已经有了语法形式类似于JavaScript的匿名函数,但我的豚鼠squeaks反馈抱怨它们对于许多用途来说过于冗长,并指出C#lambda表达式是更理想的解决方案。我担心这个解决方案可能会造成歧义。所以,真的,我只对那一部分感兴趣。其他的东西,比如泛型和类型转换,对我来说都不是问题
我以前的语法版本是机械可解析的,我不想失去这个属性,我以前使用机械生成器的经验告诉我,最好在这里检查,而不是自己尝试。对于我的手摇解析器,我当然可以简单地使用特例
”(“identifier
,以便比正常情况下看得更远一些。首先,解析器理论一直是我的弱点之一。我主要从事语义分析器的工作
其次,我研究过的所有C#解析器都是手工生成的递归下降解析器。我以前的一位同事在解析器理论方面有很强的背景,他构建了自己的解析器生成器,并成功地将C#语法输入其中,但我不知道这样做会导致什么样的骇人听闻的黑客行为
所以我在这里要说的是以适当的怀疑态度来接受这个答案
正如您所注意到的,lambda有点麻烦,因为您必须小心括号内的表达式——它可能是括号内的表达式、强制转换运算符或lambda参数列表,lambda参数列表可能有几种不同的形式。但从各方面考虑,将lambda添加到C#3.0中相对容易,grammati说破解解析器并不太困难——对lambdas来说,语义分析是个难题 就前瞻性而言,C#文法中真正令人烦恼的问题是泛型和类型转换 泛型是在C#2中添加的,在该语言已经有了
>
、
和
(E))
调用方法A
是否需要两个参数:B
和D>(E)
或一个,B(E)
消除歧义的规则是:
如果令牌序列可以解析为简单名称、成员访问或以类型参数列表结尾的指针成员访问,则检查紧跟在结束标记之后的令牌。如果它是()]:;,.?==!=
则类型参数列表将作为简单名称、成员访问或指针成员访问的一部分保留,并放弃对令牌序列的任何其他可能解析。否则,即使没有其他POS,类型参数列表也不会被视为简单名称、成员访问或指针成员访问的一部分标记序列的可解析性
语法的第二个问题可以追溯到C#1.0,这就是cast操作符。问题是(x)-y
可能意味着“cast-y
键入x
”,也可能意味着从x
中减去y
。这里的规则是:
仅当以下至少一项为真时,括号中包含的一个或多个标记序列才被视为强制转换表达式的开始:
标记序列是类型的正确语法,但不是表达式的正确语法
标记序列是类型的正确语法,紧跟在右括号后面的标记是标记“~”、标记“!”、标记“(”、标识符、文字或除as
和is
之外的任何关键字
消除这两种情况歧义的规则在理论上都涉及到潜在的大外观,但在实践中,您很少需要将解析器备份到很远的地方。我认为lambda表达式语法问题本身并不有趣, 除非你知道语言的其余部分是LALR(1) 如果您想知道答案,请将子语法提供给LALR(1)解析器 发电机。如果它抱怨轮班减少或减少冲突, 它不是LALR(1)。语法是否是LALR(1)取决于 您可以根据定义为其构建转换表 大多数情况下,我们需要一个用于整个语言的解析器 这里有两个有趣的问题 1) C#4.5作为一种语言是LALR(1)吗?(例如,是否有一些语法是LALR(1)? 请注意,一个特定的语法不是LALR(1),并不意味着没有其他语法 2) 微软(以多种形式)发布的C#文法中有没有一种是LALR(1) 我想埃里克告诉我们这不是真的。这表明这也不是真的 C++需要无限前瞻来解析其模板,这主要是由本地possi
( id )
( id1 id2 )
primary: '(' expression ')'
lambda_parameters: '(' id_list ')'
primary: '(' expression_not_id ')'
| '(' ID ')'
lambda_parameters: '(' id_list_not_id ')'
| '(' ID ')'
%token ID LITERAL RIGHT_ARROW
%start expr
%%
primary: primary_not_id | ID ;
term: term_not_id | ID ;
sum: sum_not_id | ID ;
expr: expr_not_id | ID ;
expr_list: expr | expr_list ',' expr ;
arguments: '(' ')' | '(' expr_list ')' ;
ids: ID ',' ID | ids ',' ID ;
parameters: '(' ID ')' | '(' ids ')' ;
primary_not_id: LITERAL
| '(' expr_not_id ')'
| '(' ID ')'
| primary arguments
;
term_not_id: primary_not_id
| term '*' primary
;
sum_not_id: term_not_id
| sum '+' term
;
expr_not_id: sum_not_id
| parameters RIGHT_ARROW expr
;
id_list: ID
| id_list ',' ID
;
expression_list_not_id_list: expression_not_id
| id_list ',' expression_not_id
| expression_list_not_id_list ',' expression
;
expression_list: expression_list_not_id_list
| id_list
;
%token identifier ARROW
%%
program
: expression
| program expression
;
identifier_list
: identifier
| identifier_list identifier;
lambda_arguments
: '(' identifier_list ')'
| identifier;
lambda
: lambda_arguments ARROW expression;
primary_expression
: '(' expression ')'
| identifier
| lambda;
expression : primary_expression
$ yacc -v test.6.y
conflicts: 1 reduce/reduce
%token identifier ARROW
%%
program
: expression
| program expression
;
identifier_list
: identifier
| identifier_list identifier
;
lambda_arguments
: '(' identifier identifier_list ')'
| identifier
;
primary_expression
: '(' expression ')'
| '(' expression ')' ARROW expression
| lambda_arguments ARROW expression
| identifier
;
expression : primary_expression
| '(' expression ')' ARROW expression
| lambda_arguments ARROW expression