java开发C编译器:结构体的解析和执行
来源:互联网 发布:电脑视频监控软件 编辑:程序博客网 时间:2024/05/18 23:54
更详细的讲解和代码调试演示过程,请参看视频
用java开发C语言编译器
结构体是C语言中,最为复杂的原生数据结构,它把多种原生结构结合在一起,形成一个有特点含义的数据结构,要实现一个完整的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{ @Override public 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对象,这表明程序要访问结构体定义中不存在的变量,从而我们的程序就会因此种异常而退出。
本节内容较为复杂,请参看视频获得更详实的讲解和代码调试演示。
更多技术信息,包括操作系统,编译器,面试算法,机器学习,人工智能,请关照我的公众号:
- java开发C编译器:结构体的解析和执行
- java实现C编译器:for 循环语句的解析和执行
- java方法调用过程解析和执行--编译器的处理
- java开发C语言编译器: return 语句的解释和执行
- java开发C语言解释器:间套结构体的解释和执行
- java开发编译器:C语言逻辑控制语句if else if 的语法解析
- 编译器开发:C语言循环控制语句的解析
- linux的vi比编译器开发java和c的步骤
- java开发编译器:自底向上语法解析的基本原理
- C编译器编译结构体时的对齐原则
- java解析C结构体框架
- java开发C语言编译器: JVM的基本原理
- 使用Lex和Yacc开发C语言的编译器
- 使用Lex和Yacc开发C语言的编译器
- 使用Lex和Yacc开发C语言的编译器
- C语言结构体、C++结构体和C++类的解析
- C编译器剖析_4.4 语义检查_外部声明_结构体和数组的初始化
- 行为驱动开发: Cucumber的目录结构和执行过程
- 数据结构03栈和队列
- CDN是什么?使用CDN有什么优势?
- UGUI学习手记-ExecuteEvents & EventInterface
- Java开发环境的配置步骤。
- Jave_erhui
- java开发C编译器:结构体的解析和执行
- Picasso 图片加载及缓存的使用心得
- 使用C#清空Edge浏览器的Cookie
- Javascript 闭包与高阶函数 ( 一 )
- servlet文件操作
- 写下这篇博客的初衷
- openwrt系统 sysupgrade 命令执行过程分析
- HDU1003
- 安卓基础知识