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

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.h
class 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.h
class 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.h
class 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 define
void 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 | fun
void 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 | assign
void 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 | assign
Var *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 | SEM
void 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 -> addexpr
Var *Parser::expr() {
    Var *var = addexpr();
    return var;
}
//addexpr -> iterm addpart
//addpart -> addopr iterm addpart|~
//addopr -> ADD SUB
Var *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|BOL
Var *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|BOL
Var *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.其他规划