java词法解释器_编译原理-实现一个函数绘图语言的解释器(1)实现词法分析器...

要实现一个解释器,主要要经过三个步骤,分别是构造:

1、词法分析器:用于识别一条语句中的关键词是否符合预先定义的规则。

2、语法分析器:用来确定一条语句是否满足语法规则。

3、解释器:用来确定满足语法规则的句子,在意思上是否符合要求。

程序的主要架构是:

1、词法分析器:scanner.h scanner.cpp

2、语法分析器:parser.h parser.cpp

3、解释器:semantic.h semantic.cpp main.cpp

首先介绍一下函数绘图语言:

6741c3a3a4a13a144ae0740b1d3fe7ee.png

函数绘图源程序举例:

94b81e47da14e0f836b49b851d5a462c.png

画出的图形举例:

a31a6ea62f5e72cd463f8e3a98923f7d.png

下面给出词法分析器的源码:

scanner.h:

1 #ifndef SCANNER_H2 #define SCANNER_H

3

4 #include

5 #include

6 #include

7 #include

8 #include

9 #include

10

11 enum Token_Type //记号种类

12 {13 ORIGIN, SCALE, ROT, IS, TO, //保留字

14 STEP, DRAW, FOR, FROM, //保留字

15 T, //参数

16 SEMICO, L_BRACKET, R_BRACKET, COMMA, //分隔符号

17 PLUS, MINUS, MUL, DIV, POWER, //运算符

18 FUNC, //函数

19 CONST_ID, //常数

20 NONTOKEN, //空记号

21 ERRTOKEN //出错记号

22 };23

24 typedef double(*MathFuncPtr)(double);25

26 struct Token //记号与符号表结构

27 {28 Token_Type type; //记号的类型

29 char *lexeme; //构成记号的字符串

30 double value; //若为常数,则是常数的值

31 double(*FuncPtr)(double); //若为函数,则是函数的指针

32 };33

34 static Token TokenTab[] = //符号表内容

35 {36 { CONST_ID,"PI",3.1415926,NULL },37 { CONST_ID,"E",2.71828,NULL },38 { T,"T",0.0,NULL },39 { FUNC,"SIN",0.0,sin },40 { FUNC,"COS",0.0,cos },41 { FUNC,"TAN",0.0,tan },42 { FUNC,"LN",0.0,log },43 { FUNC,"EXP",0.0,exp },44 { FUNC,"SQRT",0.0,sqrt },45 { ORIGIN,"ORIGIN",0.0,NULL },46 { SCALE,"SCALE",0.0,NULL },47 { ROT,"ROT",0.0,NULL },48 { IS,"IS",0.0,NULL },49 { FOR,"FOR",0.0,NULL },50 { FROM,"FROM",0.0,NULL },51 { TO,"TO",0.0,NULL },52 { STEP,"STEP",0.0,NULL },53 { DRAW,"DRAW",0.0,NULL },54 };55 //extern 表示变量或者函数的定义在别的函数中

56 extern unsigned int LineNo; //跟踪记号所在源文件行号

57 extern int InitScanner(const char*); //初始化词法分析器

58 extern Token GetToken(void); //获取记号函数

59 extern void CloseScanner(void); //关闭词法分析器

60

61 #endif //SCANNER_H

scanner.cpp:

1 #include "scanner.h"

2

3 #define TOKEN_LEN 100 //记号最大长度

4

5 unsigned int LineNo; //跟踪源文件行号6 //static FILE *InFile;//输入文件流

7 static char TokenBuffer[TOKEN_LEN]; //记号字符缓冲

8 FILE*pFile;9 errno_t err = 0; //用来记录文件是否打开成功10 //初始化词法分析器

11 extern int InitScanner(const char *FileName)//如果成功打开文件,则返回值1

12 {13 LineNo = 1;14 err = fopen_s(&pFile, FileName, "r");15 if (err == 0) return 1;16 else return 0;17 }18

19 //关闭词法分析器

20 extern void CloseScanner(void)21 {22 if (err == 0) fclose(pFile);23 }24

25 //从输入源程序中读入一个字符

26 static char GetChar(void)27 {28 int Char =getc(pFile);29 return toupper(Char); //将Char变成大写字母

30 }31

32 //把预读的字符退回到输入源程序中

33 static void BackChar(charChar)34 {35 if (Char !=EOF) ungetc(Char, pFile);36 }37

38 //加入字符到记号缓冲区

39 static void AddCharTokenString(charChar)40 {41 int TokenLength =strlen(TokenBuffer);42 if (TokenLength + 1 >= sizeof(TokenBuffer)) return;//发生数组越界

43 TokenBuffer[TokenLength] =Char;44 TokenBuffer[TokenLength + 1] = '\0';//字符串以'\0'结尾,c语言的字符串都是以/0来结尾的

45 }46

47 //清空记号缓冲区

48 static voidEmptyTokenString()49 {50 memset(TokenBuffer, 0, TOKEN_LEN);51 }52

53 //判断所给的字符串是否在符号表中

