• javacc之路1--- Token Manager


    词法状态

    JavaCC 词法规范被组织成一组词法状态,每个词法状态都用一个唯一的标识符命名。有一个标准的词汇状态称为 DEFAULT。生成的令牌管理器随时处于这些词法状态之一。默认情况下,初始化令牌管理器时,它将在状态中启动。在构造令牌管理器对象时,也可以将起始词法状态指定为参数。

    每个词法状态都包含一个正则表达式的有序列表 - 顺序派生自输入文件中的出现顺序。有四种类型的正则表达式:

    • SKIP,
    • MORE,
    • TOKEN,
    • SPECIAL_TOKEN

    在语法中作为扩展单元出现的所有正则表达式都被视为处于 DEFAULT 词法状态,其出现顺序由它们在语法文件中的位置确定。

    Token匹配

    当前词法状态中的所有正则表达式都被视为潜在的匹配候选项。Token 管理器使用输入流中与这些正则表达式之一匹配的最大字符数。也就是说,Token 管理器首选尽可能长的匹配。如果有多个长度相同的最长匹配项,则匹配的正则表达式是语法文件中出现顺序最早的正则表达式。

    如上所述,Token 管理器在任何时候都处于一种状态。此时,Token 管理器仅考虑在此状态下定义的正则表达式以进行匹配。匹配后,可以指定要执行的操作以及要移动到的新词汇状态。如果未指定新的词法状态,则Token 管理器将保持当前状态。

    TOKEN: {
          
        | 
        | 
              …
              …
        | 
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    扫描器扫描符合正则表达式模式的字符串并生成对应的token。并且TOKEN命令的块在一个文件中可以出现任意多次,因此按照逻辑上的相关性分开记载TOKEN命令比较好。

    选择匹配规则

    • JavaCC会同时尝试匹配所有的正则表达式,并选择匹配字符串最长的规则
    • 多个规则的正则表达式匹配的字符串长度相同的情况下,JavaCC优先选择在文件中先定义的token规则

    词汇操作

    正则表达式类型指定成功匹配正则表达式时要执行的操作:

    SKIP 只需丢弃匹配的字符串(在执行任何词法操作后)。
    MORE 继续下一个状态,带走匹配的字符串。此字符串将是新匹配字符串的前缀。
    TOKEN 使用匹配的字符串创建令牌,并将其发送到解析器(或任何调用方)。
    SPECIAL_TOKEN 创建不参与分析的特殊令牌。前面已经描述过了。
    注:注:访问特殊令牌的机制位于本页末尾。

    每当检测到文件末尾 时,无论词法分析器的当前状态如何,都会导致创建 token。但是,如果 token在正则表达式的匹配过程中检测到 -(或在匹配 MORE 正则表达式后立即检测到 -),则会报告错误。

    匹配正则表达式后,将执行词法操作。在 TOKEN_MGR_DECLS region 中声明的所有变量和方法(见下文)都可以在此处使用。此外,下面列出的变量和方法也可供使用。

    在此之后,Token 管理器将状态立即更改为指定的状态(如果有)。

    之后,执行由正则表达式类型指定的操作(SKIP, MORE 等)。如果类型为 TOKEN,则返回匹配的TOKEN。如果类型为 SPECIAL_TOKEN,则保存匹配的令牌,以便与匹配的下一个一起返回。


    不使用TOKEN命令而使用SKIP命令的话就不会生成token,因此使用SKIP命令可以省略token名。还可以用SPECIAL_TOKEN命令(SPECIAL_TOKEN directive)来跳过token。SKIP命令和SPECIAL_TOKEN命令的区别在于是否保存跳过的token。使用SKIP命令无法访问跳过的字符串,使用SPECIAL_TOKEN命令就可以借助下面被扫描的TOKEN对象来取得跳过的字符串

    SKIP: {
          
        | 
              …
              …
        | 
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    词法操作内的变量

    下面的变量可以在词法操作中使用:

    1. StringBuffer image (READ/WRITE)
       image 变量(不同于image 字段匹配的 Token )是一个包含自上次SKIP, TOKEN, or SPECIAL_TOKEN 匹配的所有StringBuffer的字符。你可以自由地做任何改变你希望它只要你不将它分配给空自生成的token,生成的 token 管理器也使用这个变量。  
        如果你改变 image ,这变化是传递给后续匹配(如果当前匹配 MORE)。image 的内容并不会自动分配给 image 匹配字符的 image 字段。如果你希望这样的事情发生,您必须显式地指定在词法行动令牌或SPECIAL_TOKEN正则表达式。
        Example 1
     MORE : { "a" : S1 }
    
     MORE :
    {
      "b"
        { int l = image.length()-1; image.setCharAt(l, image.charAt(l).toUpperCase()); }
        ^1                                                                             ^2
        : S2
    }
    
     TOKEN :
    {
      "cd" { x = image; } : DEFAULT
           ^3
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    上面的例子,3处的 image 值:

    At ^1: “ab”
    At ^2: “aB”
    At ^3: “aBcd”

    1. int lengthOfMatch (READ ONLY)
      这是当前匹配的长度(它不是 MORE的积累)。只读。
      例:

    At ^1: 1 (the size of “b”)
    At ^2: 1 (does not change due to lexical actions)
    At ^3: 2 (the size of “cd”)

    1. int curLexState (READ ONLY)
      这是当前词法状态的索引。你不应该修改这个变量。整型常量的名字是那些词汇生成状态进入…Constant常量文件,因此您可以参考词汇而不用担心实际索引值。

    2. inputStream (READ ONLY)
      输入流是以下的一种:
      ASCII_CharStream
      ASCII_UCodeESC_CharStream
      UCode_CharStream
      UCode_UCodeESC_CharStream

    3. Token matchedToken (READ/WRITE)

    4. void SwitchTo(int)

    Special Tokens

    特殊token就像token,除了他们被允许出现在输入文件(任何两个token之间)。特殊token可以指定输入文件的语法使用保留字SPECIAL_TOKEN 而不是 token ,例如:

    SPECIAL_TOKEN :
    {
      
    }
    
    • 1
    • 2
    • 3
    • 4

    任何定义为 SPECIAL_TOKEN 的正则表达式,可能以特殊的方式从词法和语法的用户操作规范访问。这允许将这些 token 在解析时恢复,同时这些 token 不参与解析。
    从输入语法文件复制到生成的文件,JavaCC一直引导使用此功能会自动复制相关comments 。  
    类令牌现在有一个额外的字段:

    Token specialToken;

    这个字段指向 SPECIAL_TOKEN 在当前令牌之前(特殊或其他)。如果在当前 token 之前的 token 是一个常规的token (而不是一个特殊的token ),那么这个字段被设置为null。常规token的下一个字段具有相同的意义,即他们指向下一个常规token除了EOF token。EOF token next字段为空。下一个字段特殊标记的特殊令牌后立即当前令牌。如果跟随当前令牌之后是一个常规的token ,next字段被设置为null。

    例:

    // if there are no special tokens return control to the caller
    if (t.specialToken == null) {
      return;
    }
    
    // walk back the special token chain until it reaches the first special token after the previous regular token
    Token tmp_t = t.specialToken;
    while (tmp_t.specialToken != null) {
      tmp_t = tmp_t.specialToken;
    }
    
    // now walk the special token chain forward and print them in the process
    while (tmp_t != null) {
      System.out.println(tmp_t.image);
      tmp_t = tmp_t.next;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
  • 相关阅读:
    C#WPF相对好看的登录界面
    ArcGIS实验教程——实验四十八:ArcGIS制图表达入门及案例教程
    【数据挖掘工程师-笔试】2022年大华股份
    pytest学习和使用10-Pytest中的测试用例如何跳过执行?
    C++编程练习系列(1)C++和标准库速成
    IB数学TI nspire使用入门
    flink中维表Join几种常见方式总结
    Python图像处理丨三种实现图像形态学转化运算模式
    介绍 TensorFlow 的基本概念和使用场景
    C语言中计算函数执行时间
  • 原文地址:https://blog.csdn.net/u013257767/article/details/128009675