文法及语义代码实现 | 从零实现一门语言

        本节主要内容是通过编码实现上几节中定义的文法,同时也包含部分语义的分析。通过本节内容,可以完成以下自定义代码的文法解析和语义分析。

int test(int x){    int y = 10;    int n = 2;    int z = x + y * 2;    return z;}int main(){    int a = 10;    int b = 20;    string e = "hello world";    int d = test(a,b);    return d;}

符号和符号表

    在文法中我们分析了源程序的基本结构由变量和函数组成,称为符号。符号表用于保存上下文中定义的符号。文中代码非完整代码,考虑篇幅进行了裁剪。

//symbol.hclass Var {    string name;    Tag type;   //变量类型    int size;   //大小    //各种类型常量的值    int num_val;    char ch_val;    string str_val;    Var *data;  //变量的值    vector<int> scope;  //作用域}class Func{    string name;    Tag rtype;  //返回值类型    vector<Var*> params; //参数列表    vector<int> scope;  //作用域}

    符号表的实现。

//symtab.hclass Symtab {    unordered_map<string, vector<Var *> *> var_map;    //变量集合    unordered_map<string, Func *> func_map;  //函数集合    vector<string> var_seq;     //变量序列    vector<string> func_seq;    //函数序列    vector<Var *> str_list;      //字符常量集合    int scope;      //当前作用域    vector<int> scope_seq;      //作用域序列    Func *current;      //当前方法public:    void addVar(Var *var);    void addFunc(Func *func);    void addStrVar(Var *var);    vector<int>& getScope();    Var* getVar(string name);    Func* getFunc(string name);    Symtab();    ~Symtab();};

文法解析器

//parser.hclass Parser {    Lexer &lexer;   //词法解析器    Token *token;   //词法标记    Symtab &symtab;     //符号表private:    void next();        //向后读取一个词法标记    void program();     //先解析主程序    void cdsmt();       //再解析代码段    Tag defType();    void define(Tag t);    void defOne(Tag t, string idName);    void defVar(Tag t, vector<string>& ids);    Var* idVar();    void defList(Tag t, vector<string>& ids);    void defFun(Tag t, string name);    void defFunImpl(Func* f);    void defStatmt();    void defFramgment();    void defLocalval();    void defParams(vector<Var*>& params);    Var* assign();    Var* expr();    Var* addexpr();    Var* iterm();    Var* itermpart(Var* var);    Var* factor();    Var* valpart();    Var* addpart(Var* var);    Var* val();    Var* funcallexpr(string name, Func* func);public:    void process();     //语法处理入口    Parser(Lexer &lexer1, Symtab &symtab1);    ~Parser();};

    next() 函数是将词法标记序号移动到下一位。

void Parser::next() {    token = lexer.fetch();}

    process();文法处理的主程序。

