C#在评估/解析表达式时是否有影响?

5

前段时间我在尝试使用C#编写以下语句:

i+++++i // does not compile <bt>

i++ + ++i // executed

空格在表达式中有影响吗?
以上陈述有何不同之处?

Ramachandran


1
你到底为什么要那样做? - Fosco
1
这只是为了探索语言如何解释等等,可能在实际应用中并不真正有用 :)无论如何感谢您的回复。 - RAM
3个回答

14

首先,让我解释一下编译器是如何工作的。

我们首先将源代码分解成标记。然后将这些标记组织成一个语法树。接着对语法树进行语义分析,最终基于该语义分析生成代码。在这些阶段中,包括词法分析、语法分析和语义分析,任何一个阶段都可能产生错误。重要的是:如果后面的步骤出现错误,我们不会返回并重新执行之前的步骤

词法分析器是“贪婪”的——它试图在每个阶段尽可能地生成最大的标记。所以Daniel是对的。词法分析器将i+++++i分解为i / ++ / ++ / + / i。

接下来,语法分析器会尝试将其转换成语法树,得到:

                +
               / \
              ++  i
             /
            ++
           /
          i   

也就是说,等价于 (((i++)++) + i)。

现在语义分析器检查它并说:“i ++没问题,因为i是一个变量。但是i ++不是变量,而是值。你不能对值进行++操作,因此第二个++是非法的。” 然后语义分析器就会给出错误:增量的操作数必须是变量

语义分析器不会重新进行词法分析,并说你知道吗,这可能是i / ++ / + / ++ / i,这将解析得到不同的结果并且合法。我们不会回溯因为可能有数十亿种重新词法分析和重新解析程序的可能性,我们不想尝试所有这些可能性。只考虑您的情况;i+++++i可以是(((i++)++)+i)或)((i++)+(+(+i)))或(i+(+(+(+(+i))))或...请记住,+可以是一元加号、二元加号、前增量或后增量的一部分,因此这五个加号有很多可能的组合。


10

空格在分隔符号时会产生影响。

显而易见的例子是:int a = 1; 不同于 inta=1;

同样地,+ +a 相当于 +(+(a)),它简单地返回1(假设 a=1)。然而去掉中间的空格,两个 + 将形成单一的 ++,因此将a递增至2。

你的第一个例子标记化后产生了5个标记:"i" "++" "++" "+" "i"

你的第二个例子结果略有不同,产生了5个标记:"i" "++" "+" "++" "i"


3

C、C++、C#和Java编译器采用一种名为“最大匹配”的解析方式,它们总是尝试生成最长的记号。

现在,有些字符会自动结束一个记号--例如分号或括号。而空格就是其中之一。

因此,在你的第二个例子中,有5个记号:"i"、“++”、“+”、“++”和“i”

然而,在你的第一个例子中,只有三个记号:“i”、“+++++”和“i”。

另外,我应该指出的是,虽然您的第二个例子可以在C++下编译通过,但这是完全不合法的(在一条语句中不能修改同一个值两次)。 在C#中也可能是非法的,不过C#在这些事情上往往更加灵活。


不,"+++++" 在任何类 C 语言中都不是有效的标记。相反,他的第一个示例有 5 个标记:"i"、"++"、"++"、"+" 和 "i"。 - Daniel
1
我并没有说这是一个有效的令牌,只是一个(已解析的)令牌。 - James Curran
2
丹尼尔是正确的;这个答案是错误的。在C#中,+++++不是一个标记。相反,分词器将其拆分为i / ++ / ++ / + / i。 - Eric Lippert
1
此外,第二种形式是完全合法的C#代码,并且非常明确定义。在C#中没有规定变量不能被两次改变的规则。不需要这样的规则,因为C#精确地定义了子表达式的求值顺序,而C/C++则不同。在C/C++中,这些类型的表达式是一个坏主意,因为求值顺序是未定义的,因此有多个可能的合法结果。 - Eric Lippert

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接