如何使用Ragel正确扫描标识符

时间:2011-03-06 16:21:34

标签: lexical-analysis ragel

我正在尝试为我的C / C ++ / C#/ Java / D类编程语言编写扫描程序,这是我出于个人原因设计的。为此,我正在使用Ragel生成扫描仪。我很难理解许多操作员何时触发行动,可能是因为我的学者专注于实践知识而非理论,而且大量的这种非确定性/确定性有限自动机业务正好在我脑海中。我发现文档要么缺乏,要么我对它的理解是如此。我假设后者。

无论如何,我正在从基础开始。我在第一次迭代中发现了几个关键字和特殊字符。现在我遇到了所有关键字都被扫描为标识符的问题。我正在使用扫描程序运算符来处理我的所有关键字,因为这解决了我的问题字符串returns被扫描为returnreturns关键字。

如何正确扫描标识符?我理解为了使这个确定性,我需要有效地指定lexeme只能是identifier,如果它不匹配其他令牌的模式。原谅我缺乏知识。

Ragel脚本:

%%{
    Identifier = (alpha | '_') . (alnum | '_')*;
    action IdentifierAction
    {
        std::cout << "identifier(\"";
        std::cout.write(ts, te - ts);
        std::cout << "\")";
    }
}%%

%%{
    main :=
    |*
        Interface => InterfaceAction;
        Class => ClassAction;
        Property => PropertyAction;
        Function => FunctionAction;
        TypeQualifier => TypeQualifierAction;
        OpenParenthesis => OpenParenthesisAction;
        CloseParenthesis => CloseParenthesisAction;
        OpenBracket => OpenBracketAction;
        CloseBracket => CloseBracketAction;
        OpenBrace => OpenBraceAction;
        CloseBrace => CloseBraceAction;
        Semicolon => SemicolonAction;
        Returns => ReturnsAction;
        Return => ReturnAction;
        Identifier => IdentifierAction;
        space+;
    *|;
}%%

1 个答案:

答案 0 :(得分:6)

不熟悉Ragel,但是,做过一些自定义解析器&amp;扫描仪。

您的问题似乎与检测关键字有关,而不是检测通用标识符。

你有规则要求Ragel检测代码是一个数字的部分,“return”关键字,分号,“returns”关键字,标识符等等。 Altought,可以为每个关键字制定规则,我不建议。

我从经验中学到的是,最好将所有关键字明确作为标识符(分配一般的“标识符”标记),并在C / C ++代码的某些部分中,检测哪些标识符是“关键字”。

换句话说。 Ragel将只检测标识符。 “myvar”,“return”和“return”都将被标记为“标识符”。稍后,在语义操作的代码( C / C ++而不是Ragel )中,您将检查每个标识符,并检测C / C ++中是否为关键字。这通常是通过提供关键字列表来完成的。

我认为会是这样的:

%%{
Identifier = (alpha | '_') . (alnum | '_')*;
action IdentifierAction
{
    String Keywords[] = 
    (
       "return",
       "if",
       "else"
    ); 

    String MyIdentifier = te - ts;
    if (SearchKeywordCode(Keywords, MyIdentifier)) {
      std::cout << "keyword(\"";
      std::cout.write(ts, te - ts);
      std::cout << "\")";
    }
    else {
      std::cout << "identifier(\"";
      std::cout.write(ts, te - ts);
      std::cout << "\")";
    }
}
}%%

所以,没有“返回”或“退货”规则,只有“标识符”。