Ruby如何知道何时'/';是除法符号,而不是当它启动正则表达式时?
我正在为Ruby开发lexer。这样的lexer需要清楚地 区分除法“/”运算符和正则表达式/…/操作数 lexer在上下文无关(无状态)时最适合构建 关于对下一个标记进行词法分析 某些以“/”开头的程序文本可能是:Ruby如何知道何时'/';是除法符号,而不是当它启动正则表达式时?,ruby,regex,lexical-analysis,Ruby,Regex,Lexical Analysis,我正在为Ruby开发lexer。这样的lexer需要清楚地 区分除法“/”运算符和正则表达式/…/操作数 lexer在上下文无关(无状态)时最适合构建 关于对下一个标记进行词法分析 某些以“/”开头的程序文本可能是: ... / abc*(foo(def,bar[q-z]*)+sam) / ... 您无法判断“/”符号是除法还是regexp的开头 所以很明显,Ruby必须查看上下文,否则它必须有规则 决定什么时候不明确。规则是什么 [一种可能性:只允许在无法发生分歧的情况下,例如,在
... / abc*(foo(def,bar[q-z]*)+sam) / ...
您无法判断“/”符号是除法还是regexp的开头
所以很明显,Ruby必须查看上下文,否则它必须有规则
决定什么时候不明确。规则是什么
[一种可能性:只允许在无法发生分歧的情况下,例如,在
when [ ( , #{ { if elseif != = !~ + , << and or not
when[(,#{if elseif!==!~+,这是因为解析器的定义方式。查看一下您可以看到除法操作(在ARGS
部分)在定义REGEXP
之前定义。这就是为什么除法运算的优先级高于REGEXP
也就是说,如果ruby解析器偶然发现一个解析为
ARG / ARG
它将把它视为一种分裂,并将进一步发展
通过a行走会给你带来启发!(而且这很有趣)Ruby lexer为除法运算符和正则表达式的开头发出完全不同的标记(一个是'/'
,另一个是tREGEXP_BEG
)。因此解析器不知道这两个标记实际上使用相同的源文本
lexer如何知道要发出哪个令牌?请参阅Ruby源代码中的parse.y:8451
传递给lexer的解析器_params
结构有一个名为lex.state
的成员。这是一个位字段,每个位都表示lexer状态的一些信息。单个位称为BEG
,END
,ENDARG
,ENDFN
,ARG
,CMDARG
,MID代码>,FNAME
,DOT
,类
,标签
,标签
当lexer看到一个'/'
字符时,如果
对于ARG
和标记的而言,lexer状态均为真,或者
lexer状态适用于BEG
、MID
或CLASS
中的任何一种
否则,它将发出除法运算符令牌
那么这些状态实际上意味着什么呢?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. */
每当lexer发出令牌时,根据当前lexer状态、被lexed的令牌以及lexer可能在源文本中看到的下一个内容(它确实在许多地方向前看),它可能会移动到一个新状态
一些状态只有在对保留关键字进行词法分析后才能输入。例如,EXPR\u MID
是在对break
、next
、rescue
、或return
进行词法分析后输入的。不,至少在方法名//code>之后,它不表示除法或regex start。Ruby解析很难。我假设是不是要添加到你公司的工具链?我担心你不知道你自己进入了什么。是的,但是它也看下一个字符(决定它是<代码> //=代码>操作符还是含糊的):@ DaveNewton是的。(解析C++是很难的,我们这样做,所以“硬”不会吓我很多)@ CurMnO我可以处理LeXER中的状态。下一个字符,这对这个例子毫无帮助。是的,我知道它是因为露比的解析器而工作的;我很久以前就听说过“只有Ruby可以解析Ruby”。但是这并没有告诉你任何东西。我也反复听到用分析器生成器解析C++是不起作用的;这是错误的。(我们的工具可以做到这一点)。我想我对flex和bison了解得足够多。我将看看@cremno的链接“凝视深渊”试图理解他们做了什么。我这里的问题的目的是找出是否有一个简单的抽象规则。那么,我的示例如何解决?它似乎需要无限前瞻,而flex做得很糟糕。遵循BNF,它取决于。
(在/)之前的代码。不是吗?本质上,BNF所说的是,“允许在允许的地方使用regexp”。词法分析器通常不方便查阅语法。但是,我们的解析器有这种能力,所以我想我可以回到这一点,增加以前容易完成的标记检查,以获得清晰的指示位置(例如,我在问题中提出的一组引入标记)。令牌检查在实践中似乎工作得非常好;在组成MetaSploit的5180个文件中,除了69个文件外,我可以对所有文件执行lex操作(一个很好的大示例)就这样,我还没有实现一些更神秘的插值结构。lexer不处理BNF,它只是生成一个终端符号和文字流。/
是一个文字。刚才发现了你的答案,我真的很感谢你的提醒。我不知道这是否是事实,但它有权限环。+1,直到我发现其他情况为止+}如果我能测试它,它就会接受。[所有这些位都是从lexer状态派生的吗?]“它有权限环。。。“嗯,这是基于阅读Ruby lexer代码。如果你有任何疑问,你可以下载并阅读它。顺便说一句,如果你想看到Ruby lexer发出的令牌,你可以在irb
中使用它:require'ripper';ripper.lex('Ruby code here')