void Parser::process() {    next(); //读取下一个标记    program(); //解析程序文法}

    program() 对应文法中的源程序实现,cdsmt() 对应文法的代码段实现。

//文法:prog -> cdsmt prog|~void Parser::program() {    if (token->tag == END) {        return;    }    cdsmt(); //解析代码段文法    program(); //递归主程序}   
//cdsmt -> type definevoid Parser::cdsmt() {    Tag t = defType();    define(t);}

    defType() 获取符号的类型,define() 定义符号的实现。

Tag Parser::defType() {    next();    Tag t = token->tag;    if(t == INT || t == CHAR || t == VOID || t == STR || t == BOL){        next();        return t;    }else if(t == ID){        return ID;    } else{        return UKN;    }}//define-> defone deflist | funvoid Parser::define(Tag t) {    if(token->tag == ID){        string idName = ((Id *)token)->name;        next();        defOne(t, idName);    }else{        printf("ID[%s] is not correct, error line is %s\n", token->toString().c_str(), lexer.lineInfo().c_str());        exit(1);    }}

    defOne() 单个符号申明的实现。

//defone -> ID defvar func| assign;//defvar -> idvar deflist|~//deflist -> COMMA idvar|~//idvar -> NUM STR CH | assignvoid Parser::defOne(Tag t, string idName) {    //先判断是否为函数,“(“开头为函数,否则为变量    if (token->tag == LPR) {        defFun(t, idName);    } else{        vector<string> ids = {idName};        defVar(t, ids);    }}

    defvar() 变量符号的实现。

//defvar -> idvar idlist|~void Parser::defVar(Tag t, vector<string> &ids) {    //根据”,“判断变量是单个还是多个    if (token->tag == COMMA) {        defList(t, ids);    } else{        Var *value = idVar();        Var *var = symtab.getVar(ids.front());        if (var) {            var->setVarData(value);        } else {            var = new Var(ids.front(), value, t, symtab.getScope());            symtab.addVar(var);        }    }}//idvar -> NUM STR CH | assignVar *Parser::idVar() {    return assign();}

    defList() 多个变量符号的实现。

void Parser::defList(Tag t, vector<string> &ids) {    while (true) {        next();        ids.push_back(((Id *) token)->name);        next();        //判断下一个记号是否为","        if (token->tag == COMMA) {            continue;        } else {            break;        }    }    Var *v = idVar();    for (string names: ids) {        Var *var = symtab.getVar(names);        if(!var){            var = new Var(names, v, t, symtab.getScope());            symtab.addVar(var);        }else{            var->setVarData(v);        }    }}

    defFun() 函数的实现。

//fun -> ID LPA parms RPA funimpl//funimpl -> statmt | SEMvoid Parser::defFun(Tag t, string name) {    next();    vector<Var *> params;    defParams(params);    if (token->tag != RPR) {        printf("func is not end with ')'");        exit(1);    }    Func* func = new Func(t, name, params);    symtab.addFunc(func);    //函数实现    defFunImpl(func);}void Parser::defFunImpl(Func *f) {    next();    Tag t = token->tag;    if (t == LBE) {  //以"{"开始为函数实现        defStatmt();        next();    } else if (t == SEM) {        printf("func define is not support error:\n", lexer.lineInfo().c_str());//函数定义        exit(1);    } else {        printf("func end of error: %s, error:%s\n", token->toString().c_str(), lexer.lineInfo().c_str());        exit(1);    }}

    expr() 表达式的实现。

​//assign-> ASSIGN expr | ~Var *Parser::assign() {    Tag tag = token->tag;    if (tag == ASSIGN) {        next();        return expr();    } else{        printf("assign expression is not correct, line is[%s]\n", lexer.lineInfo().c_str());        exit(1);    }}//expr -> addexprVar *Parser::expr() {    Var *var = addexpr();    return var;}//addexpr -> iterm addpart//addpart -> addopr iterm addpart|~//addopr -> ADD SUBVar *Parser::addexpr() {    Var *var = iterm();    return addpart(var);}Var *Parser::iterm() {    Var *var = factor();    return itermpart(var);}Var *Parser::itermpart(Var *var) {    Tag t = token->tag;    if (t == MUL || t == DIV) {        next();        Var *vars = factor();        Var *tmp = new Var(INT, "tempName", symtab.getScope());        string mark = t == MUL ? "*" : "/";        printf("code:[%s %s %s]\n", var->getName().c_str(), mark.c_str(), vars->getName().c_str());        return itermpart(tmp);    }    return var;}//factor -> leftopr factor |valpart//leftopr -> ! & ++ --//valpart -> val rightpor//rightopr -> ++ --//val -> ID |LPA expr RLA| NUM|CHAR|STRING|BOLVar *Parser::factor() {    Tag t = token->tag;    //左结合语句暂支持取负,此外还有--,++    if (t == SUB) {        next();        Var *v = factor();        //此处要考虑左值和右值结合的临时变量        Var *tmp = new Var(token->tag, "NE_TMP", symtab.getScope());        symtab.addVar(tmp);        printf("NE_TMP = -%s\n", v->getName().c_str());        return tmp;    } else {        return valpart();    }}Var *Parser::valpart() {    return val();}Var *Parser::addpart(Var *val) {    Tag tag = token->tag;    if (tag == ADD || tag == SUB) {        next();        Var *vars = iterm();        Var *temp = new Var(INT, "tempName", symtab.getScope());        string mark = tag == ADD ? "+" : "-";        printf("code: [%s %s %s]\n", val->getName().c_str(), mark.c_str(), vars->getName().c_str());        next();        return addpart(temp);    }    return val;}//val -> ID |LPR expr RLR| NUM|CHAR|STRING|BOLVar *Parser::val() {    Tag t = token->tag;    if (t == ID) {        string idName = ((Id *) token)->name;        next();        if (token->tag == LPR) {//函数调用            return funcallexpr(idName, nullptr);        } else {//否则为变量            return symtab.getVar(idName);        }    } else if (t == NUM || t == CHAR || t == STR || t == BOL) {        Var *var = new Var(token);        symtab.addVar(var);        next();        return var;    } else {        printf("not support other val type: %s, line: %s", to_string(t).c_str(), lexer.lineInfo().c_str());        exit(1);    }}

   为便于理解,代码中比较关键的部分补充了注释。整体逻辑不算太复杂,因为我们实现的内容并不多,主要涵盖了上几节中的文法。在解析过程中,如遇到不符合自定义的语法,为简化复杂度,直接抛出相应代码所在的行数,并终止程序。错误处理并不完善,没有在出现错误后继续往后读取,直至尽可能找到更多错误。另外,文中虽然定义了变量作用域,但没有真实使用到,我们将在后续的中间代码里实现。

    功能支持如下:

    (1)变量类型支持:int、char、string、bol以及无类型void;

    (2)运算符支持:+、-、*、/、-、+、=;

    (3)函数声明及调用;

    下一节我们将进行中间代码的生成,考虑到中间代码的生成是需要了解函数的栈帧调用的,所以决定先讲解计算机系统的函数调用过程和部分汇编的基本知识。

欢迎关注公众号:零点码起。


     目录

     1.一个hello world的诞生

     2.词法解析器

     3.从自然语言认识文法

     4.构造文法

     5.文法及语义代码实现

     6.代码函数的帧栈调用过程

     7.生成中间代码

     8.汇编

     9.编译和链接

     10.终于跑起来了

     11.多文件编译

     12.丰富数据类型

     13.流程控制语句

     14.编译优化算法

     15.文件读取

     16.一个线程的实现

     17.什么是锁

     18.网络编程

     19.面向对象

     20.其他规划

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值