开发环境 Microsoft .NET Framework版本 2.0.50727
Microsoft Visual Studio 2005版本 8.0.50727.4
Microsoft Visual C++ 2005版本77983-009-0000007-41481
Microsoft Visual Studio 2005版本 8.0.50727.4
Microsoft Visual C++ 2005版本77983-009-0000007-41481
1/********************************* scanner.h *********************************/
2
3#ifndef SCANNER_H
4#pragma warning (disable:4996) // 屏蔽4996警告
5#pragma warning (disable:4313) // 屏蔽4313警告
6
7#define SCANNER_H
8
9#include <string.h>
10#include <stdio.h>
11#include <stdlib.h>
12#include <ctype.h>
13#include <stdarg.h>
14#include <math.h>
15
16enum Token_Type /* 记号种类 */
17{
18 ORIGIN, SCALE, ROT, IS, TO, STEP, DRAW, FOR, FROM, // 保留字
19 T, // 参数
20 SEMICO, L_BRACKET, R_BRACKET, COMMA, // 分隔符号
21 PLUS, MINUS, MUL, DIV, POWER, // 运算符
22 FUNC, // 函数
23 CONST_ID, // 常数
24 NONTOKEN, // 空记号
25 ERRTOKEN // 出错记号
26};
27
28typedef double (*MathFuncPtr)(double); /* 函数指针类型 */
29
30struct Token /* 记号与符号表结构 */
31{
32 Token_Type type; // 记号的类别
33 char *lexeme; // 构成记号的字符串
34 double value; // 若为常数,则是常数的值
35 MathFuncPtr FuncPtr; // 若为函数,则是函数的指针
36};
37
38static Token TokenTab[] = { /* 符号表内容 */
39 {CONST_ID, "PI", 3.1415926, 0 },
40 {CONST_ID, "E", 2.71828, 0 },
41 {T, "T", 0.0, 0 },
42 {FUNC, "SIN", 0.0, sin },
43 {FUNC, "COS", 0.0, cos },
44 {FUNC, "TAN", 0.0, tan },
45 {FUNC, "LN", 0.0, log },
46 {FUNC, "EXP", 0.0, exp },
47 {FUNC, "SQRT", 0.0, sqrt},
48 {ORIGIN, "ORIGIN", 0.0, 0 },
49 {SCALE, "SCALE", 0.0, 0 },
50 {ROT, "ROT", 0.0, 0 },
51 {IS, "IS", 0.0, 0 },
52 {FOR, "FOR", 0.0, 0 },
53 {FROM, "FROM", 0.0, 0 },
54 {TO, "TO", 0.0, 0 },
55 {STEP, "STEP", 0.0, 0 },
56 {DRAW, "DRAW", 0.0, 0 }
57};
58
59extern unsigned int LineNo; /* 跟踪记号所在源文件行号 */
60extern int InitScanner(const char *); /* 初始化词法分析器 */
61extern Token GetToken(); /* 获取记号 */
62extern void CloseScanner(); /* 关闭词法分析器 */
63
64#endif
2
3#ifndef SCANNER_H
4#pragma warning (disable:4996) // 屏蔽4996警告
5#pragma warning (disable:4313) // 屏蔽4313警告
6
7#define SCANNER_H
8
9#include <string.h>
10#include <stdio.h>
11#include <stdlib.h>
12#include <ctype.h>
13#include <stdarg.h>
14#include <math.h>
15
16enum Token_Type /* 记号种类 */
17{
18 ORIGIN, SCALE, ROT, IS, TO, STEP, DRAW, FOR, FROM, // 保留字
19 T, // 参数
20 SEMICO, L_BRACKET, R_BRACKET, COMMA, // 分隔符号
21 PLUS, MINUS, MUL, DIV, POWER, // 运算符
22 FUNC, // 函数
23 CONST_ID, // 常数
24 NONTOKEN, // 空记号
25 ERRTOKEN // 出错记号
26};
27
28typedef double (*MathFuncPtr)(double); /* 函数指针类型 */
29
30struct Token /* 记号与符号表结构 */
31{
32 Token_Type type; // 记号的类别
33 char *lexeme; // 构成记号的字符串
34 double value; // 若为常数,则是常数的值
35 MathFuncPtr FuncPtr; // 若为函数,则是函数的指针
36};
37
38static Token TokenTab[] = { /* 符号表内容 */
39 {CONST_ID, "PI", 3.1415926, 0 },
40 {CONST_ID, "E", 2.71828, 0 },
41 {T, "T", 0.0, 0 },
42 {FUNC, "SIN", 0.0, sin },
43 {FUNC, "COS", 0.0, cos },
44 {FUNC, "TAN", 0.0, tan },
45 {FUNC, "LN", 0.0, log },
46 {FUNC, "EXP", 0.0, exp },
47 {FUNC, "SQRT", 0.0, sqrt},
48 {ORIGIN, "ORIGIN", 0.0, 0 },
49 {SCALE, "SCALE", 0.0, 0 },
50 {ROT, "ROT", 0.0, 0 },
51 {IS, "IS", 0.0, 0 },
52 {FOR, "FOR", 0.0, 0 },
53 {FROM, "FROM", 0.0, 0 },
54 {TO, "TO", 0.0, 0 },
55 {STEP, "STEP", 0.0, 0 },
56 {DRAW, "DRAW", 0.0, 0 }
57};
58
59extern unsigned int LineNo; /* 跟踪记号所在源文件行号 */
60extern int InitScanner(const char *); /* 初始化词法分析器 */
61extern Token GetToken(); /* 获取记号 */
62extern void CloseScanner(); /* 关闭词法分析器 */
63
64#endif
1/********************************* scanner.cpp *********************************/
2
3#include "scanner.h"
4
5#define TOKEN_LEN 100 // 记号最大长度
6
7unsigned int LineNo; // 跟踪源文件行号
8static FILE *InFile; // 输入文件流
9static char TokenBuffer[TOKEN_LEN]; // 记号字符缓冲
10
11/* 初始化词法分析器 */
12extern int InitScanner(const char *FileName)
13{
14 LineNo = 1;
15 InFile = fopen(FileName, "r");
16 return ((InFile != 0) ? 1 : 0);
17}
18
19/* 关闭词法分析器 */
20extern void CloseScanner()
21{
22 if(InFile != 0) fclose(InFile);
23}
24
25/* 从输入源程序读入一个字符 */
26static char GetChar()
27{
28 int Char = getc(InFile);
29 return toupper(Char);
30}
31
32/* 把预读的字符退回到输入源程序中 */
33static void BackChar(char Char)
34{
35 if(Char != EOF) ungetc(Char, InFile);
36}
37
38/* 加入字符到记号缓冲区 */
39static void AddCharTokenString(char Char)
40{
41 int TokenLength = (int)strlen(TokenBuffer);
42 if(TokenLength + 1 >= sizeof(TokenBuffer)) return;
43 TokenBuffer[TokenLength] = Char;
44 TokenBuffer[TokenLength + 1] = '\0';
45}
46
47/* 清空记号缓冲区 */
48static void EmptyTokenString()
49{
50 memset(TokenBuffer, 0, TOKEN_LEN);
51}
52
53/* 判断所给的字符串是否在符号表中 */
54static Token JudgeKeyToken(const char *IDString)
55{
56 for(int loop = 0; loop < sizeof(TokenTab) / sizeof(sizeof(TokenTab[0])) / 6; ++loop)
57 /* 注意:需要" / 6",否则 TokenTab 中的元素个数扩大了 6 倍 */
58 {
59 if(strcmp(TokenTab[loop].lexeme, IDString) == 0) return TokenTab[loop];
60 }
61 Token errortoken;
62 memset(&errortoken, 0, sizeof(Token));
63 errortoken.type = ERRTOKEN;
64 return errortoken;
65}
66
67/* 获取一个记号 */
68extern Token GetToken()
69{
70 Token token;
71 int Char;
72
73 memset(&token, 0, sizeof(Token));
74 EmptyTokenString();
75 token.lexeme = TokenBuffer;
76
77 for(;;) // 过滤源程序中的空格、TAB、回车等,遇到文件结束符返回空记号
78 {
79 Char = GetChar();
80 if(Char == EOF)
81 {
82 token.type = NONTOKEN;
83 return token;
84 }
85 if(Char == '\n') LineNo++;
86 if(!isspace(Char)) break;
87 }
88
89 AddCharTokenString(Char); // 若不是空格、TAB、回车、文件结束符等,则先加入到记号的字符缓冲区中
90
91 if(isalpha(Char)) // 若Char是A-Za-z,则一定是函数、关键字、PI、E等
92 {
93 for(;;)
94 {
95 Char = GetChar();
96 if(isalnum(Char)) AddCharTokenString(Char);
97 else break;
98 }
99 BackChar(Char);
100 token = JudgeKeyToken(TokenBuffer);
101 token.lexeme = TokenBuffer;
102 return token;
103 }
104 else if(isdigit(Char)) // 若是一个数字,则一定是常量
105 {
106 for(;;)
107 {
108 Char = GetChar();
109 if(isdigit(Char)) AddCharTokenString(Char);
110 else break;
111 }
112 if(Char == '.')
113 {
114 AddCharTokenString(Char);
115 for(;;)
116 {
117 Char = GetChar();
118 if(isdigit(Char)) AddCharTokenString(Char);
119 else break;
120 }
121 }
122 BackChar(Char);
123 token.type = CONST_ID;
124 token.value = atof(TokenBuffer);
125
126 return token;
127 }
128 else
129 {
130 switch(Char)
131 {
132 case ';' : token.type = SEMICO; break;
133 case '(' : token.type = L_BRACKET; break;
134 case ')' : token.type = R_BRACKET; break;
135 case ',' : token.type = COMMA; break;
136 case '+' : token.type = PLUS; break;
137 case '-' :
138 Char = GetChar();
139 if(Char == '-')
140 {
141 while(Char != '\n' && Char != EOF) Char = GetChar();
142 BackChar(Char);
143 return GetToken();
144 }
145 else
146 {
147 BackChar(Char);
148 token.type = MINUS;
149 break;
150 }
151 case '/' :
152 Char = GetChar();
153 if(Char == '/')
154 {
155 while(Char != '\n' && Char != EOF) Char = GetChar();
156 BackChar(Char);
157 return GetToken();
158 }
159 else
160 {
161 BackChar(Char);
162 token.type = DIV;
163 break;
164 }
165 case '*' :
166 Char = GetChar();
167 if(Char == '*')
168 {
169 token.type = POWER;
170 AddCharTokenString(Char);
171 break;
172 }
173 else
174 {
175 BackChar(Char);
176 token.type = MUL;
177 break;
178 }
179 default : token.type = ERRTOKEN; break;
180 }
181 }
182 return token;
183}
2
3#include "scanner.h"
4
5#define TOKEN_LEN 100 // 记号最大长度
6
7unsigned int LineNo; // 跟踪源文件行号
8static FILE *InFile; // 输入文件流
9static char TokenBuffer[TOKEN_LEN]; // 记号字符缓冲
10
11/* 初始化词法分析器 */
12extern int InitScanner(const char *FileName)
13{
14 LineNo = 1;
15 InFile = fopen(FileName, "r");
16 return ((InFile != 0) ? 1 : 0);
17}
18
19/* 关闭词法分析器 */
20extern void CloseScanner()
21{
22 if(InFile != 0) fclose(InFile);
23}
24
25/* 从输入源程序读入一个字符 */
26static char GetChar()
27{
28 int Char = getc(InFile);
29 return toupper(Char);
30}
31
32/* 把预读的字符退回到输入源程序中 */
33static void BackChar(char Char)
34{
35 if(Char != EOF) ungetc(Char, InFile);
36}
37
38/* 加入字符到记号缓冲区 */
39static void AddCharTokenString(char Char)
40{
41 int TokenLength = (int)strlen(TokenBuffer);
42 if(TokenLength + 1 >= sizeof(TokenBuffer)) return;
43 TokenBuffer[TokenLength] = Char;
44 TokenBuffer[TokenLength + 1] = '\0';
45}
46
47/* 清空记号缓冲区 */
48static void EmptyTokenString()
49{
50 memset(TokenBuffer, 0, TOKEN_LEN);
51}
52
53/* 判断所给的字符串是否在符号表中 */
54static Token JudgeKeyToken(const char *IDString)
55{
56 for(int loop = 0; loop < sizeof(TokenTab) / sizeof(sizeof(TokenTab[0])) / 6; ++loop)
57 /* 注意:需要" / 6",否则 TokenTab 中的元素个数扩大了 6 倍 */
58 {
59 if(strcmp(TokenTab[loop].lexeme, IDString) == 0) return TokenTab[loop];
60 }
61 Token errortoken;
62 memset(&errortoken, 0, sizeof(Token));
63 errortoken.type = ERRTOKEN;
64 return errortoken;
65}
66
67/* 获取一个记号 */
68extern Token GetToken()
69{
70 Token token;
71 int Char;
72
73 memset(&token, 0, sizeof(Token));
74 EmptyTokenString();
75 token.lexeme = TokenBuffer;
76
77 for(;;) // 过滤源程序中的空格、TAB、回车等,遇到文件结束符返回空记号
78 {
79 Char = GetChar();
80 if(Char == EOF)
81 {
82 token.type = NONTOKEN;
83 return token;
84 }
85 if(Char == '\n') LineNo++;
86 if(!isspace(Char)) break;
87 }
88
89 AddCharTokenString(Char); // 若不是空格、TAB、回车、文件结束符等,则先加入到记号的字符缓冲区中
90
91 if(isalpha(Char)) // 若Char是A-Za-z,则一定是函数、关键字、PI、E等
92 {
93 for(;;)
94 {
95 Char = GetChar();
96 if(isalnum(Char)) AddCharTokenString(Char);
97 else break;
98 }
99 BackChar(Char);
100 token = JudgeKeyToken(TokenBuffer);
101 token.lexeme = TokenBuffer;
102 return token;
103 }
104 else if(isdigit(Char)) // 若是一个数字,则一定是常量
105 {
106 for(;;)
107 {
108 Char = GetChar();
109 if(isdigit(Char)) AddCharTokenString(Char);
110 else break;
111 }
112 if(Char == '.')
113 {
114 AddCharTokenString(Char);
115 for(;;)
116 {
117 Char = GetChar();
118 if(isdigit(Char)) AddCharTokenString(Char);
119 else break;
120 }
121 }
122 BackChar(Char);
123 token.type = CONST_ID;
124 token.value = atof(TokenBuffer);
125
126 return token;
127 }
128 else
129 {
130 switch(Char)
131 {
132 case ';' : token.type = SEMICO; break;
133 case '(' : token.type = L_BRACKET; break;
134 case ')' : token.type = R_BRACKET; break;
135 case ',' : token.type = COMMA; break;
136 case '+' : token.type = PLUS; break;
137 case '-' :
138 Char = GetChar();
139 if(Char == '-')
140 {
141 while(Char != '\n' && Char != EOF) Char = GetChar();
142 BackChar(Char);
143 return GetToken();
144 }
145 else
146 {
147 BackChar(Char);
148 token.type = MINUS;
149 break;
150 }
151 case '/' :
152 Char = GetChar();
153 if(Char == '/')
154 {
155 while(Char != '\n' && Char != EOF) Char = GetChar();
156 BackChar(Char);
157 return GetToken();
158 }
159 else
160 {
161 BackChar(Char);
162 token.type = DIV;
163 break;
164 }
165 case '*' :
166 Char = GetChar();
167 if(Char == '*')
168 {
169 token.type = POWER;
170 AddCharTokenString(Char);
171 break;
172 }
173 else
174 {
175 BackChar(Char);
176 token.type = MUL;
177 break;
178 }
179 default : token.type = ERRTOKEN; break;
180 }
181 }
182 return token;
183}
1/********************************* scannermain.cpp *********************************/
2
3#include "scanner.h"
4
5int main(int argc, char *argv[])
6{
7 Token token;
8 if(!InitScanner("test.txt"))
9 {
10 printf("Open Source File Error !\n");
11 return -1;
12 }
13 printf("记号类别 字符串 常数值 函数指针\n");
14 printf("________________________________________________\n");
15 while(1)
16 {
17 token = GetToken();
18 if(token.type != NONTOKEN)
19 printf("%4d, %12s, %12f, %12x\n", token.type, token.lexeme, token.value, token.FuncPtr);
20 else break;
21 };
22 printf("________________________________________________\n");
23 CloseScanner();
24 return 0;
25}
2
3#include "scanner.h"
4
5int main(int argc, char *argv[])
6{
7 Token token;
8 if(!InitScanner("test.txt"))
9 {
10 printf("Open Source File Error !\n");
11 return -1;
12 }
13 printf("记号类别 字符串 常数值 函数指针\n");
14 printf("________________________________________________\n");
15 while(1)
16 {
17 token = GetToken();
18 if(token.type != NONTOKEN)
19 printf("%4d, %12s, %12f, %12x\n", token.type, token.lexeme, token.value, token.FuncPtr);
20 else break;
21 };
22 printf("________________________________________________\n");
23 CloseScanner();
24 return 0;
25}