词法扫描器 c c++
发布网友
发布时间:2022-04-24 01:57
我来回答
共1个回答
热心网友
时间:2023-10-20 09:15
类似的词法分析器,你可以在这基础上加上一些功能。mlex.c内容如下:#include <stdio.h>#include <stdlib.h>#include <string.h>#include <conio.h>#include <assert.h>#include "lex.h"
char strToken[30]; //字符数组,存放构成单词符号的字符串。int lvalue; //单词的内码值keyword keywords[]={"switch",$SWITCH,"case",$CASE,"if",$IF,"else",$ELSE,"do",$DO,"while",$WHILE,"stop",$STOP,"end",$END,"var",$VAR,"dim",$DIM,"char",$CHAR,0,0,}; //关键字表symbol ctable[200]; //常数表symbol vtable[200]; //符号表(标识符)char inbuf[300]; //扫描缓冲区int sp; //起点指示器int ep; //扫描指示器int lineno; //行计数器FILE *fsrc;
char GetChar(){//从扫描缓冲区第一个缓冲区从inbuf中读一个字符,实现双输入缓冲。//[0]到inbuf[149],第二个缓冲区从inbuf[150]到inbuf[299],//每次从源文件读一个缓冲区大小的内容,分析完当前工作缓冲区内容时把源文件读入//另一个缓冲区,另一个缓冲区成为工作缓冲区int i = 0;char ch;if ((ep == 150)||(ep == 300)){ep = ep%300;while (((inbuf[i+ep]=fgetc(fsrc))!=NULL) && (i<150))i++;}ch = inbuf[ep];ep++;return ch;}char GetBC(){//从扫描缓冲区读字符,过滤空格、制表和回车符号char ch = GetChar();while ((ch==' ') || (ch=='\n') || (ch=='\t')){if (ch=='\n')lineno++;ch = GetChar();}return ch;}void Concat(char str[], char ch){//将字符ch添加到符号串str的尾部str[strlen(str)] = ch;}bool isLetter(char ch){//判断ch是否字母if (((ch>='A')&&(ch<='Z')) || ((ch>='a')&&(ch<='z')))return true;return false;}bool isDigit(char ch){//判断ch是否数字if ((ch>='0')&&(ch<='9'))return true;return false;}
int Reserve(char* str){//如str是保留字,返回保留字种别号//否则返回0int i = 0;while (keywords[i].code != 0){if (strcmp(str,keywords[i].name) == 0)return keywords[i].code;i++;}return 0;}void Retract(){//从扫描输入缓冲区回退一个字符if (ep==0)ep = 299;elseep--;}
int InsertID(char *str){//如符号表中已有str标识符,返回记录号,//否则将str加到符号表中,返回记录号int i = 0;while ((vtable[i].number!=0) && (i<200)){if (strcmp(str,vtable[i].name) == 0)return vtable[i].number;i++;}if (i<200){vtable[i].number = i+1;strcpy(vtable[i].name, str);return vtable[i].number;}return 0;}int InsertConst(char *str){//如常数表中已有str常数,返回记录号,//否则将str加到常数表中,返回记录号int i = 0;while ((ctable[i].number!=0) && (i<200)){if (strcmp(str,ctable[i].name) == 0)return ctable[i].number;i++;}if (i<200){ctable[i].number = i+1;strcpy(ctable[i].name, str);return ctable[i].number;}return 0;}void ProcError(){printf("%i 行有错误\n", lineno);}int Lex(){//从扫描缓冲区中识别出一个单词,返回单词种别号,//构成的单词的符号串保留在strToken中,//单词的值保留在lvalue中。strToken和lvalue为全局变量。int code;char ch;
memset(strToken, 0, 30);ch = GetBC();sp = ep-1;lvalue = 0;if (isLetter(ch)){while (isLetter(ch) || isDigit(ch)){Concat(strToken, ch);ch = GetChar();}Retract();code = Reserve(strToken);if (code == 0){lvalue = InsertID(strToken);return $ID;}return code;}else if (isDigit(ch)){while (isDigit(ch)){Concat(strToken, ch);ch = GetChar();} if (ch == '.' ) { Concat(strToken, ch); if(!isDigit(GetChar())) {ProcError(); return $END;} Retract(); while(isDigit(GetChar())) { Retract(); Concat(strToken,GetChar()); Retract(); GetChar(); } InsertConst(strToken); return $FLOAT; }Retract();lvalue = InsertConst(strToken);return $INT;}
else if (ch == '='){ch = GetChar();if (ch == '=') return $EQ;Retract();return $ASSIGN;}else if (ch == '+') return $PLUS;else if (ch == ';') return $SEMICOLON;else if (ch == '(') return $LPAR;else if (ch == ')') return $RPAR;else if (ch == '{') return $LBRACE;else if (ch == '}') return $RBRACE;
else if (ch == '*') {ch = GetChar();if (ch == '*') return $POWER;Retract();return $STAR;}else if (ch == EOF) return $END; else{ProcError();return $END;}}void main(){token aToken;int i = 0;char strName[256];FILE *fcon = fopen("const.txt","w+");FILE *ftoken = fopen("token.txt","w+");FILE *fsym = fopen("symbol.txt","w+");printf("请输入源文件名(enter结束):\n");scanf("%s",strName);fsrc = fopen(strName,"r");if (fsrc == NULL){printf("找不到源文件src.txt\n");exit(1);}if ((ftoken == NULL) || (fcon == NULL) || \(fsym == NULL)){printf("不能创建输出文件const.txt,token.txt,symbol.txt\n");exit(1);}/*读源文件入缓冲区*/while ((i<150) && ((inbuf[i]=fgetc(fsrc)) != EOF))i++;
/*词法分析开始*/ep = 0;lineno = 1;aToken.label = 0;aToken.code = Lex();aToken.addr = lvalue;printf("单词序列:\n");while (aToken.code != $END){//单词输出到文件fprintf(ftoken, "(%3d,%3d)", aToken.code, aToken.addr);//单词输出到屏幕printf("(%3d,%3d) ", aToken.code, aToken.addr);aToken.label++;aToken.code = Lex();aToken.addr = lvalue;}/*词法分析结束,输出符号表和常数表到symbol.txt、const.txt文件并显示在屏幕*/i = 0;printf("\n符号表:\n");while (vtable[i].number != 0){fprintf(fsym, "(%3d,%s)", vtable[i].number, vtable[i].name);printf("(%3d,%s)", vtable[i].number, vtable[i].name);i++;}i = 0;printf("\n常数表:\n");while (ctable[i].number != 0){fprintf(fcon, "(%3d,%s)", ctable[i].number, ctable[i].name);printf("(%3d,%s)", ctable[i].number, ctable[i].name);i++;}fclose(fsrc);fclose(fsym);fclose(fcon);fclose(ftoken);printf("\n词法分析结束,按任意键\n");getch();}
lex.h头文件内容如下:typedef struct token{int label;char name[30];//组成单词的字符串int code;int addr;}token;
typedef struct symbol{int number;char name[30];//组成标识符或常数的字符串} symbol;
typedef struct keyword{char name[30]; //组成关键字的字符串int code;} keyword;
//定义一些常量enum TVAL {$WHILE=1,$IF,$ELSE,$SWITCH,$CASE,$DO,$STOP,$END,$ID,$INT,$EQ,$ASSIGN,$PLUS, \$STAR,$POWER,$COMMA,$LPAR,$RPAR,$SEMICOLON,$LBRACE, \$RBRACE,$VAR,$DIM,$FLOAT,$CHAR};
热心网友
时间:2023-10-20 09:15
类似的词法分析器,你可以在这基础上加上一些功能。mlex.c内容如下:#include <stdio.h>#include <stdlib.h>#include <string.h>#include <conio.h>#include <assert.h>#include "lex.h"
char strToken[30]; //字符数组,存放构成单词符号的字符串。int lvalue; //单词的内码值keyword keywords[]={"switch",$SWITCH,"case",$CASE,"if",$IF,"else",$ELSE,"do",$DO,"while",$WHILE,"stop",$STOP,"end",$END,"var",$VAR,"dim",$DIM,"char",$CHAR,0,0,}; //关键字表symbol ctable[200]; //常数表symbol vtable[200]; //符号表(标识符)char inbuf[300]; //扫描缓冲区int sp; //起点指示器int ep; //扫描指示器int lineno; //行计数器FILE *fsrc;
char GetChar(){//从扫描缓冲区第一个缓冲区从inbuf中读一个字符,实现双输入缓冲。//[0]到inbuf[149],第二个缓冲区从inbuf[150]到inbuf[299],//每次从源文件读一个缓冲区大小的内容,分析完当前工作缓冲区内容时把源文件读入//另一个缓冲区,另一个缓冲区成为工作缓冲区int i = 0;char ch;if ((ep == 150)||(ep == 300)){ep = ep%300;while (((inbuf[i+ep]=fgetc(fsrc))!=NULL) && (i<150))i++;}ch = inbuf[ep];ep++;return ch;}char GetBC(){//从扫描缓冲区读字符,过滤空格、制表和回车符号char ch = GetChar();while ((ch==' ') || (ch=='\n') || (ch=='\t')){if (ch=='\n')lineno++;ch = GetChar();}return ch;}void Concat(char str[], char ch){//将字符ch添加到符号串str的尾部str[strlen(str)] = ch;}bool isLetter(char ch){//判断ch是否字母if (((ch>='A')&&(ch<='Z')) || ((ch>='a')&&(ch<='z')))return true;return false;}bool isDigit(char ch){//判断ch是否数字if ((ch>='0')&&(ch<='9'))return true;return false;}
int Reserve(char* str){//如str是保留字,返回保留字种别号//否则返回0int i = 0;while (keywords[i].code != 0){if (strcmp(str,keywords[i].name) == 0)return keywords[i].code;i++;}return 0;}void Retract(){//从扫描输入缓冲区回退一个字符if (ep==0)ep = 299;elseep--;}
int InsertID(char *str){//如符号表中已有str标识符,返回记录号,//否则将str加到符号表中,返回记录号int i = 0;while ((vtable[i].number!=0) && (i<200)){if (strcmp(str,vtable[i].name) == 0)return vtable[i].number;i++;}if (i<200){vtable[i].number = i+1;strcpy(vtable[i].name, str);return vtable[i].number;}return 0;}int InsertConst(char *str){//如常数表中已有str常数,返回记录号,//否则将str加到常数表中,返回记录号int i = 0;while ((ctable[i].number!=0) && (i<200)){if (strcmp(str,ctable[i].name) == 0)return ctable[i].number;i++;}if (i<200){ctable[i].number = i+1;strcpy(ctable[i].name, str);return ctable[i].number;}return 0;}void ProcError(){printf("%i 行有错误\n", lineno);}int Lex(){//从扫描缓冲区中识别出一个单词,返回单词种别号,//构成的单词的符号串保留在strToken中,//单词的值保留在lvalue中。strToken和lvalue为全局变量。int code;char ch;
memset(strToken, 0, 30);ch = GetBC();sp = ep-1;lvalue = 0;if (isLetter(ch)){while (isLetter(ch) || isDigit(ch)){Concat(strToken, ch);ch = GetChar();}Retract();code = Reserve(strToken);if (code == 0){lvalue = InsertID(strToken);return $ID;}return code;}else if (isDigit(ch)){while (isDigit(ch)){Concat(strToken, ch);ch = GetChar();} if (ch == '.' ) { Concat(strToken, ch); if(!isDigit(GetChar())) {ProcError(); return $END;} Retract(); while(isDigit(GetChar())) { Retract(); Concat(strToken,GetChar()); Retract(); GetChar(); } InsertConst(strToken); return $FLOAT; }Retract();lvalue = InsertConst(strToken);return $INT;}
else if (ch == '='){ch = GetChar();if (ch == '=') return $EQ;Retract();return $ASSIGN;}else if (ch == '+') return $PLUS;else if (ch == ';') return $SEMICOLON;else if (ch == '(') return $LPAR;else if (ch == ')') return $RPAR;else if (ch == '{') return $LBRACE;else if (ch == '}') return $RBRACE;
else if (ch == '*') {ch = GetChar();if (ch == '*') return $POWER;Retract();return $STAR;}else if (ch == EOF) return $END; else{ProcError();return $END;}}void main(){token aToken;int i = 0;char strName[256];FILE *fcon = fopen("const.txt","w+");FILE *ftoken = fopen("token.txt","w+");FILE *fsym = fopen("symbol.txt","w+");printf("请输入源文件名(enter结束):\n");scanf("%s",strName);fsrc = fopen(strName,"r");if (fsrc == NULL){printf("找不到源文件src.txt\n");exit(1);}if ((ftoken == NULL) || (fcon == NULL) || \(fsym == NULL)){printf("不能创建输出文件const.txt,token.txt,symbol.txt\n");exit(1);}/*读源文件入缓冲区*/while ((i<150) && ((inbuf[i]=fgetc(fsrc)) != EOF))i++;
/*词法分析开始*/ep = 0;lineno = 1;aToken.label = 0;aToken.code = Lex();aToken.addr = lvalue;printf("单词序列:\n");while (aToken.code != $END){//单词输出到文件fprintf(ftoken, "(%3d,%3d)", aToken.code, aToken.addr);//单词输出到屏幕printf("(%3d,%3d) ", aToken.code, aToken.addr);aToken.label++;aToken.code = Lex();aToken.addr = lvalue;}/*词法分析结束,输出符号表和常数表到symbol.txt、const.txt文件并显示在屏幕*/i = 0;printf("\n符号表:\n");while (vtable[i].number != 0){fprintf(fsym, "(%3d,%s)", vtable[i].number, vtable[i].name);printf("(%3d,%s)", vtable[i].number, vtable[i].name);i++;}i = 0;printf("\n常数表:\n");while (ctable[i].number != 0){fprintf(fcon, "(%3d,%s)", ctable[i].number, ctable[i].name);printf("(%3d,%s)", ctable[i].number, ctable[i].name);i++;}fclose(fsrc);fclose(fsym);fclose(fcon);fclose(ftoken);printf("\n词法分析结束,按任意键\n");getch();}
lex.h头文件内容如下:typedef struct token{int label;char name[30];//组成单词的字符串int code;int addr;}token;
typedef struct symbol{int number;char name[30];//组成标识符或常数的字符串} symbol;
typedef struct keyword{char name[30]; //组成关键字的字符串int code;} keyword;
//定义一些常量enum TVAL {$WHILE=1,$IF,$ELSE,$SWITCH,$CASE,$DO,$STOP,$END,$ID,$INT,$EQ,$ASSIGN,$PLUS, \$STAR,$POWER,$COMMA,$LPAR,$RPAR,$SEMICOLON,$LBRACE, \$RBRACE,$VAR,$DIM,$FLOAT,$CHAR};
热心网友
时间:2023-10-20 09:15
类似的词法分析器,你可以在这基础上加上一些功能。mlex.c内容如下:#include <stdio.h>#include <stdlib.h>#include <string.h>#include <conio.h>#include <assert.h>#include "lex.h"
char strToken[30]; //字符数组,存放构成单词符号的字符串。int lvalue; //单词的内码值keyword keywords[]={"switch",$SWITCH,"case",$CASE,"if",$IF,"else",$ELSE,"do",$DO,"while",$WHILE,"stop",$STOP,"end",$END,"var",$VAR,"dim",$DIM,"char",$CHAR,0,0,}; //关键字表symbol ctable[200]; //常数表symbol vtable[200]; //符号表(标识符)char inbuf[300]; //扫描缓冲区int sp; //起点指示器int ep; //扫描指示器int lineno; //行计数器FILE *fsrc;
char GetChar(){//从扫描缓冲区第一个缓冲区从inbuf中读一个字符,实现双输入缓冲。//[0]到inbuf[149],第二个缓冲区从inbuf[150]到inbuf[299],//每次从源文件读一个缓冲区大小的内容,分析完当前工作缓冲区内容时把源文件读入//另一个缓冲区,另一个缓冲区成为工作缓冲区int i = 0;char ch;if ((ep == 150)||(ep == 300)){ep = ep%300;while (((inbuf[i+ep]=fgetc(fsrc))!=NULL) && (i<150))i++;}ch = inbuf[ep];ep++;return ch;}char GetBC(){//从扫描缓冲区读字符,过滤空格、制表和回车符号char ch = GetChar();while ((ch==' ') || (ch=='\n') || (ch=='\t')){if (ch=='\n')lineno++;ch = GetChar();}return ch;}void Concat(char str[], char ch){//将字符ch添加到符号串str的尾部str[strlen(str)] = ch;}bool isLetter(char ch){//判断ch是否字母if (((ch>='A')&&(ch<='Z')) || ((ch>='a')&&(ch<='z')))return true;return false;}bool isDigit(char ch){//判断ch是否数字if ((ch>='0')&&(ch<='9'))return true;return false;}
int Reserve(char* str){//如str是保留字,返回保留字种别号//否则返回0int i = 0;while (keywords[i].code != 0){if (strcmp(str,keywords[i].name) == 0)return keywords[i].code;i++;}return 0;}void Retract(){//从扫描输入缓冲区回退一个字符if (ep==0)ep = 299;elseep--;}
int InsertID(char *str){//如符号表中已有str标识符,返回记录号,//否则将str加到符号表中,返回记录号int i = 0;while ((vtable[i].number!=0) && (i<200)){if (strcmp(str,vtable[i].name) == 0)return vtable[i].number;i++;}if (i<200){vtable[i].number = i+1;strcpy(vtable[i].name, str);return vtable[i].number;}return 0;}int InsertConst(char *str){//如常数表中已有str常数,返回记录号,//否则将str加到常数表中,返回记录号int i = 0;while ((ctable[i].number!=0) && (i<200)){if (strcmp(str,ctable[i].name) == 0)return ctable[i].number;i++;}if (i<200){ctable[i].number = i+1;strcpy(ctable[i].name, str);return ctable[i].number;}return 0;}void ProcError(){printf("%i 行有错误\n", lineno);}int Lex(){//从扫描缓冲区中识别出一个单词,返回单词种别号,//构成的单词的符号串保留在strToken中,//单词的值保留在lvalue中。strToken和lvalue为全局变量。int code;char ch;
memset(strToken, 0, 30);ch = GetBC();sp = ep-1;lvalue = 0;if (isLetter(ch)){while (isLetter(ch) || isDigit(ch)){Concat(strToken, ch);ch = GetChar();}Retract();code = Reserve(strToken);if (code == 0){lvalue = InsertID(strToken);return $ID;}return code;}else if (isDigit(ch)){while (isDigit(ch)){Concat(strToken, ch);ch = GetChar();} if (ch == '.' ) { Concat(strToken, ch); if(!isDigit(GetChar())) {ProcError(); return $END;} Retract(); while(isDigit(GetChar())) { Retract(); Concat(strToken,GetChar()); Retract(); GetChar(); } InsertConst(strToken); return $FLOAT; }Retract();lvalue = InsertConst(strToken);return $INT;}
else if (ch == '='){ch = GetChar();if (ch == '=') return $EQ;Retract();return $ASSIGN;}else if (ch == '+') return $PLUS;else if (ch == ';') return $SEMICOLON;else if (ch == '(') return $LPAR;else if (ch == ')') return $RPAR;else if (ch == '{') return $LBRACE;else if (ch == '}') return $RBRACE;
else if (ch == '*') {ch = GetChar();if (ch == '*') return $POWER;Retract();return $STAR;}else if (ch == EOF) return $END; else{ProcError();return $END;}}void main(){token aToken;int i = 0;char strName[256];FILE *fcon = fopen("const.txt","w+");FILE *ftoken = fopen("token.txt","w+");FILE *fsym = fopen("symbol.txt","w+");printf("请输入源文件名(enter结束):\n");scanf("%s",strName);fsrc = fopen(strName,"r");if (fsrc == NULL){printf("找不到源文件src.txt\n");exit(1);}if ((ftoken == NULL) || (fcon == NULL) || \(fsym == NULL)){printf("不能创建输出文件const.txt,token.txt,symbol.txt\n");exit(1);}/*读源文件入缓冲区*/while ((i<150) && ((inbuf[i]=fgetc(fsrc)) != EOF))i++;
/*词法分析开始*/ep = 0;lineno = 1;aToken.label = 0;aToken.code = Lex();aToken.addr = lvalue;printf("单词序列:\n");while (aToken.code != $END){//单词输出到文件fprintf(ftoken, "(%3d,%3d)", aToken.code, aToken.addr);//单词输出到屏幕printf("(%3d,%3d) ", aToken.code, aToken.addr);aToken.label++;aToken.code = Lex();aToken.addr = lvalue;}/*词法分析结束,输出符号表和常数表到symbol.txt、const.txt文件并显示在屏幕*/i = 0;printf("\n符号表:\n");while (vtable[i].number != 0){fprintf(fsym, "(%3d,%s)", vtable[i].number, vtable[i].name);printf("(%3d,%s)", vtable[i].number, vtable[i].name);i++;}i = 0;printf("\n常数表:\n");while (ctable[i].number != 0){fprintf(fcon, "(%3d,%s)", ctable[i].number, ctable[i].name);printf("(%3d,%s)", ctable[i].number, ctable[i].name);i++;}fclose(fsrc);fclose(fsym);fclose(fcon);fclose(ftoken);printf("\n词法分析结束,按任意键\n");getch();}
lex.h头文件内容如下:typedef struct token{int label;char name[30];//组成单词的字符串int code;int addr;}token;
typedef struct symbol{int number;char name[30];//组成标识符或常数的字符串} symbol;
typedef struct keyword{char name[30]; //组成关键字的字符串int code;} keyword;
//定义一些常量enum TVAL {$WHILE=1,$IF,$ELSE,$SWITCH,$CASE,$DO,$STOP,$END,$ID,$INT,$EQ,$ASSIGN,$PLUS, \$STAR,$POWER,$COMMA,$LPAR,$RPAR,$SEMICOLON,$LBRACE, \$RBRACE,$VAR,$DIM,$FLOAT,$CHAR};
热心网友
时间:2023-10-20 09:15
类似的词法分析器,你可以在这基础上加上一些功能。mlex.c内容如下:#include <stdio.h>#include <stdlib.h>#include <string.h>#include <conio.h>#include <assert.h>#include "lex.h"
char strToken[30]; //字符数组,存放构成单词符号的字符串。int lvalue; //单词的内码值keyword keywords[]={"switch",$SWITCH,"case",$CASE,"if",$IF,"else",$ELSE,"do",$DO,"while",$WHILE,"stop",$STOP,"end",$END,"var",$VAR,"dim",$DIM,"char",$CHAR,0,0,}; //关键字表symbol ctable[200]; //常数表symbol vtable[200]; //符号表(标识符)char inbuf[300]; //扫描缓冲区int sp; //起点指示器int ep; //扫描指示器int lineno; //行计数器FILE *fsrc;
char GetChar(){//从扫描缓冲区第一个缓冲区从inbuf中读一个字符,实现双输入缓冲。//[0]到inbuf[149],第二个缓冲区从inbuf[150]到inbuf[299],//每次从源文件读一个缓冲区大小的内容,分析完当前工作缓冲区内容时把源文件读入//另一个缓冲区,另一个缓冲区成为工作缓冲区int i = 0;char ch;if ((ep == 150)||(ep == 300)){ep = ep%300;while (((inbuf[i+ep]=fgetc(fsrc))!=NULL) && (i<150))i++;}ch = inbuf[ep];ep++;return ch;}char GetBC(){//从扫描缓冲区读字符,过滤空格、制表和回车符号char ch = GetChar();while ((ch==' ') || (ch=='\n') || (ch=='\t')){if (ch=='\n')lineno++;ch = GetChar();}return ch;}void Concat(char str[], char ch){//将字符ch添加到符号串str的尾部str[strlen(str)] = ch;}bool isLetter(char ch){//判断ch是否字母if (((ch>='A')&&(ch<='Z')) || ((ch>='a')&&(ch<='z')))return true;return false;}bool isDigit(char ch){//判断ch是否数字if ((ch>='0')&&(ch<='9'))return true;return false;}
int Reserve(char* str){//如str是保留字,返回保留字种别号//否则返回0int i = 0;while (keywords[i].code != 0){if (strcmp(str,keywords[i].name) == 0)return keywords[i].code;i++;}return 0;}void Retract(){//从扫描输入缓冲区回退一个字符if (ep==0)ep = 299;elseep--;}
int InsertID(char *str){//如符号表中已有str标识符,返回记录号,//否则将str加到符号表中,返回记录号int i = 0;while ((vtable[i].number!=0) && (i<200)){if (strcmp(str,vtable[i].name) == 0)return vtable[i].number;i++;}if (i<200){vtable[i].number = i+1;strcpy(vtable[i].name, str);return vtable[i].number;}return 0;}int InsertConst(char *str){//如常数表中已有str常数,返回记录号,//否则将str加到常数表中,返回记录号int i = 0;while ((ctable[i].number!=0) && (i<200)){if (strcmp(str,ctable[i].name) == 0)return ctable[i].number;i++;}if (i<200){ctable[i].number = i+1;strcpy(ctable[i].name, str);return ctable[i].number;}return 0;}void ProcError(){printf("%i 行有错误\n", lineno);}int Lex(){//从扫描缓冲区中识别出一个单词,返回单词种别号,//构成的单词的符号串保留在strToken中,//单词的值保留在lvalue中。strToken和lvalue为全局变量。int code;char ch;
memset(strToken, 0, 30);ch = GetBC();sp = ep-1;lvalue = 0;if (isLetter(ch)){while (isLetter(ch) || isDigit(ch)){Concat(strToken, ch);ch = GetChar();}Retract();code = Reserve(strToken);if (code == 0){lvalue = InsertID(strToken);return $ID;}return code;}else if (isDigit(ch)){while (isDigit(ch)){Concat(strToken, ch);ch = GetChar();} if (ch == '.' ) { Concat(strToken, ch); if(!isDigit(GetChar())) {ProcError(); return $END;} Retract(); while(isDigit(GetChar())) { Retract(); Concat(strToken,GetChar()); Retract(); GetChar(); } InsertConst(strToken); return $FLOAT; }Retract();lvalue = InsertConst(strToken);return $INT;}
else if (ch == '='){ch = GetChar();if (ch == '=') return $EQ;Retract();return $ASSIGN;}else if (ch == '+') return $PLUS;else if (ch == ';') return $SEMICOLON;else if (ch == '(') return $LPAR;else if (ch == ')') return $RPAR;else if (ch == '{') return $LBRACE;else if (ch == '}') return $RBRACE;
else if (ch == '*') {ch = GetChar();if (ch == '*') return $POWER;Retract();return $STAR;}else if (ch == EOF) return $END; else{ProcError();return $END;}}void main(){token aToken;int i = 0;char strName[256];FILE *fcon = fopen("const.txt","w+");FILE *ftoken = fopen("token.txt","w+");FILE *fsym = fopen("symbol.txt","w+");printf("请输入源文件名(enter结束):\n");scanf("%s",strName);fsrc = fopen(strName,"r");if (fsrc == NULL){printf("找不到源文件src.txt\n");exit(1);}if ((ftoken == NULL) || (fcon == NULL) || \(fsym == NULL)){printf("不能创建输出文件const.txt,token.txt,symbol.txt\n");exit(1);}/*读源文件入缓冲区*/while ((i<150) && ((inbuf[i]=fgetc(fsrc)) != EOF))i++;
/*词法分析开始*/ep = 0;lineno = 1;aToken.label = 0;aToken.code = Lex();aToken.addr = lvalue;printf("单词序列:\n");while (aToken.code != $END){//单词输出到文件fprintf(ftoken, "(%3d,%3d)", aToken.code, aToken.addr);//单词输出到屏幕printf("(%3d,%3d) ", aToken.code, aToken.addr);aToken.label++;aToken.code = Lex();aToken.addr = lvalue;}/*词法分析结束,输出符号表和常数表到symbol.txt、const.txt文件并显示在屏幕*/i = 0;printf("\n符号表:\n");while (vtable[i].number != 0){fprintf(fsym, "(%3d,%s)", vtable[i].number, vtable[i].name);printf("(%3d,%s)", vtable[i].number, vtable[i].name);i++;}i = 0;printf("\n常数表:\n");while (ctable[i].number != 0){fprintf(fcon, "(%3d,%s)", ctable[i].number, ctable[i].name);printf("(%3d,%s)", ctable[i].number, ctable[i].name);i++;}fclose(fsrc);fclose(fsym);fclose(fcon);fclose(ftoken);printf("\n词法分析结束,按任意键\n");getch();}
lex.h头文件内容如下:typedef struct token{int label;char name[30];//组成单词的字符串int code;int addr;}token;
typedef struct symbol{int number;char name[30];//组成标识符或常数的字符串} symbol;
typedef struct keyword{char name[30]; //组成关键字的字符串int code;} keyword;
//定义一些常量enum TVAL {$WHILE=1,$IF,$ELSE,$SWITCH,$CASE,$DO,$STOP,$END,$ID,$INT,$EQ,$ASSIGN,$PLUS, \$STAR,$POWER,$COMMA,$LPAR,$RPAR,$SEMICOLON,$LBRACE, \$RBRACE,$VAR,$DIM,$FLOAT,$CHAR};