Ruby如何知道何时'/';是除法符号,而不是当它启动正则表达式时?

Ruby如何知道何时'/';是除法符号,而不是当它启动正则表达式时?,ruby,regex,lexical-analysis,Ruby,Regex,Lexical Analysis,我正在为Ruby开发lexer。这样的lexer需要清楚地 区分除法“/”运算符和正则表达式/…/操作数 lexer在上下文无关(无状态)时最适合构建 关于对下一个标记进行词法分析 某些以“/”开头的程序文本可能是: ... / abc*(foo(def,bar[q-z]*)+sam) / ... 您无法判断“/”符号是除法还是regexp的开头 所以很明显,Ruby必须查看上下文,否则它必须有规则 决定什么时候不明确。规则是什么 [一种可能性:只允许在无法发生分歧的情况下,例如,在

我正在为Ruby开发lexer。这样的lexer需要清楚地 区分除法“/”运算符和正则表达式/…/操作数

lexer在上下文无关(无状态)时最适合构建 关于对下一个标记进行词法分析

某些以“/”开头的程序文本可能是:

    ...  / 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')