假设您有一种语言,其中标识符可能以关键字开头。例如,假设“case”是一个关键字,但“caser”是一个有效的标识符。还假设lexer规则只能处理正则表达式。那么我似乎不能将关键字规则放在lexer中标识符规则的前面,因为这会将“caser”解析为“case”后跟“r”。我也不能在标识符规则之后放置关键字列表规则,因为标识符规则将匹配关键字,并且关键字规则永远不会触发。
因此,我可以在lexer中创建一个keyword_or_identifier规则,并让解析器确定keyword_or_identifier是关键字还是标识符。这是正常的做法吗?
我意识到“使用一个具有前瞻性的不同的lexer”是一个答案(某种程度上),但我也对如何在传统的基于DFA的lexer中做到这一点感兴趣,因为我当前的lexer似乎就是这样工作的。
大多数lexer从原始的lex
开始,匹配备选项如下:
>
使用最长的匹配。
如果有两个或更多的备选项是最长的匹配项,则使用lexer定义中的第一个。
"case" { return CASE; }
[[:alpha:]][[:alnum:]]* { return ID; }
虽然这看起来有点武断,但它基本上与DFA方法是一致的。首先,DFA不会在第一次到达接受状态时停止。如果是这样,那么[[:alpha:]][[:alnum:]]*
这样的模式就没有用了,因为它们会在第一个字符(假设是字母)上进入接受状态。取而代之的是,基于DFA的lexer会继续,直到当前状态没有可能的转换,然后它们会备份,直到最后一个接受状态。(见下文)
一个给定的DFA状态可能会因为两个不同的规则而接受,但这也不是问题;只记录第一个接受规则。
公平地说,这与DFA的数学模型略有不同,DFA的数学模型在每个状态下对每个符号都有一个转换(尽管其中许多转换可能是到“接收器”状态),并且根据自动机在读取输入的最后一个符号时是否处于接受状态,它匹配完整的输入。lexer模型略有不同,但也很容易被形式化。
理论模型中唯一的难点是“回到最后接受状态”。在实践中,这通常是通过每次达到接受状态时记住状态和输入位置来完成的。这确实意味着可能需要倒回输入流,可能倒回的量是任意的。
大多数语言并不经常需要备份,极少数语言需要无限期备份。如果没有备份状态,一些lexer生成器可以生成更快的代码。(flex
将在使用-cf
或-cf
时执行此操作。)
导致不确定备份的一种常见情况是未能为字符串文本提供适当的错误返回:
["][^"\n]*["] { return STRING; }
/* ... */
. { return INVALID; }
在这里,如果同一行上有匹配的“
”,则第一个html" target="_blank">模式将匹配以“
开头的字符串文字。(为了简单起见,我省略了\
-转义。)如果字符串文字未终止,则最后一个模式将匹配,但需要将输入重绕到“
。在大多数情况下,试图通过忽略不匹配的”
来继续词法分析是没有意义的;忽略该行的全部剩余部分会更有意义。因此,备份不仅效率低下,而且很可能导致错误消息的爆炸。更好的解决办法可能是:
["][^"\n]*["] { return STRING; }
["][^"\n]* { return INVALID_STRING; }
在这里,第二个备选方案只有在字符串未终止的情况下才能成功,因为如果字符串终止,第一个备选方案将多匹配一个字符。因此,即使我认识的每个人都会把它们按我所做的相同顺序排列,但它们的出现顺序并不重要。
问题内容: 如何将“ 09”解析为9? 问题答案: 包括基数:
问题内容: CSS 2.1将标识符定义为 在CSS中, 标识符 只能包含字符[a-zA-Z0-9]和ISO 10646字符U + 00A0及更高版本,以及连字符(-)和下划线(_);它们不能以数字,两个连字符或连字符后跟数字开头。标识符还可以包含转义字符和任何ISO 10646字符作为数字代码。 因此,应该是一个无效的标识符,因此不应使用来选择元素: 在属性选择器中,属性值必须是标识符或字符串。
问题内容: 为什么在Java中(我不知道任何其他编程语言)标识符不能以数字开头,为什么也不允许以下声明? 问题答案: 通常,您将这种限制放入其中有两个原因: 用电子方式解析很痛苦。 对人类来说这是一个痛苦的解析。 考虑以下代码片段: 如果是合法标识符,那么末尾有哪个值?-3还是2?这是模棱两可的。 同时考虑: 最后有什么价值?这也是模棱两可的。 另外,以任何一种方式阅读都是很痛苦的。如果有人声明,
问题内容: 我在OCJP for Java6的书中读到了带有断言的部分。我到达了那一部分,它概述了如果将“ assert”一词用作关键字或标识符时编译器的反应。 a 和an有什么区别?谁能给我一个简单的解释,并同时给我一个或多个例子? 问题答案: 术语“关键字”和“标识符”不是Java特定的。 关键字是Java关键字列表中的保留字,可为编译器提供指令。由于保留了关键字,因此程序员不能将其用于变量或
主要内容:标识符,关键字任何一种计算机语言都离不开标识符和关键字,因此下面将详细介绍 Java 的标识符、关键字和保留字。 标识符 Java 中标识符是为方法、变量或其他用户定义项所定义的名称。标识符可以有一个或多个字符。在 Java 语言中,标识符的构成规则如下。 标识符由数字(0~9)和字母(A~Z 和 a~z)、美元符号($)、下划线(_)以及 Unicode 字符集中符号大于 0xC0 的所有符号组合构成(各符号
我有以下问题:我正在为GLSL着色语言创建一个编辑器。我希望在某些情况下允许关键字作为标识符,因为内置函数的名称可以用作标识符。 例如: 和不被识别为标识符。 完整语法供参考:http://paste2.org/YwDNkBYW 解决方案: 我创建了一个包含所有内置函数的源文件: 我使用保留的关键字来区分内置函数和本地创建的函数: ...在ScopeProvider中添加了以下内容: 在中,我在迭