zoukankan      html  css  js  c++  java
  • 使用bison和yacc制作脚本语言(3)

    我们现在已经可以写好文法了,下一步我们打算开始正式创建工程了

    在工程目录下,我们创建如下文件夹

    ./include
    ./memory
    ./ms
    

    include文件夹下我们将放头文件

    memory是内存管理模块,检测内存泄漏

    ms文件夹主要是放源文件

    memory内存管理模块可以参考我另一个随笔 https://www.cnblogs.com/stdpain/p/10484403.html ,不愿意了解的话直接把里面的函数当做mallocfree即可

    我们先创建lex文件ms.l这个是flex使用的文件,下面是部分代码:

    %{
    #include <stdio.h>
    #include <string.h>
    #include "../include/create.h"
    #include "y.tab.h"
    
    /* 一个功能性函数-都要加 */
    int
    yywrap(void)
    {
        return 1;
    }
    
    %}
    %start COMMENT STRING_LITERAL_STATE
    %%
    <INITIAL>"function"  return FUNCTION;
    <INITIAL>[A-Za-z_][A-Za-z_0-9]* {
        yylval.identifier = Interpreter_str_malloc(yytext);
        return IDENTIFIER;
    }
    

    %{ 中的内容会被原封不动的输出到文件中,%%之后是正则表达式匹配然后返回某个token(终结符),将会被bison识别,<...>前缀代表状态的意思,因为正则表达式有时候有一定的局限性(贪心匹配)

    {}中的内容可以使用我们定义好的函数,当成功匹配的时候会执行里面的函数,return 也是返回某个token,yylval是yacc内置的对象,我们可以让yylval保存一些变量

    我们接着编写其他的正则表达式

    <INITIAL>([1-9][0-9]*)|"0" {
        int temp;
        sscanf(yytext, "%d", &temp);
        yylval.integer = temp;
        return INT_LITERAL;
    }
    <INITIAL>[0-9]+\.[0-9]+ {
        double temp;
        sscanf(yytext, "%lf", &temp);
        yylval.db = temp;
        return DOUBLE_LITERAL;
    }
    

    以上两个分别是整数和浮点数的正则表达式,通过scanf读取然后保存到yylval中

    <INITIAL>\" {
    	open_charbuffer();
    	BEGIN STRING_LITERAL_STATE;
    }
    

    当遇见\"的时候说明遇到了字符串,这个时候很多规则都会变动,我们可以让他转换到另一个状态 BEGIN 后面就是状态的名字, open_charbuffer()是我们写的函数用于打开一个缓冲区存放字符串

    <STRING_LITERAL_STATE>\"        {
        yylval.identifier = flush_charbuffer();
        BEGIN INITIAL;
        return STRING_LITERAL;
    }
    <STRING_LITERAL_STATE>\n        {
        addc_charbuffer('\n');
    }
    <STRING_LITERAL_STATE>\\\"      addc_charbuffer('"');
    <STRING_LITERAL_STATE>\\n       addc_charbuffer('\n');
    <STRING_LITERAL_STATE>\\t       addc_charbuffer('\t');
    <STRING_LITERAL_STATE>\\\\      addc_charbuffer('\\');
    <STRING_LITERAL_STATE>.         addc_charbuffer(yytext[0]);
    

    在字符串模式下,我们可以在遇到各种字符的时候可以添加到缓冲区,注意特殊字符需要转义,再次遇到\"的时候把缓冲区刷新然后保存这个字符串到yylval中并且转移到初始模式

    <INITIAL>.      {
        //error
        char buf[1024];
        if (isprint(yytext[0])) {
            buf[0] = yytext[0];
            buf[1] = '\0';
        } else {
            sprintf(buf, "0x%02x", (unsigned char)yytext[0]);
        }
        printf("meet:%s",buf);
        abort();
    }
    

    遇到期望之外的字符直接错误处理即可,

    这几个字符串缓冲区函数我们先简单实现一下即可,有较长字符串需求的时候再重新写

    void open_charbuffer()
    {
        buffer = Interpreter_malloc(100);
        pos = 0;
    }
    void addc_charbuffer(char c)
    {
        assert(buffer);
        assert(pos < 100);
        buffer[pos++] = c;
    }
    char *flush_charbuffer()
    {
        char *p = buffer;
        buffer[pos] = 0;
        buffer = NULL;
        return p;
    }
    

    代码已经上传至github地址:https://github.com/stdpain/compiler-interpreter

    其中ms.l在ms/ms.l

  • 相关阅读:
    UVALive
    训练指南 UVA
    训练指南 UVALive
    Codeforces Round #535 (Div. 3)
    训练指南 UVALive
    训练指南 UVALive
    Codeforces Round #534 (Div. 2)
    Codeforces Round #532 (Div. 2)
    《算法问题实战策略》——chaper9——动态规划法技巧
    《训练指南》——8.3
  • 原文地址:https://www.cnblogs.com/stdpain/p/10528826.html
Copyright © 2011-2022 走看看