简单介绍csly
csly是一个编译器前端框架,使用C#开发。 因为本系列只是想带大家简单的介绍一下一个解释器是如何构成的,所以我们使用csly来进行开发以节省时间。 一个解释器首先应该将文本进行解析:比如下面的这个句子:
int a = 1;就可以被解析成: (int)(a)(=)(1)这四个元素。这时就有人觉得很简单,觉得就分割空格就行了,但是事实上我们还有一种可能:
int a=1这也可以被解析。 然后还要将这些元素分类组合成一堆类实例,比如说将上面的赋值语句解析成一个statement类的子类setStatement。 这里就比较麻烦了。而csly就是将这些麻烦的内容包装成一个个api来供我们使用。所以我们只需要完成其他的简单内容就行了。 csly在分析语法这方面提供了一个方法,使用bnf/ebnf来书写语法格式。如:
root:statement*statement: id '=' expr我相信各位或许还不明白这两句话表达着什么,我简单讲一下: 第一句是一个总起:root包含0或多个statement,*的意思就是0或多个; 第二句声明statement的一种可能:形如 \<id\> = \<表达式\>; ## 第一步:编写Token(Lexer) 那么我们现在先进行我们的第一步 根据上面的说法,我们需要先进行解析元素这一步。csly已经帮我们包装好了一个api,我们只需要编写一个枚举类就行。 那么让我们想想应该加入哪些东西,我们来看这个句子:
if(a < 1){return a}我们来解析一下:(if)(a)(<)(1)(return)(a)。有这些东西。我们从这些东西中可以看出有以下几个类别: - 关键字:像if,return这种,属于特殊的标识符 - 标识符:命名变量 - 通用符号:指像 =, !=, <, > 这种符号 - 值:像int,string,double这种,他们有自己的表达方式。 - 注释://或者/* */ 首先我们定义一下关键字(keyword)
[Keyword("if")] IF = 1,
[Keyword("for")] FOR = 2,
[Keyword("while")] WHILE = 3,
[Keyword("def")] DEF = 4,
[Keyword("true")] TRUE = 5,
[Keyword("false")] FALSE = 6,
[Keyword("elif")] ELIF = 7,
[Keyword("else")] ELSE = 8,
[Keyword("return")] RETUEN = 9,
[Keyword("import")] IMPROT = 10,
[Keyword("class")] CLASS = 11,
[Keyword("import")] IMPORT = 12,我们使用修饰器来帮助csly找到相关内容,形如: [Keyword("<关键字>")] <标识符> = <int值> 接下来是标识符和值:
[AlphaNumId] IDENTIFIER = 200,
[String] STRING = 201,
[Int] INT = 202,
[Double] DOUBLE = 203,然后是通用符号:
[Sugar("=")] SET = 100,
[Sugar("==")] EQUALS = 101,
[Sugar("<")] LESSER = 102,
[Sugar(">")] GREATER = 103,
[Sugar("<=")] LESS_EQ = 104,
[Sugar(">=")] GR_EQ = 105,
[Sugar("||")] OR = 106,
[Sugar("&&")] AND = 107,
[Sugar("!")] NOT = 108,
[Sugar("(")] LPAREN = 109,
[Sugar(")")] RPAREN = 110,
[Sugar("[")] L_BRACKET = 111,
[Sugar("]")] R_BRACKET = 112,
[Sugar("!=")] DIFFERENT = 113,
[Sugar(".")] DOT = 114,
[Sugar("+")] PLUS = 115,
[Sugar("-")] MINUS = 116,
[Sugar("*")] TIMES = 117,
[Sugar("/")] DIVIDE = 118,注释:
[Comment("//","/*","*/")] COMMENT = 1000,这里需要注意一下,第一个参数是单行注释符号,第二个是多行注释符号开端,第三个是其结尾。 现在,我们已经定义好了Token这个枚举。 ## 全部代码(Token)
using sly.lexer;namespace LuckyLang;
[Lexer(IndentationAWare = true)]
public enum Lexer{
#region Keyword 1~99
[Keyword("if")] IF = 1,
[Keyword("for")] FOR = 2,
[Keyword("while")] WHILE = 3,
[Keyword("def")] DEF = 4,
[Keyword("true")] TRUE = 5,
[Keyword("false")] FALSE = 6,
[Keyword("elif")] ELIF = 7,
[Keyword("else")] ELSE = 8,
[Keyword("return")] RETUEN = 9,
[Keyword("import")] IMPROT = 10,
[Keyword("class")] CLASS = 11,
[Keyword("import")]IMPORT =12,
#endregion
#region Sugar 100~199
[Sugar("=")] SET = 100,
[Sugar("==")] EQUALS = 101,
[Sugar("<")] LESSER = 102,
[Sugar(">")] GREATER = 103,
[Sugar("<=")] LESS_EQ = 104,
[Sugar(">=")] GR_EQ = 105,
[Sugar("||")] OR = 106,
[Sugar("&&")] AND = 107,
[Sugar("!")] NOT = 108,
[Sugar("(")] LPAREN = 109,
[Sugar(")")] RPAREN = 110,
[Sugar("[")] L_BRACKET = 111,
[Sugar("]")] R_BRACKET = 112,
[Sugar("!=")] DIFFERENT = 113,
[Sugar(".")] DOT = 114,
[Sugar("+")] PLUS = 115,
[Sugar("-")] MINUS = 116,
[Sugar("*")] TIMES = 117,
[Sugar("/")] DIVIDE = 118,
#endregion
#region VA 200~299
[AlphaNumId] IDENTIFIER = 200,
[String] STRING = 201,
[Int] INT = 202,
[Double] DOUBLE = 203,
#endregion
#region Comment
[Comment("//","/*","*/")] COMMENT = 1000,
#endregion
}