有时回来我在C#
中尝试以下语句i+++++i // does not compile <bt>
i++ + ++i // executed
空间对表达式有影响吗?
上述陈述以何种方式不同?
Ramachandran的
答案 0 :(得分:14)
首先,让我解释编译器的工作原理。
我们要做的第一件事就是将源代码分解为令牌。然后我们将令牌组织成解析树。然后我们对解析树进行语义分析,然后基于该语义分析生成代码。任何这些阶段 - lexing,解析或分析 - 都会产生错误。这是重要的部分:如果后期阶段出现错误,我们不会再回到前一阶段。
词法分析者是“贪婪的” - 它试图在每个阶段都能做出最大的代币。所以丹尼尔是对的。词法分析器将i +++++ i分解为i / ++ / ++ / + / i
然后解析器尝试将其转换为解析树,然后出现
+
/ \
++ i
/
++
/
i
即等同于(((i ++)++)+ i)。
现在语义分析器看着它并说“i ++很好,因为我是一个变量。但是i ++不是一个变量,它是一个值。你不能对一个值做++,所以第二个 ++是非法的。“语义分析器然后给出错误:增量的操作数必须是变量。
语义分析器不然后重新执行lex并说你知道,这可能是i / ++ / + / ++ / i,它会以不同方式解析并且是合法的。我们不回溯,因为可能有数十亿可能的方法来重新解析和重新解析程序,我们不想尝试所有这些。只考虑你的情况; i +++++我可能是(((i ++)++)+ i)或)((i ++)+(+(+ i)))或(i +(+(+(+(+ i))) )或者......记住,+可以是一元加,二进制加,预增量或后增量的一部分,因此这五个加号可能有批次。
答案 1 :(得分:10)
分隔令牌时空格有效。
明显的例子:int a = 1;
与inta=1;
同样,+ +a
与+(+(a))
相同,后者只返回1(假设为a=1
)。无论如何移除空格,两个+
标记将形成一个++
标记,从而将a增加到2.
您的第一个示例标记化结果为5个标记:“i”“++”“++”“+”“i”
你的第二个例子导致5个令牌略有不同:“i”“++”“+”“++”“i”
答案 2 :(得分:3)
C-ish(C / C ++ / C#/ Java)编译器使用称为“max munch”的解析方式 - 他们总是试图使最大的令牌成为可能。
现在,一些字符会自动结束一个标记 - 例如分号或括号。空白就是其中之一。
所以,在你的第二个例子中,然后是5个令牌:“i”“++”“+”“++”“i”
然而,在你的第一个例子中,只有三个:“i”“+++++”和“i”
另外,我应该注意,虽然你的第二个例子将在C ++下编译,但它完全是非法的(你不允许在一个语句中两次修改相同的值)。它在C#中可能也是非法的,尽管C#在这些方面往往更灵活。