• flex&bison 学习笔记(1)


    最近用的项目是用脚本写GUI界面,空闲时间也想自己写个脚本系统玩一玩,以前用的都是别人写好的脚本引擎,比如:JavaScript、VBScript、lua……
    自己没有研究过。准备工作当然是搜集资料了,先看了一篇教程《Implementing a Scripting Engine》,说得不错,打算也采用lex和yacc来做词法和语法的分析(全都自己写太累了,有现成的何必不用呢?)。
    但是郁闷的是,该教程附带的例子只有一个lex词法分析的,yacc的没有,不管那么多,先跑起来看看,恩,不知所云,不过程序跑完整了。能把输入的文本按规则返回token。不过怎么编写lex文件还摸不到门道。
    上网搜了半天关于yacc的资料,结果有语法文件的都编译不通过,郁闷!~~~~~~
    今天决定分开来看,首先是flex文件,
    %{
    #include 
    <stdio.h>
    #include 
    <string.h>
    #include 
    <io.h>
    #include 
    "lexsymb.h"
    #include 
    "parse.cpp.h"
    %}

    LETTER      [a
    -zA-Z_]
    DIGIT       [
    0-9]
    IDENT       
    {LETTER}({LETTER}|{DIGIT})*
    STR         \
    "[^\"]*\"
    CHAR        '{LETTER}'
    WSPACE      [ \t]
    +
    INTEGER     [
    -]*{DIGIT}+
    bool        "true"|"false"

    %%
    {WSPACE} ;/* Eat all space */
    \n 
    {lineno++;}

    "="         {return ASSIGN;}
    "=="        {return EQUAL;}
    "!="        {return NOTEQUAL;}
    "if"        {return IF;}
    "else"      {return ELSE;}
    "print"     {return PRINT;}
    "input"     {return INPUT;}
    "+"         {return CONCAT;}
    ";"         {return END_STMT;}
    "("         {return OPEN_PAR;}
    ")"         {return CLOSE_PAR;}
    "{"         {return BEGIN_CS;}
    "}"         {return END_CS;}
    {bool}      { printf("bool value\n"); };
    {INTEGER} {
    yylval.str 
    = new char[strlen(yytext) + 1];
    strcpy(yylval.str, yytext);
    printf(
    "Integer:%s\n", yylval.str);
    return INTEGER;
    }

    {CHAR} {int iSize = strlen(yytext) - 1;
    yylval.str 
    = new char[iSize];
    strncpy(yylval.str, 
    &yytext[1], iSize - 1);
    yylval.str[iSize 
    - 1= 0;
    printf(
    "Char:%s\n", yylval.str);
    return STRING;
    }

    {STR} int iSize = strlen(yytext) - 1;
    yylval.str 
    = new char[iSize];
    strncpy(yylval.str, 
    &yytext[1], iSize - 1);
    yylval.str[iSize 
    - 1= 0;
    printf(
    "String:%s\n", yylval.str);
    return STRING;
    }

    {IDENT} {
    yylval.str 
    = new char[strlen(yytext) + 1];
    strcpy(yylval.str, yytext);
    printf(
    "Identifier:%s\n", yylval.str);
    return ID;
    }

    {printf("Undefined symbo at line %d\n", lineno);return ERROR_TOKEN;}
    %%
    int yywrap()
    {
    return 1;
    }

    /* YYSTYPE yylval; */
    int lineno = 0;
    /*int main()
    {
    while ( yylex() )
    {
    }
    return 0;
    }
    */

    这个文件编译出来的东西没有问题,可以执行,当然要单独执行就要把最后的那些注释掉的代码恢复。lex文件分成三部分,用%%来隔开,第一部分是声明部分可以放C和lex的全局声明,第二部分是模式以及动作代码,第三部分是附加c代码(可以不写)
    parse.cpp.h是和yacc同时运行时有yacc生成的头文件,包含了token符号的定义以及YYSTYPE的定义:
    typedef union {
        
    char* str;
    }
     YYSTYPE;
    #define    ERROR_TOKEN    258
    #define    IF    259
    #define    ELSE    260
    #define    PRINT    261
    #define    INPUT    262
    #define    ASSIGN    263
    #define    EQUAL    264
    #define    NOTEQUAL    265
    #define    CONCAT    266
    #define    END_STMT    267
    #define    OPEN_PAR    268
    #define    CLOSE_PAR    269
    #define    BEGIN_CS    270
    #define    END_CS    271
    #define    ID    272
    #define    INTEGER    273
    #define    STRING    274


    extern YYSTYPE yylval;
    在.NET 2005下编译必须要包含io.h,否则会报告没有定义的函数  int __cdecl isatty(int)
    lexsymb.h文件包含了几个函数的声明以及用来保存行数的全局变量:
    extern int lineno;
    extern int yyerror(char *msg);
    extern int yylex();

    接下来是yacc文件了:这是从网上找到的很简单的一个例子,修改了一下以和我的lex文件相符合:
    %union {
        
    char* str;
    }
    %{

    #include 
    <stdio.h>
    #include 
    <string.h>
    #include 
    <io.h>
    #include 
    <malloc.h>
    #include 
    "lexsymb.h"
    %}
    %token ERROR_TOKEN
    %token IF
    %token ELSE
    %token PRINT
    %token INPUT
    %token ASSIGN
    %token EQUAL
    %token NOTEQUAL
    %token CONCAT
    %token END_STMT
    %token OPEN_PAR
    %token CLOSE_PAR
    %token BEGIN_CS
    %token END_CS
    %token ID
    %token INTEGER
    %token STRING
    %%
    file : record file
    | record
    ;
    record : ID EQUAL INTEGER {
    printf(
    "%s is %s years old!!!\n", $1, $3); }
    ;
    %%
    int main()
    {
    yyparse();
    return 0;
    }
    int yyerror(char *msg)
    {
    printf(
    "Error encountered: %s \n", msg);
    return 0;
    }

    yacc文件也跟lex文件一样分成三部分,用%%来分隔,
    第一部分中的%union代码 声明了 Yacc 值栈,并且外部变量 yylval 和 yyval 有等于这个联合的类型。如果使用 -d 选项调用 Yacc,则把联合声明复制到 头文件中(我这里是parse.cpp.h)。二者选一的,联合也可以在头文件中声明,使用 typedef 来定义变量 YYSTYPE 去表示这个联合
    token的定义也在第一部分,-d参数会把这些token的id复制到头文件中。
    先了解了这么多,接下来的任务是yacc文件中规则的编写。
  • 相关阅读:
    Hibernate与JPA的区别是什么
    11 吐司 Toast 代码案例
    万众瞩目之下,ANGULAR 2终于正式发布啦!
    Sencha EXTJS6的 Eclipse 插件安装指南
    安卓6.0新特性在Fragment申请运行时权限
    NDK环境配置
    18 UI美化之level(等级显示显示)
    ABAP SY-SUBRC 使用过程中返回值的几种含义
    SAP中给当前指定的活动用户发系统信息的函数
    SAP中的Currency Converting Factor
  • 原文地址:https://www.cnblogs.com/hyamw/p/690300.html
Copyright © 2020-2023  润新知