cmm是c的一个子集,保留字只有如下几个
if else while read write int real
特殊符号有如下几个
+ - * / = < == <> ( ) ; { } [ ] /* */
标识符:由数字,字母或下划线组成的字符串,且不能使关键字,第一个字母不能是数字
如果了解c很容易明白上面的是什么意思,也会明白cmm其实有的东西并不多,所以做cmm解释器相对来说比较简单。
上面的特殊符号实际上比较少,我个人实现的时候还对> >= <=等做了相关的支持,当然,原理上都是一样。
简要介绍了cmm之后,就开始进入正题——词法分析。
假设我们有个.cmm文件,我们读取的时候是一个字符一个字符的读取的,也就是字符流,人能准确的判断字符流,但是程序做不到,所以我们需要将字符转换成程序方便处理的形式,也就是Token流,或者说是Token序列。
比如下面这句代码
int a = 10;
我们可以将它转换为 INT ID ASSIGN NUMBER SEMI
INT就是int,ID代表标识符,也就是a,ASSIGN代表赋值运算符,NUMBER代表一个数字,SEMI代表代码末尾的分号。
我们将一句代码解析成这样的Token序列之后,我们就可以很方便的进行进一步的处理了。
那么现在的问题在于我们如何将字符流转换成Token流呢。
有一个东西叫javacc,我们在里面可以通过正则表达式来定义一些Token,然后javacc会根据我们提供的正则表达式来处理输入字符流,转换成Token流,非常强大,有兴趣的东西可以去试一试,我们这里用比较简单的方法,当然也比较笨,那就是我们通过自己的经验总结出来的规律来写一段代码将字符流转换为Token流。
我们先把几种Token定义好:
/** if */
public static final int IF = 1;
/** else */
public static final int ELSE = 2;
/** while */
public static final int WHILE = 3;
/** read */
public static final int READ = 4;
/** write */
public static final int WRITE = 5;
/** int */
public static final int INT = 6;
/** real */
public static final int REAL = 7;
/** + */
public static final int PLUS = 8;
/** - */
public static final int MINUS = 9;
/** * */
public static final int MUL = 10;
/** / */
public static final int DIV = 11;
/** = */
public static final int ASSIGN = 12;
/** < */
public static final int LT = 13;
/** == */
public static final int EQ = 14;
/** <> */
public static final int NEQ = 15;
/** ( */
public static final int LPARENT = 16;
/** ) */
public static final int RPARENT = 17;
public static final int SEMI = 18;
/*