• 编译器一日一练(DIY系列之词法分析)


    【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱:feixiaoxing @163.com】

            词法分析是编译原理的基础。目前来说,大部分编程语言还是以英文为主。使用英文有几个好处,这主要是因为英文的单词和单词之间是用空格分开来的,不像中文需要用词组来分割。记得读书的时候,有一个编译原理上机作业,就是编写一个词法分析器。如果是纯手工编写词法分析器,那么势必涉及到状态机的知识。然而如果使用javacc来编写,只需要描述清楚规则就可以了。

            目前词法分析涉及到的分词主要有这么几种,一种是关键字,一种是标识符,剩下来的就是各种各样的符号、字符串、数字等等。通常来说,分词就是将一长串的字符串解析成一个一个token。

            当然,除了分词之外,有一些字符也是要过滤的,比如换行、空格、注释等等。

            代码链接:https://github.com/feixiaoxing/DIYCompiler

    1、关键字

            关键字比较好理解。就是某个编程语言当中被预留的一些单词。比如c语言里面if、else、for、while、switch、case、goto等等,这些都属于关键字。javacc中一般是这么安排的,

    1. TOKEN: {<IF : "if">}
    2. TOKEN: {<ELSE : "else">}
    3. TOKEN: {<FOR : "for">}
    4. TOKEN: {<WHILE : "while">}
    5. TOKEN: {<DO : "do">}
    6. TOKEN: {<SWITCH : "switch">}
    7. TOKEN: {<CASE : "case">}

    2、标识符

            除了关键字之外,接下来就该说说标志符了。标识符通常就是各种各样变量的名字。这个名字一般用于描述全局变量、局部变量、函数名、函数参数、函数调用等等。对于标识符,javacc是这样来描述的,

    TOKEN: {<IDENTIFIER: ["a"-"z","A"-"Z","_"](["a"-"z","A"-"Z","_","0"-"9"])*>}

    3、其他符号

            在关键字和标识符之后,留下来的就是各种各样的计算符号、数字、字符串和一些特殊付好了。比如,数字一般这么描述,

    TOKEN: { <INTEGER: (["0"-"9"])+> }

            计算符号通常这么来描述,

    1. TOKEN: {<ADD : "+">}
    2. TOKEN: {<SUB : "-">}
    3. TOKEN: {<MUL : "*">}
    4. TOKEN: {<DIV : "/">}
    5. TOKEN: {<EQUAL : "=">}

            特殊符号也有一些,比如这些,

    1. TOKEN: {";">}
    2. TOKEN: {"[">}
    3. TOKEN: {"]">}
    4. TOKEN: {"{">}
    5. TOKEN: {"}">}
    6. TOKEN: {"(">}
    7. TOKEN: {")">}

    4、待过滤的符号

            在编程代码中,有一些符号是要过滤的,他们不参与最终的代码生成,

    SKIP: { <[" ", "\t", "\r", "\n"]> }
    

            这样,有了上面四种形式的符号,基本的词法分析就差不多了。这里没有描述出来所有的符号,本着用多少记录多少的想法,大家在实际开发中可以根据自己的需要灵活增减。

    5、实例

            之前我们谈到了四则运算,这里稍作改变,其实就可以将语法表达式全部用token来表示了,

    1. options {
    2. STATIC = false;
    3. }
    4. PARSER_BEGIN(Parse)
    5. import java.io.*;
    6. public class Parse {
    7. public static void main(String[] args) {
    8. for (String arg : args) {
    9. try {
    10. System.out.println(evaluate(arg));
    11. } catch (ParseException ex) {
    12. System.err.println(ex.getMessage());
    13. }
    14. }
    15. }
    16. public static long evaluate(String src) throws ParseException {
    17. Reader reader = new StringReader(src);
    18. return new Parse(reader).expr();
    19. }
    20. }
    21. PARSER_END(Parse)
    22. SKIP: { <[" ", "\t", "\r", "\n"]> }
    23. TOKEN: { <INTEGER: (["0"-"9"])+> }
    24. TOKEN: {<ADD : "+">}
    25. TOKEN: {<SUB : "-">}
    26. TOKEN: {<MUL : "*">}
    27. TOKEN: {<DIV : "/">}
    28. TOKEN: {<EQUAL : "=">}
    29. TOKEN: {<IDENTIFIER: ["a"-"z","A"-"Z","_"](["a"-"z","A"-"Z","_","0"-"9"])*>}
    30. TOKEN: {<SEMICOLON: ";">}
    31. TOKEN: {<LEFTBRACKETS: "[">}
    32. TOKEN: {<RIGHTBRACKETS: "]">}
    33. TOKEN: {<LEFTBRACE: "{">}
    34. TOKEN: {<RIGHTBRACE: "}">}
    35. TOKEN: {<LEFTPARENTHESES: "(">}
    36. TOKEN: {<RIGHTPARENTHESES: ")">}
    37. long expr() throws NumberFormatException :
    38. {
    39. long value = 0 ;
    40. }
    41. {
    42. value = main_expr()
    43. <EOF>
    44. { return value ; }
    45. }
    46. long main_expr() throws NumberFormatException :
    47. {
    48. long a ;
    49. long b ;
    50. long value = 0 ;
    51. }
    52. {
    53. a = primary() {value = a;}
    54. (
    55. <ADD> b = primary()
    56. {
    57. value += b;
    58. }|
    59. <SUB> b = primary()
    60. {
    61. value -= b;
    62. }
    63. )*
    64. { return value ; }
    65. }
    66. long primary() throws NumberFormatException :
    67. {
    68. long a ;
    69. long b ;
    70. long value = 0 ;
    71. }
    72. {
    73. a = secondary() {value = a;}
    74. (
    75. <MUL> b = secondary()
    76. {
    77. value *= b;
    78. }|
    79. <DIV> b = secondary()
    80. {
    81. value /= b;
    82. }
    83. )*
    84. { return value ; }
    85. }
    86. long secondary() throws NumberFormatException:
    87. {
    88. Token a;
    89. long b = 0;
    90. long value = 0;
    91. }
    92. {
    93. (
    94. a = <INTEGER> {value = Integer.parseInt( a.image );} |
    95. <LEFTPARENTHESES> b =main_expr() <RIGHTPARENTHESES> { value = b;}
    96. )
    97. { return value;}
    98. }

            这里有一点需要注意下,如果在语法表达式中需要使用token的时候,应该用<>来表示。此外如果需要解析这个token的时候,可以直接转变为Token,获取对应的信息就可以了。

  • 相关阅读:
    Python实现一个简单的HTTP服务器(GET/POST)
    机器学习1综述
    failed (13: Permission denied) while reading upstream解决方法
    Android 11 AudioPolicyService 启动流程
    华为发布:30岁以下员工仅占28% 你信吗?
    函数重载——C++
    Linux寄存器+Linux2.6内核进程调度队列+命令行参数+环境变量
    Mqtt是什么
    Android OpenCV(六十八):决策树
    第一篇【传奇开心果系列】Python的游戏库pygame技术点案例示例:深度解读实战开发飞机大战经典游戏案例
  • 原文地址:https://blog.csdn.net/feixiaoxing/article/details/127582805