找回密码
 立即注册
首页 业界区 业界 自己动手开发编译器(五)miniSharp语言的词法分析器 ...

自己动手开发编译器(五)miniSharp语言的词法分析器

荪俗 2025-5-29 15:45:49
多谢各位的一直以来的支持,我们今天总算走到了实践的一步。今天我们要用VBF.Compilers的词法分析库来开发一个小型语言——miniSharp的词法分析。miniSharp是C#语言的子集,miniSharp程序的语义就等于把它当做C#的语义。但是miniSharp只支持很少的语言特性,以降低制作编译器的难度。简单来说miniSharp有如下特征:
<ol> 只有一个源文件,不能引用其他dll(甚至不能引用.NET的类库)。
没有命名空间。
第一个类必须是静态类,而且里面只能定义一个静态方法Main作为程序入口。  
只能定义类,没有枚举、结构体、接口、委托等。  
类的成员只有私有的字段和共有的非静态方法两种。不支持虚方法。  
方法必须有返回值,除了Main方法之外。  
支持的类型只有int、bool、int[]和自定义的类。不支持其他类型。  
仅支持一个库函数System.Console.WriteLine,只支持参数是int的用法。  
只支持if-else语句、while语句、赋值语句、变量声明语句和调用WriteLine语句。  
只支持+、-、*、/、>、 lettersCategories.Contains(Char.GetUnicodeCategory(c))) | RE.Symbol('_');ID = lex.DefineToken(RE_IdChar >>    (RE_IdChar | RE.Range('0', '9')).Many(), "identifier");[/code][/td][/tr][/table] 
大家可以看到我用了.NET类库中的Char.GetUnicodeCategory方法来判断Unicode分类。将来的VBF类库中可能会提供Unicode分类的直接支持。接下来是整型常量和标点符号,没有啥好说的,直接看代码:
 
  1.  
复制代码
 
稍微说明一点,整型常量和上面的标识符的词法,在调用lex.DefineToken时都多传了一个参数。这个参数是可选的描述信息,如果不传会直接使用正则表达式的字符串形式。而标识符的正则表达式有4万多个字符那么长而且没有可读性,所以加一个额外字符串描述一下。它将来会被用于生成编译错误信息。
 
最后我们来写空白符、换行符和注释的正则表达式。这三个是完全按照C# spec的规范编写的。其中注释包含了两种://开头直到换行的注释已经/*开头直到*/的多行注释。大家可以学习一下它们的正则表达式怎么写:
 
  1. var lex = lexicon.DefaultLexer;
  2. //keywords
  3. K_CLASS = lex.DefineToken(RE.Literal("class"));
  4. K_PUBLIC = lex.DefineToken(RE.Literal("public"));
  5. K_STATIC = lex.DefineToken(RE.Literal("static"));
  6. K_VOID = lex.DefineToken(RE.Literal("void"));
  7. K_MAIN = lex.DefineToken(RE.Literal("Main"));
  8. K_STRING = lex.DefineToken(RE.Literal("string"));
  9. K_RETURN = lex.DefineToken(RE.Literal("return"));
  10. K_INT = lex.DefineToken(RE.Literal("int"));
  11. K_BOOL = lex.DefineToken(RE.Literal("bool"));
  12. K_IF = lex.DefineToken(RE.Literal("if"));
  13. K_ELSE = lex.DefineToken(RE.Literal("else"));
  14. K_WHILE = lex.DefineToken(RE.Literal("while"));
  15. K_SYSTEM = lex.DefineToken(RE.Literal("System"));
  16. K_CONSOLE = lex.DefineToken(RE.Literal("Console"));
  17. K_WRITELINE = lex.DefineToken(RE.Literal("WriteLine"));
  18. K_LENGTH = lex.DefineToken(RE.Literal("Length"));
  19. K_TRUE = lex.DefineToken(RE.Literal("true"));
  20. K_FALSE = lex.DefineToken(RE.Literal("false"));
  21. K_THIS = lex.DefineToken(RE.Literal("this"));
  22. K_NEW = lex.DefineToken(RE.Literal("new"));
复制代码
 
最后还有一点后续的代码,从Lexicon对象生成ScannerInfo,再生成Scanner:
 
  1.  
复制代码
 
这样就完成了!我们创建了一个完整的miniSharp词法分析器。现在它就能分析所有miniSharp源代码了。注意我们设定了该词法分析器忽略所有空白符、换行以及注释,是为了后面语法分析简便而考虑的。各位读者可以自己试着任意扩展这个词法分析器,比如增加字符串常量的词法、更多关键字和运算符甚至前所未有的新词法。祝各位实践愉快!下一篇开始我们要进入另一个重要的环节——语法分析部分,敬请期待。
此外别忘了关注我的VBF项目:https://github.com/Ninputer/VBF 和我的微博:http://weibo.com/ninputer 多谢大家支持!

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
您需要登录后才可以回帖 登录 | 立即注册