当我们分析到 "int n;",说明其已经定义了一个变量,之后又遇到一个 "n=3",我们从哪里去找这个n并且赋值呢?
答案是:通过我们定义的 变量表(Table) 中查找。
其实,这变量声明定义与变量赋值一系列动作,都是由语义分析器负责的。
1. 当扫描到一个声明语句,比如 "string x;" 时:
1)在语法分析中,当检测到 string <type>,其会将 (string,x)保存在(tVar.type,tVar.name)。
2)调用 Table.addVar ,该函数会生成一个新的 变量对象(var_record),然后添加进 map<> 中。
3)当之后遇到 x = ''hello world"时,其会调用 Table.getVar(x),然后将其赋值为 "hello world",这样就实现了赋值。
2. var_record类定义如下():
1 class var_record { 2 public: 3 symbol type; // 类型 4 string name; // 名称 5 6 // 变量值 7 int intVal; // 整数 8 string strVal; // 字符串 9 10 11 12 int localAddr; // 局部变量相对于ebp指针的地址,或者临时string的索引地址 13 var_record(); // 默认构造函数 14 void init(symbol dec_type, string dec_name); // 声明初始化函数 15 var_record(const var_record& v);//拷贝构造函数 16 ~var_record(); 17 };
1)变量值一开始打算使用 union{int,string} 来实现,但在c++union作为类,存在权限访问冲突(暂时没解决),因此就分开来实现。
3. Table 变量表的定义如下:
1 class Table { 2 map<string, var_record*> var_map; // 变量声明列表 3 public: 4 Table(); // 构造函数 5 void addVar(); // 添加变量声明记录,默认使用tvar 6 7 // 该函数估计暂时用不到 8 //void addVar(var_record*v); // 添加变量声明记录,重载(赋值已声明的变量后则要实现重载) 9 var_record * getVar(string name); // 获取已经记录的变量名 10 };
1)Table类核心就是围绕map<>结构来建立
2)两个方法,一个是添加变量,另一个是找到变量。
4. 简单的测试代码(模拟"遇到字符串与数字的定义赋值与输出")
1 #include "pch.h" 2 #include "semantic.h" 3 #include <iostream> 4 #include <string> 5 #include <map> 6 using namespace std; 7 8 map<string, int> a; 9 10 /* 11 模拟变量声明过程 12 int a; 13 a = 3; 14 */ 15 16 int main() { 17 // 建立一个全局变量表 18 19 Table VarTable; 20 21 // int a; 22 tVar.type = NUM; // 变量类型是 NUM(INT) 数字类型 23 tVar.name = "a"; // 添加变量名 24 VarTable.addVar(); // 其默认将tVar 添加进表中 25 26 // a = 3; 27 var_record * a = VarTable.getVar("a"); // 拿出变量a 28 a->intVal = 3; // 将a 赋值为 3 29 30 // 输出结果 31 // cout << a << endl 32 cout << VarTable.getVar("a")->intVal << endl; 33 34 35 // string x; 36 tVar.type = STR; // 变量类型是 NUM(INT) 数字类型 37 tVar.name = "x"; // 添加变量名 38 VarTable.addVar(); // 其默认将tVar 添加进表中 39 40 // x= "hello world"; 41 var_record * x = VarTable.getVar("x"); // 拿出变量x 42 x->strVal = "hello world"; // 将a 赋值为 3 43 int tt =4; 44 45 cout << VarTable.getVar("x")->strVal << endl; 46 return 0; 47 }
测试结果符合要求。