考虑分析中用到的Tokentype,由各种值。所有的token取值都在里面了
typedef enum
/* book-keeping tokens */
{ENDFILE,ERROR,
/* reserved words */
IF,THEN,ELSE,END,REPEAT,UNTIL,READ,WRITE,
/* multicharacter tokens 多字符tokens分为两类ID,NUM。比如a=3 a是ID 3是NUM类型的值*/
ID,NUM,
/* special symbols 比如a=3,=就是ASSIGN,操作符*/
ASSIGN,EQ,LT,PLUS,MINUS,TIMES,OVER,LPAREN,RPAREN,SEMI
} TokenType;
一些其他变量:
/* MAXRESERVED = the number of reserved words */
#define MAXRESERVED 8
extern FILE* source; /* source code text file */
extern FILE* listing; /* listing output text file */
extern FILE* code; /* code text file for TM simulator */
extern int lineno; /* source line number for listing */
最后还有for tracing的部分,设置对应变量为True会在解析过程中打印状态信息
词法分析部分:
/* states in scanner DFA */
typedef enum
{ START,INASSIGN,INCOMMENT,INNUM,INID,DONE }
StateType;
既然是状态机,首先要记录状态,StateType就是用来记录状态机的状态,根据当前不同的状态和获取的字符选择下一步操作。图中六个状态正好对应enum的六个值。
这里要注意,每识别一个用空格隔开的单词就重复从START到DONE的步骤。
/* lexeme of identifier or reserved word */
char tokenString[MAXTOKENLEN+1];
应该是识别identifier用
/* index for storing into tokenString */
int tokenStringIndex = 0; #tokenString下标,分析是一个一个字符分析的,总要有个容器(tokenString)临时存放这个半成品的token
/* holds current token to be returned */
TokenType currentToken; #记录当前token的值
/* current state - always begins at START */
StateType state = START; #记录当前状态的值
/* flag to indicate save to tokenString */
int save; #判断当前字符是否记录进tokenString,如果是空白等无意义字符就不记录
图上省略了一些对操作符±<>*的判断,直接在other中没有体现出来。
这些操作符也有单独的token表示
switch (state)
{ case START:
if (isdigit(c))
state = INNUM;
else if (isalpha(c))
state = INID;
else if (c == ':')
state = INASSIGN; #如果是:,就进入赋值状态(赋值语句)比如语句fact := 1;
else if ((c == ' ') || (c == '\t') || (c == '\n'))
save = FALSE;
else if (c == '{')
{ save = FALSE;
state = INCOMMENT;
}
else
{ state = DONE;
switch (c)
{ case EOF:
save = FALSE;
currentToken = ENDFILE;
break;
case '=':
currentToken = EQ;
break;
case '<':
currentToken = LT;
break;
。。。
}
}
break;
当判断出token结束时,执行ungetNextChar函数。
/* ungetNextChar backtracks one character
in lineBuf */
static void ungetNextChar(void)
{ if (!EOF_flag) linepos-- ;}
case INNUM:
if (!isdigit(c))
{ /* backup in the input */
ungetNextChar(); #理论上来说数字必须是全部是digit,一旦出现不是数字了,就默认该token已经结束。这时这个字符就要unget一下。
save = FALSE;
state = DONE;
currentToken = NUM;
}
break;
符号表:
记录了这些信息
fprintf(listing,"Variable Name Location Line Numbers\n");
fprintf(listing,"------------- -------- ------------\n");