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