java开发C语言编译器:为C语言提供API调用
2017-01-10 10:41
295 查看
更详细的讲解和代码调试演示过程,请参看视频
用java开发C语言编译器
我们第一次使用C语言开发程序时,往往是在控制台上打印一句”Hello World”,实现打印语句功能的函数是printf, 这个函数是有C语言的链接库提供的,开发者可以直接调用,类似于这种无需自己实现,直接可以调用的函数,我们都称为库函数,或是API, 本节,我们要为当前构建的虚拟机提供C语言库函数,我们要给解释器提供一种函数调用机制,这些函数无需程序自己实现,而是由我们的解释器提供的,C语言程序直接调用即可,这节,我们要实现的一个库函数就是printf. 完成本节代码后,我们的解释器能解释执行下面程序:
printf函数是我们解释器提供给代码的,有了库函数,程序的开发便能高效很多。
库函数机制的实现由新构造的类ClibCall,我们先看看它的实现代码:
ClibCall 包含了一个集合类叫apiSet, 其用于存储库函数的函数名,当代码中有函数调用时,解释器拿到被调函数的名字,提交给ClibCall, 该类会在apiSet中查找是否含有与给定名字相同的字符串,如果有,那意味着该函数属于库函数。
由于目前我们只实现了一个库函数printf, 因此初始化时,我们把字符串”printf”加入到该集合中。 isAPICall 传入的是函数名,如果函数名包含在apiSet里面,那么返回true, 表明他是库函数调用。
invokeAPICall 用来执行给定的库函数,传入参数是库函数的名称。在里面,解释器根据不同的库函数名称,去实现不同的库函数。handlePrintfCall用于实现printf调用,首先,它获得输入参数,第一个输入参数是要显示到控制台上的字符串,在字符串中,可能会含有格式化字符,当前我们实现的printf可接受的格式化字符是%d. 在printf的模拟实现中,我们遍历每一个字符,当遇到%d时,我们从参数列表中获得对应的数值,然后把数值替换%d格式符,最后通过println把格式化后的字符串打印到控制台上。
有了库函数调用后,每当解释器解析到函数调用是,需要确定当前调用的函数是代码自己实现的,还是库函数提供的,这个机制的实现在UnaryExecutor中,代码如下:
当解释器解析函数调用时,它现在函数调用表中,查找给定函数的语法执行树头结点,如果找不到的话,那么解释器知道,这个函数是库函数,于是调用ClibCall来处理,它先通过isAPICall来判断,给定函数是否是库函数,如果是的话,则调用invokeAPI来执行库函数提供的功能。
有了ClibCall, 以后我们想要添加新的库函数时,只要修改ClibCall的实现即可,基于现在的架构基础上,我们今后可以快速的实现更多库函数,从而让我们的解释器越来越强大!
更加具体的代码解释和调试过程请参看视频。
更多技术信息,包括操作系统,编译器,面试算法,机器学习,人工智能,请关照我的公众号:
用java开发C语言编译器
我们第一次使用C语言开发程序时,往往是在控制台上打印一句”Hello World”,实现打印语句功能的函数是printf, 这个函数是有C语言的链接库提供的,开发者可以直接调用,类似于这种无需自己实现,直接可以调用的函数,我们都称为库函数,或是API, 本节,我们要为当前构建的虚拟机提供C语言库函数,我们要给解释器提供一种函数调用机制,这些函数无需程序自己实现,而是由我们的解释器提供的,C语言程序直接调用即可,这节,我们要实现的一个库函数就是printf. 完成本节代码后,我们的解释器能解释执行下面程序:
void main() { printf("a is %d:",1); }
printf函数是我们解释器提供给代码的,有了库函数,程序的开发便能高效很多。
库函数机制的实现由新构造的类ClibCall,我们先看看它的实现代码:
package backend; import java.util.ArrayList; import java.util.HashSet; import java.util.Set; public class ClibCall { private Set<String> apiSet; private ClibCall() { apiSet = new HashSet<String>(); apiSet.add("printf"); } private static ClibCall instance = null; public static ClibCall getInstance() { if (instance == null) { instance = new ClibCall(); } return instance; } public boolean isAPICall(String funcName) { return apiSet.contains(funcName); } public Object invokeAPI(String funcName) { switch (funcName) { case "printf": return handlePrintfCall(); default: return null; } } private Object handlePrintfCall() { ArrayList<Object> argsList = FunctionArgumentList.getFunctionArgumentList().getFuncArgList(false); String argStr = (String)argsList.get(0); String formatStr = ""; int i = 0; int argCount = 1; while (i < argStr.length()) { if (argStr.charAt(i) == '%' && i+1 < argStr.length() && argStr.charAt(i+1) == 'd') { i += 2; formatStr += argsList.get(argCount); argCount++; } else { formatStr += argStr.charAt(i); i++; } } System.out.println(formatStr); return null; } }
ClibCall 包含了一个集合类叫apiSet, 其用于存储库函数的函数名,当代码中有函数调用时,解释器拿到被调函数的名字,提交给ClibCall, 该类会在apiSet中查找是否含有与给定名字相同的字符串,如果有,那意味着该函数属于库函数。
由于目前我们只实现了一个库函数printf, 因此初始化时,我们把字符串”printf”加入到该集合中。 isAPICall 传入的是函数名,如果函数名包含在apiSet里面,那么返回true, 表明他是库函数调用。
invokeAPICall 用来执行给定的库函数,传入参数是库函数的名称。在里面,解释器根据不同的库函数名称,去实现不同的库函数。handlePrintfCall用于实现printf调用,首先,它获得输入参数,第一个输入参数是要显示到控制台上的字符串,在字符串中,可能会含有格式化字符,当前我们实现的printf可接受的格式化字符是%d. 在printf的模拟实现中,我们遍历每一个字符,当遇到%d时,我们从参数列表中获得对应的数值,然后把数值替换%d格式符,最后通过println把格式化后的字符串打印到控制台上。
有了库函数调用后,每当解释器解析到函数调用是,需要确定当前调用的函数是代码自己实现的,还是库函数提供的,这个机制的实现在UnaryExecutor中,代码如下:
public class UnaryNodeExecutor extends BaseExecutor{ @Override public Object Execute(ICodeNode root) { executeChildren(root); int production = (Integer)root.getAttribute(ICodeKey.PRODUCTION); String text ; Symbol symbol; Object value; ICodeNode child; switch (production) { .... case CGrammarInitializer.Unary_LP_ARGS_RP_TO_Unary: //先获得函数名 String funcName = (String)root.getChildren().get(0).getAttribute(ICodeKey.TEXT); if (production == CGrammarInitializer.Unary_LP_ARGS_RP_TO_Unary) { ICodeNode argsNode = root.getChildren().get(1); ArrayList<Object> argList = (ArrayList<Object>)argsNode.getAttribute(ICodeKey.VALUE); FunctionArgumentList.getFunctionArgumentList().setFuncArgList(argList); } //找到函数执行树头节点 ICodeNode func = CodeTreeBuilder.getCodeTreeBuilder().getFunctionNodeByName(funcName); if (func != null) { Executor executor = ExecutorFactory.getExecutorFactory().getExecutor(func); executor.Execute(func); Object returnVal = func.getAttribute(ICodeKey.VALUE); if (returnVal != null) { System.out.println("function call with name " + funcName + " has return value that is " + returnVal.toString()); root.setAttribute(ICodeKey.VALUE, returnVal); } } else { ClibCall libCall = ClibCall.getInstance(); if (libCall.isAPICall(funcName)) { Object obj = libCall.invokeAPI(funcName); root.setAttribute(ICodeKey.VALUE, obj); } } .... }
当解释器解析函数调用时,它现在函数调用表中,查找给定函数的语法执行树头结点,如果找不到的话,那么解释器知道,这个函数是库函数,于是调用ClibCall来处理,它先通过isAPICall来判断,给定函数是否是库函数,如果是的话,则调用invokeAPI来执行库函数提供的功能。
有了ClibCall, 以后我们想要添加新的库函数时,只要修改ClibCall的实现即可,基于现在的架构基础上,我们今后可以快速的实现更多库函数,从而让我们的解释器越来越强大!
更加具体的代码解释和调试过程请参看视频。
更多技术信息,包括操作系统,编译器,面试算法,机器学习,人工智能,请关照我的公众号:
相关文章推荐
- Java开发调用PageOffice提供的Word手写批注接口
- CloudStack4.4开发,API调用java实例
- java微信开发API解析(三)-高级功能的前奏----获取以及保存接口调用凭证 标签: 微信java办微信开发微信文档解析 2016-04-06 20:50 1101人阅读 评论(0) 收藏 举报
- JPush极光推送 Java调用服务器端API开发
- java开发系统内核:使用一个中断实现多个API调用
- 分享:写了一个 java 调用 C语言 开发的动态库的范例
- 使用Java调用ElasticSearch提供的相关API进行数据搜索完整实例演示
- JPush极光推送 Java调用服务器端API开发
- java微信开发API第三步 微信获取以及保存接口调用凭证
- java开发C语言编译器:把C语言的数组操作转换成java字节码
- android开发教程(十三)——JAVA基础之理解JNI原理(java调用C语言接口)
- JPush极光推送 Java调用服务器端API开发
- Windows下使用Java调用ElasticSearch提供的相关API进行数据搜索完整实例演示
- 微信支付开发教程JAVA编[008]-wxsdk4java:微信公众号和微信支付开发的所有API功能点的封装及调用实例
- 我用纯C语言开发的中英文混合分词服务器3.0正式发布,词库190多万词,每秒切分5万+,同时提供 c、java、C#、delphi、js调用范例
- 外贸开发,用java调用速卖通api第一步,token的获取。
- 用java的jni调用C语言的API,实现带图形界面的一元稀疏多项式计算器
- 使用Java调用ElasticSearch提供的相关API进行数据搜索完整实例演示
- java开发的通过dll调用mt4 API
- java开发系统内核:实现系统API调用