本节主要内容是通过编码实现上几节中定义的文法,同时也包含部分语义的分析。通过本节内容,可以完成以下自定义代码的文法解析和语义分析。
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.其他规划
1943

被折叠的 条评论
为什么被折叠?



