我正在为 Ruby 开发一个词法分析器。这样的词法分析器需要清楚地 区分除法“/”运算符和正则表达式/..../操作数。
词法分析器在上下文无关(无状态)时最好构建 关于词法下一个标记。
某些以“/”开头的程序文本可能是:
... / abc*(foo(def,bar[q-z]*)+sam) / ...
您无法判断“/”符号是除号还是正则表达式的开头。
很明显,Ruby 必须查看上下文,或者它必须有规则 当有歧义时才做出决定。规则是什么?
[一种可能性:它只允许它们在不能发生分割的地方,例如,之后
when [ ( , #{ { if elseif != = !~ + , << and or not
(2015 年 8 月 24 日编辑:扩展了上述列表)
这涵盖了所有内容吗?还是完全不同的东西?]
最佳答案
Ruby 词法分析器为除法运算符和正则表达式的开头发出完全不同的标记(一个是 '/'
,另一个是 tREGEXP_BEG
)。因此解析器不知道两者实际上使用相同的源文本。
词法分析器如何知道要发出哪个标记?请参阅 Ruby 源代码中的 parse.y:8451
。
传递给词法分析器的 parser_params
结构有一个名为 lex.state
的成员。这是一个位字段,每个位都指示有关词法分析器状态的信息。各个位称为 BEG
、END
、ENDARG
、ENDFN
、ARG
、 CMDARG
、MID
、FNAME
、DOT
、CLASS
、LABEL
和 LABELED
。
当词法分析器看到 '/'
字符时,它会发出 tREGEXP_BEG
if...
- 词法分析器状态对于
ARG
和LABELED
均成立,或者 - 词法分析器状态对于
BEG
、MID
或CLASS
中的任何一个都为 true。
否则,它会发出除法运算符标记。
那么这些状态实际上意味着什么呢? Ruby 源代码包含以下对它们的注释:
EXPR_BEG_bit, /* ignore newline, +/- is a sign. */
EXPR_END_bit, /* newline significant, +/- is an operator. */
EXPR_ENDARG_bit, /* ditto, and unbound braces. */
EXPR_ENDFN_bit, /* ditto, and unbound braces. */
EXPR_ARG_bit, /* newline significant, +/- is an operator. */
EXPR_CMDARG_bit, /* newline significant, +/- is an operator. */
EXPR_MID_bit, /* newline significant, +/- is an operator. */
EXPR_FNAME_bit, /* ignore newline, no reserved words. */
EXPR_DOT_bit, /* right after `.' or `::', no reserved words. */
EXPR_CLASS_bit, /* immediate after `class', no here document. */
EXPR_LABEL_bit, /* flag bit, label is allowed. */
EXPR_LABELED_bit, /* flag bit, just after a label. */
每当词法分析器发出一个标记时,根据当前词法分析器状态、被词法分析的标记以及词法分析器接下来可能在源文本中看到的内容(它确实在许多地方向前查看),它可能会移动到一个新的状态。
某些状态仅在对保留关键字进行词法分析后才输入。例如,在词法分析 break
、next
、rescue
或 return
之后输入 EXPR_MID
>.
关于ruby - Ruby 如何知道 '/' 何时是除号,以及何时开始正则表达式?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32159070/