Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/289.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
是C#';s lambda表达式语法LALR(1)?_C#_Parsing_Lalr - Fatal编程技术网

是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