网站建设 报价,wordpress怎么没有导航栏,dell网站设计特色,上海企业云服务平台用java开发C语言编译器结构体是C语言中#xff0c;最为复杂的原生数据结构#xff0c;它把多种原生结构结合在一起#xff0c;形成一个有特点含义的数据结构#xff0c;要实现一个完整的C语言编译器或解释器#xff0c;就必须要拥有对结构体的解析能力#xff0c;本节最为复杂的原生数据结构它把多种原生结构结合在一起形成一个有特点含义的数据结构要实现一个完整的C语言编译器或解释器就必须要拥有对结构体的解析能力本节我们在当前解释器的基础上增加结构体的解释执行能力完成本节后我们的解释器可以解析执行下面代码void main() {struct TAG {
int v1;
int v2;
char v3;
} tag;struct TAG myTag;
struct TAG herTag;
myTag.v1 1;
herTag.v1 2;printf(set filed v1 of struct myTag to value : %d, and v1 of herTag to value : %d, myTag.v1, herTag.v1); }
我们先回忆一下结构体的语法表达式struct_specifier - STRUCT OPT_TAG LC def_list RC| STRUCT tag;
我们对比下具体的结构体定义和语法表达式的对应关系struct TAG {
int v1;
int v2;
char v3;
} tag;
上面定义中struct 是关键字对应语法表达式中的STRUCT终结符TAG 是结构体定义名对应表达式中的OPT_TAG; int v1;int v2; char v3; 这三个变量定义对应于def_list,.另一个与结构体相关的语法表达式是unary - unary STRUCTOP NAME
上面表达式用来说明对结构体某个值域的引用例如语句myTag.v1就可以对应上面的语句STRUCTOP是终结符他对应的文本字符为”.”, 或 “-”.在前面的课程我们详细说明过当解释器解析到结构体的定义时它先给结构体变量构建一个symbol对象该symbol对象的修饰符也就是specifier含有一个结构体叫StructDefine, StructDefine 会为结构体中的每一个变量创建一个Symbol对象然后把这些对象串联成一个队列仍然以上面的结构体定义为例我们的解释器解析后形成如下结构图一当我们定义一个结构体变量时例如语句struct TAG myTag; 任何有关变量声明的语句经过一系列递归后最后对应的语法表达式为def - specifiers decl_list SEMI;
当解释器解析代码是递归到上面的表达式时解释器要判断一下当前声明的变量是否是结构体如果是的话那么必须为当前结构体变量赋值一份结构体内部的变量所对应的Symbol队列也就是说当解释器解析到语句 struct TAG myTag;时会把上图的结构再复制一份图二这样一来对结构体某个变量的值域的读写直接转换成对某个变量Symbol的读写就可以了例如代码中的语句myTag.v1 1;这相当与把数值1写入到上图中最下面v1所对应的Symbol对象即可。我们看看相应的代码实现第一步就是当解析到结构体的变量声明时把结构体定义的符号表数据结构复制一份也就是从图1到图2的过程public class LRStateTableParser {
....private void takeActionForReduce(int productNum) {switch(productNum) {....case CGrammarInitializer.Specifiers_DeclList_Semi_TO_Def:Symbol symbol (Symbol)attributeForParentNode;Typelink specifier (Typelink)(valueStack.get(valueStack.size() - 3));typeSystem.addSpecifierToDeclaration(specifier, symbol);typeSystem.addSymbolsToTable(symbol, symbolScope);handleStructVariable(symbol);break;....}
....
}private void handleStructVariable(Symbol symbol) {//先看看变量是否属于struct类型boolean isStruct false;Typelink typelink symbol.typelinkBegin;Specifier specifier null;while (typelink ! null) {if (typelink.isDeclarator false) { specifier (Specifier)typelink.getTypeobject();if (specifier.getType() Specifier.STRUCTURE) {isStruct true;break;}}typelink typelink.toNext();}if (isStruct true) {//把结构体定义中的每个变量拷贝一份存储到当前的symbol中StructDefine structDefine specifier.getStructObj();Symbol copy null, headCopy null, original structDefine.getFields();while (original ! null) {if (copy ! null) {Symbol sym original.copy();copy.setNextSymbol(sym);copy sym;} else {copy original.copy();headCopy copy;}original original.getNextSymbol();}symbol.setArgList(headCopy);}}
handleStructVariable 这个函数的作用就是把图一中的结构复制一遍实现从图一到图二的转换。这样一来当声明同一个结构体类型的不同变量时就像我们的示例代码中声明了两个结构体变量分别是myTag,herTag, 那么对应v1的Symbol对象就有两份对不同的v1赋值实际上是把数值赋值到不同的Symbol对象中。我们再看看对结构体变量的读写例如语句:myTag.v1 1;当执行上面语句时解释器先获得要读写的结构体变量对应域的名称上面给定代码要赋值的域的名称是”v1”, 然后在符号表中找到变量名myTag对应的Symbol对象然后找到Specifer,进而找到StructDefine对象在该对象中找到结构体里面各个变量所对应的Symbol队列然后利用域的名称字符串“v1”,在队列中找到独有的Symbol对象最后把数值1写入到该Symbol对象中。相应代码如下public class UnaryNodeExecutor extends baseExecutor{Overridepublic object Execute(ICodeNode root) {....case CGrammarInitializer.Unary_StructOP_Name_TO_Unary:child root.getChildren().get(0);String fieldName (String)root.getAttribute(ICodeKey.TEXT);symbol (Symbol)child.getAttribute(ICodeKey.SYMBOL);Symbol args symbol.getArgList();while (args ! null) {if (args.getName().equals(fieldName)) {break;}args args.getNextSymbol();}if (args null) {System.err.println(access a filed not in struct object!);System.exit(1);}root.setAttribute(ICodeKey.SYMBOL, args);root.setAttribute(ICodeKey.VALUE, args.getValue());break;....}
}
如果通过结构体对应成员的名字字符串在StructDefine中的Symbol队列中找不到给定名字的Symbol对象这表明程序要访问结构体定义中不存在的变量从而我们的程序就会因此种异常而退出。声明本文于网络整理版权归原作者所有如来源信息有误或侵犯权益请联系我们删除或授权事宜。