用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{@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对象,这表明程序要访问结构体定义中不存在的变量,从而我们的程序就会因此种异常而退出。

声明:

本文于网络整理,版权归原作者所有,如来源信息有误或侵犯权益,请联系我们删除或授权事宜。

java开发C编译器:结构体的解析和执行相关推荐

  1. Java开发岗高频面试题全解析补充知识点(个人补充整理的知识点,非原文)

    第3章 Java核心技术 这里仅补充牛客专刊<Java开发岗高频面试题全解析>提到但是未展开讲解的知识点,个人收录向. 3.3.1 String.StringBuffer.StringBu ...

  2. Java开发中Netty线程模型原理解析!

    Java开发中Netty线程模型原理解析,Netty是Java领域有名的开源网络库具有高性能和高扩展性的特点,很多流行的框架都是基于它来构建.Netty 线程模型不是一成不变的,取决于用户的启动参数配 ...

  3. Java中如何实现结构体?如何对结构体进行排序?

    ***今天在做老师布置的编程题时,遇到了本题.感觉这道题如果用C++来解决的话,用结构体比较好吧!哈哈哈,可能还有其他的好方法,但我目前想到的是用结构体来解决比较合理.Java中有结构体吗?如果有,它 ...

  4. java解析c的结构体_解析C语言中结构体struct的对齐问题

    首先看一下结构体对齐的三个概念值: 数据类型的默认对齐值(自身对齐): 1.基本数据类型:为指定平台上基本类型的长度.如在32位机器中,char对齐值为1,short为2,int,float为4,do ...

  5. Linux 字符设备驱动结构(四)—— file_operations 结构体知识解析

    前面在 Linux 字符设备驱动开发基础 (三)-- 字符设备驱动结构(中) ,我们已经介绍了两种重要的数据结构 struct inode{...}与 struct file{...} ,下面来介绍另 ...

  6. Java向C++发送结构体

    最近给个朋友做个网站的客户端,使用C/S模式,Client为VC6开发,Server为Java,通过Socket通信.由于Client这边为C++,所以,在接受Java发过来的数据包时,需要知道发来的 ...

  7. 用JAVA定义两个结构体_c语言struct结构体的定义和使用

    c语言由于不像java,c#,c++等语言有对象,所以就用struct结构体来表示,其实作用是差不多的,下面来快速学习c语言struct结构体的定义和使用,以学生类student来举例,有三种定义方式 ...

  8. c语言结构体反射解析,C语言结构体解析

    我们知道定义一个数组就等于定义了多个相同类型的变量,它们的类型是一样的.有时有这样的需求,如果我想保存一些信息,但每个信息类型不一定相同,这时该怎么办?我们就可以自己定义一类型,而这个类型,就是结构体 ...

  9. java发送c语言结构体_C语言中结构体直接赋值?

    在C语言中结构体变量之间可以进行赋值操作吗? 简单结构体的赋值 先说结论:一般来说,C语言中的结构体变量可以用另一个变量对其进行赋值或初始化.简单结构体(不包含指针成员)直接赋值没有问题. 我们先下面 ...

最新文章

  1. JXJJOI2018_T1_market
  2. 京东千万并发 API 网关实践之路!
  3. SEO优化如何让网站关键词排名稳如狗?
  4. RobotFramework自动化4-批量操作案例
  5. 如果诸葛亮用C++写出师表。。。。
  6. 远程桌面配置php,Win2008 R2实现多用户远程连接设置方法(图)
  7. Array.prototype.slice.apply(arguments)和[].slice.apply(arguments)解析
  8. linux之git入门命令
  9. 如何使用jQuery刷新页面?
  10. 12c集群日志位置_关于Oracle 12c的集群监控(CHM)
  11. 十二、I/O复用介绍
  12. ActiveMQ 命令行启动 与 嵌入式启动、MessageListener 监听消息
  13. 用maven编译spark2.1.0
  14. 直流有刷电机(可以用L298N来驱动)
  15. jsp超市仓库管理系统myeclipse开发sqlserver数据库
  16. 计算机基础知识及键盘熟悉实验报告,计算机基础实验报告实验一二.doc
  17. NOIP2016:换教室
  18. matlab latex emf 乱码,latex 使用中的一些问题
  19. HHL论文及代码理解(Generalizing A Person Retrieval Model Hetero- and Homogeneously ECCV 2018)...
  20. docker---dockerfile 编写优化

热门文章

  1. aop 代码_项目学生:使用AOP简化代码
  2. java jpa 规范_Java:在JPA中使用规范模式
  3. 1.0jpa 2.0_在JPA 2.1中使用@Convert正确完成映射枚举
  4. tomcat web应用_具有可执行Tomcat的独立Web应用程序
  5. JavaParser中AST节点的观察者
  6. 如何编写Java代理
  7. SSL与WildFly 8和Undertow
  8. 使用Apache Camel 2.14的轻松REST端点
  9. 想要更快地使用AtomicLong? 等待它。
  10. Java方法中的参数太多,第5部分:方法命名