54 static Token JudgeKeyToken(const char *IDString)55 {56 int loop; //sizeof(TokenTab)L:表示这个数组一共占了多少字节数;sizeof(TokenTab[0]):表示一个元素所占的字节数,57 //两者相除,表述数组中一共有多少个元素

58 for (loop = 0; loop

59 {60 //遍历TokenTab表

61 if (strcmp(TokenTab[loop].lexeme, IDString) == 0) return TokenTab[loop]; //判断所给的字符与TokenTab中的所有项,是否存在匹配

62 }63 Token errortoken;64 memset(&errortoken, 0, sizeof(Token));65 errortoken.type =ERRTOKEN;66 returnerrortoken;67 }68

69 //获取一个记号

70 extern Token GetToken(void)71 {72 Token token;73 intChar;74

75 memset(&token, 0, sizeof(Token));76 EmptyTokenString();77 token.lexeme =TokenBuffer;78 for (;;) //过滤源程序中的空格、TAB、回车等,遇到文件结束符返回空记号

79 {80 Char =GetChar();81 if (Char ==EOF)82 {83 token.type =NONTOKEN;84 returntoken;85 }86 if (Char == '\n') LineNo++;87 if (!isspace(Char)) break;//是空白字符,返回非0值 如果Char不是空白字符,跳出for循环

88 }89 AddCharTokenString(Char);90

91 //若不是空格、TAB、回车、文件结束符等,则先加入到记号的字符缓冲区中

92 if (isalpha(Char)) //判断Char是不是英文字母//若char是A-Za-z,则一定是函数、关键字、PI、E等。

93 {94 for(;;)95 {96 Char =GetChar();97 if (isalnum(Char)) //判断字符变量Char是否为字母或者数字,是则返回非0,否则返回0;

98 AddCharTokenString(Char); //Char是字母或者数字

99 else break;100 }101 BackChar(Char);102 token =JudgeKeyToken(TokenBuffer);103 token.lexeme =TokenBuffer;104 returntoken;105 }106 else if (isdigit(Char)) //若是一个数字,则一定是常量

107 {108 for(;;)109 {110 Char =GetChar();111 if(isdigit(Char)) AddCharTokenString(Char);112 else break;113 }114 if (Char == '.')115 {116 AddCharTokenString(Char);117 for(;;)118 {119 Char =GetChar();120 if(isdigit(Char)) AddCharTokenString(Char);121 else break;122 }123 }124 BackChar(Char); //把预读的字符退回到输入源程序中

125 token.type =CONST_ID;126 token.value = atof(TokenBuffer); //把字符串转换成浮点数

127 returntoken;128 }129 else //不是字母和数字,则一定是运算符或分隔符

130 {131 switch(Char)132 {133 case ';':token.type = SEMICO; break;134 case '(':token.type = L_BRACKET; break;135 case ')':token.type = R_BRACKET; break;136 case ',':token.type = COMMA; break;137 case '+':token.type = PLUS; break;138 case '-':139 Char =GetChar();140 if (Char == '-')141 {142 while (Char != '\n' && Char != EOF) Char =GetChar();143 BackChar(Char);144 returnGetToken();145 }146 else

147 {148 BackChar(Char);149 token.type =MINUS;150 break;151 }152 case '/':153 Char =GetChar();154 if (Char == '/')155 {156 while (Char != '\n' && Char != EOF) Char =GetChar();157 BackChar(Char);158 returnGetToken();159 }160 else

161 {162 BackChar(Char);163 token.type =DIV;164 break;165 }166 case '*':167 Char =GetChar();168 if (Char == '*')169 {170 token.type =POWER;171 break;172 }173 else

174 {175 BackChar(Char);176 token.type =MUL;177 break;178 }179 default:180 token.type =ERRTOKEN;181 break;182 }//end of switch

183 }//end of else(不是字母和数字,则一定是符号)

184 returntoken;185 }//end of GetToken

scannermain.cpp 测试主程序:(在最后构造解释器的时候,不需要,主要作用是用来测试词法分析器的正常运行)

#include "scanner.h"

int main(int argc, char *argv[])

{

Token token;if(argc < 2)

{

printf("please input Source File !\n"); return 0;

}if(!InitScanner(argv[1]))

{

printf("Open Source File Error!\n"); return 0;

}

printf("记号类型 字符串 常数值 函数指针\n");

printf("------------------------------------------\n");while(1)

{

token=GetToken();if(token.type !=NONTOKEN)

printf("%4d,%12s,%12f,%12x\n",token.type, token.lexeme, token.value, token.FuncPtr);else break;

}

printf("------------------------------------------\n");

CloseScanner();

}

环境说明:在单独测试词法分析器的时候,要进入到scanner生成的可执行文件的目录下,通过windows的控制台,执行scanner的可执行文件,加上函数绘图语言的源程序文件来测试。

如: scanner.exe   test.txt

测试结果:

7bcc12b979e9d45b2a698b57d77c404f.png

97a91dbc1a76781ac433862f0727209e.png

至此,成功构造该解释器的词法分析器。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值