前文.NET框架源码解读之MYC编译器讲了MyC编译器的架构,整个编译器是用C#语言写的,上图列出了MyC编译器编译一个C源文件的过程,编译主路径如下:

  1. 首先是入口Main函数用来解析命令行参数,读取源文件,并开始编译过程。Main函数在MyC.cs文件,而IO.cs文件主要保存读取源码文件的相关操作。下表是Main函数的源码(批注用注释的方式显示),IO.cs文件用单独的一个小节说明:
public static void Main()
{try
{// 看源码注释,代码是99年写的,也就是说.NET当年正在开发中// 可能那个时候虚拟机都没有做好向Main函数传递命令行参数的开发// 用了下面这个奇葩方法获取程序的命令行参数String[] args = Environment.GetCommandLineArgs();// 初始化读取源文件的IO对象,该对象负责将源文件以字节流的方式// 输出给下一个对象 – 词法分析Io prog = new Io(args);// 词法分析对象,该对象的工作是过滤掉源码中不必要的字符,比如空格// 注释之类的,并且把源码中的字符归类 – Tokenize,以便语法分析器// 更方便的解析语法Tok tok = new Tok(prog);// 语法分析对象,解析完毕后即是代码生成阶段,但一般语法分析过程// 都只会生成语法树,这样的设计可以对接多种结果文件输出手段。比如// 说,本例中生成可执行文件的exe.cs和生成IL源码的asm.cs都是通过// 遍历语法树,使用不同的输出策略生成结果文件的Parse p = new Parse(prog, tok);// 采用自顶向下的方式进行语法解析p.program();// 编译工作已经完成,关闭打开的源文件句柄等资源prog.Finish();}catch (Exception e)
{// 编译过程中有任何错误,即中断处理,打印错误消息并退出程序Console.WriteLine("Compiler aborting: " + e.ToString());}
}

  

  1. MyC的语法很简单,因此编译过程是很干净的词法分析、语法分析、代码生成和结果输出的过程。其中词法分析代码在tok.cs,语法分析代码在parse.cs中,Emit.cs处理代码生成,而Asm.cs和Exe.cs分别根据命令行参数的设置,来生成最终的可执行文件并选择是否输出IL源码。 IO.cs - IO处理 将源文件读取进内存,并采用流式处理的代码都放在IO这个类里面,IO的构造函数解析命令行参数,并打开源文件,等待Tok.cs里面代码的指令将源文件的字符一个个读进内存并处理,下面是它的构造函数的源码:
public Io(String[] a){int i;args = a;// 解析命令行参数,并根据参数打开内部的控制开关,详情请看下面对ParseArgs// 函数的源码解读ParseArgs();// 打开要编译的源文件ifile = new FileStream(ifilename, FileMode.Open,FileAccess.Read, FileShare.Read, 8192);// 如果源文件不存在,报错退出if (ifile == null){Abort("Could not open file '"+ifilename+"'\n");
}// 采用流式处理方式读取源文件rfile = new StreamReader(ifile); // open up a stream for reading// 根据源文件的名称设定结果输出文件的文件名i = ifilename.LastIndexOf('.');if (i < 0)Abort("Bad filename '"+ifilename+"'");int j = ifilename.LastIndexOf('\\');if (j < 0)j = 0;elsej++;classname = ifilename.Substring(j,i-j);// 根据命令行参数决定是生成.exe、.dll等可执行文件,还是输出包含// IL源码的.lst文件 if (genexe)ofilename = classname+".exe";if (gendll)ofilename = classname+".dll";if (genlist)
{
// 如果是要输出IL源码,因为原来的可执行文件也要输出,需要创建一个新的文件lst_ofilename = classname+".lst";lst_ofile = new FileStream(lst_ofilename, FileMode.Create,FileAccess.Write, FileShare.Write, 8192);if (lst_ofile == null)Abort("Could not open file '"+ofilename+"'\n");lst_wfile = new StreamWriter(lst_ofile);}}

  

编译器是在IO类里处理命令行参数的,参数解析实际上是一些字符串处理的活,本文解释下关键代码:

void ParseArgs(){int i = 1;// 程序至少需要两个参数,否则就输出帮助文字并退出if (args.Length < 2){Abort("myc [/debug] [/nodebug] [/list] [/dll] [/exe] [/outdir:path] filename.myc\n");}// 逐个遍历命令行参数while (true){if (args[i][0] != '/')break;// 处理 /? 这个参数,即输出帮助文本if (args[i].Equals("/?")){Console.WriteLine("Compiler options:\n  myc [/debug] [/nodebug] [/list] [/dll] [/exe] [/outdir:path] filename.myc\n");Environment.Exit(1);}
// 如果有 /debug 参数,则打开内部的 gendebug 开关,这个开关在代码生成的过程
// 中会用到if (args[i].Equals("/debug")){gendebug = true;i++;continue;}
// ... ... 跳过类似的代码
// 如果有 /outdir 参数,则获取命令行中指定的目录路径if (args[i].Length > 8 && args[i].Substring(0,8).Equals("/outdir:")){genpath = args[i].Substring(8);i++;continue;}
// 前面那么多的if相当于switch … case … default 块里面的 case 处理路径
// 下面这段代码即是 default 处理路径 – 如果命令行参数符合前面的if条件
// 都会执行里面的 continue 子句跳出循环,能执行到这里,说明参数
// 是无法识别的参数,因此报告错误并退出执行Abort("Unmatched switch = '"+args[i]+"'\nArguments are:\nmyc [/debug] [/nodebug] [/list] [/dll] [/exe] [/outdir:path] filename.myc\n");}// 如果前面的循环执行完毕,还有参数列表未处理,说明输入了不支持的参数if (args.Length-i != 1){Abort("myc [/debug] [/nodebug] [/list] [/dll] [/exe] [/outdir:path] filename.myc\n");
}// 最后一个参数是要编译的源文件路径ifilename = args[args.Length-1]; // filename is last}

  

IO类中大部分函数都是为Tok.cs服务的,因此其它函数在解释词法分析的时候说明

转载于:https://www.cnblogs.com/vowei/p/4329568.html

MYC编译器源码分析之程序入口相关推荐

  1. MYC编译器源码之词法分析

    前文  .NET框架源码解读之MYC编译器 和 MYC编译器源码分析之程序入口 分别讲解了 SSCLI 里示例编译器的架构和程序入口,本文接着分析它的词法分析部分的代码. 词法解析的工作都由Tok类处 ...

  2. Linux内核源码分析方法—程序员进阶必备

    一.内核源码之我见 Linux内核代码的庞大令不少人"望而生畏",也正因为如此,使得人们对Linux的了解仅处于泛泛的层次.如果想透析Linux,深入操作系统的本质,阅读内核源码是 ...

  3. MYC编译器源码之语法分析

    MyC编译器采用自顶向下的方法进行语法解析,这种语法解析方式,一般是从最左边的Token开始,然后自顶向下看哪一条语法规则可能包含这个Token,如果包含这个Token,则自左向右根据这条语法规则逐一 ...

  4. MYC编译器源码之代码生成

    前面讲过语法的解析之后,代码生成方面就简单很多了.虽然myc是一个简单的示例编译器,但是它还是在解析的过程中生成了一个小的语法树,这个语法树将会用在生成exe可执行文件和il源码的过程中. 编译器在解 ...

  5. Laravel Database——查询构造器与语法编译器源码分析 (上)

    前言 在前两个文章中,我们分析了数据库的连接启动与数据库底层 CRUD 的原理,底层数据库服务支持原生 sql 的运行.本文以 mysql 为例,向大家讲述支持 Fluent 的查询构造器 query ...

  6. java编译器源码分析之语法分析器

    token流到抽象语法树的过程是语法分析. 前面认识到token流,这部分将介绍抽象语法树(AST). 那么什么是抽象语法树(AST)?AST长啥样?我们的token流是如何转变成AST的?下面围绕这 ...

  7. java编译器源码分析之词法分析器

    java编译器是什么? 编译简单理解就是一种高级语言到另一种低级语言的翻译过程:而执行这个过程的主体称为编译器.寻常所说的编译器是指把汇编语言转变成机器语言,也称目标代码,即CPU指令集.汇编语言是一 ...

  8. dolphinscheduler-数据质量-源码分析

    数据质量工作流程 数据质量运行流程分为2个部分:在web端进行数据质量检测的流程定义,通过dolphinscheduer进行调度,提交到spark计算引擎:spark端负责解析数据质量模型的参数,通过 ...

  9. java 线程池 源码_java线程池源码分析

    我们在关闭线程池的时候会使用shutdown()和shutdownNow(),那么问题来了: 这两个方法又什么区别呢? 他们背后的原理是什么呢? 线程池中线程超过了coresize后会怎么操作呢? 为 ...

最新文章

  1. iframe自动调整高度能在IE5里实现吗
  2. 【数据挖掘笔记六】挖掘频繁模式、关联和相关性:基本概念和方法
  3. tomcat web应用_具有可执行Tomcat的独立Web应用程序
  4. scala学习-1-eclipse编写第一个程序unknown scala version problem
  5. Spark 多语言编程的简介(X)
  6. 【Oracle】并行等待之PX Deq Credit: need buffer
  7. 牛客题霸-SQL篇——10~20题
  8. vs2008 sp1安装时候系统盘空间不够问题,解决方式
  9. 编程 100个训练题目
  10. 2019暑假牛客多校赛第九场H.Cutting Bamboos (主席树+二分)
  11. DrawingManager.js___百度地图API
  12. 夏普给鸿海带来哪些改变?
  13. 默哀STAND SILENTLY!
  14. “On Writing Well” 读书总结
  15. 蚂蚁金服资深架构师解析Zeppelin不是飞艇
  16. matplotlib:marker类型/size/空心
  17. linux运行pppd,成功实现Linux下pppd通过GPRS拨号上网
  18. 计算机网络管理员 职业技能鉴定,国家职业技能鉴定·操作技能强化训练:计算机网络管理员(国家职业资格四级)(学生取证专用)...
  19. Spring异步调用传递Request对象问题分析
  20. Visio中如何锁定形状

热门文章

  1. python hashlib_python hashlib模块及md5() 、sha()
  2. c语言 数据结构 list、queue、tree抽象数据类型的定义与实现 详尽代码和注释
  3. k3 审核流程图_K3操作流程图
  4. oracle 本年1月1号 yy,ORACLE 日期函数
  5. 计算机应用基础 辅助教学系统,计算机应用基础课程辅助教学及智能测评系统使用手册——网络版.docx...
  6. 命令行输入mysql不行_MySQL命令行无法插入中文数据
  7. win10 4k分屏 eclipse等工具打开后按钮图标大小问题解决方案
  8. java jbutton 禁用_java-禁用后对jButton执行的操作
  9. matlab 矩阵与向量乘,matlab问题,关于矩阵向量的乘问题
  10. 连接linux桌面命令,连接Linux远程桌面的四个方法