词法分析
来源:互联网 发布:r2v矢量化软件 编辑:程序博客网 时间:2024/06/06 19:39
编译原理的词法分析,主要是根据自己的规则,识别出相对应的规则,根据自己的需求,输出你想要的内容
#include <string.h>#include <stdio.h>#include <stdlib.h>#include <ctype.h>#include <math.h>//记号类型序号enum Token_Type { ORIGIN, SCALE, ROT, IS, TO, //保留字 STEP, DRAW, FOR, FROM, //保留字 T, //参数 ID, //标识符(已没用了) SEMICO, L_BRACKET, R_BRACKET, COMMA, //分隔符 PLUS, MINUS, MUL, DIV, POWER, //运算符 FUNC, //函数 CONST_ID, //数值常数 ERRTOKEN, //错误单词 NONTOKEN //表示词法分析结束的专用记号};//记号变量类型struct Token { Token_Type type; //记号类别号 char *lexeme; //标识符的字符串 double value; //数值常数的值 double (*FuncPtr)(double); //函数的指针};// 预定义单词表#define NUMKEYWORDS 18struct Token TokenTab[NUMKEYWORDS] = { //语言中使用的符号常数 {CONST_ID, "PI", 3.1415926, NULL}, {CONST_ID, "E", 2.71828, NULL}, //语言中惟一的变量 {T, "T", 0.0, NULL}, //语言允许用的数学函数名(函数原型放在 math.h 中) {FUNC, "SIN", 0.0, sin}, {FUNC, "COS", 0.0, cos}, {FUNC, "TAN", 0.0, tan}, {FUNC, "LN", 0.0, log}, {FUNC, "EXP", 0.0, exp}, {FUNC, "SQRT", 0.0, sqrt}, //语句关键字 {ORIGIN, "ORIGIN", 0.0, NULL}, {SCALE, "SCALE", 0.0, NULL}, {ROT, "ROT", 0.0, NULL}, {IS, "IS", 0.0, NULL}, {FOR, "FOR", 0.0, NULL}, {FROM, "FROM", 0.0, NULL}, {TO, "TO", 0.0, NULL}, {STEP, "STEP", 0.0, NULL}, {DRAW, "DRAW", 0.0, NULL}};Token iskeywords(const char* id);//判断标识符是否语言的预留单词void main(int argc, char *argv[]) {FILE *InFile; //源文件int Char; //当前输入字符Token token; //记号变量int c; //临时变量(暂存已读入的输入字符)char *bufc,*bufval; //临时变量(以字符串形式暂存读入的单字符,暂存标识符、数值常量的当前串) if (argc < 2) { //程序执行时有 1 个命令行参数(即需要进行词法分析的文件名) printf("请输入源文件名!\n" ); return; } InFile = fopen (argv[1], "r"); //以只读方式,打开源文件 printf("记号类别 字符串 常数值 函数指针\n"); printf("__________________________________________\n"); while(1) { //初始化记号变量 //token.type=NONTOKEN;//记号类别号放在后面处理 token.lexeme=""; token.value=0; token.FuncPtr=NULL; Char = getc (InFile); // 从源文件读入一个字符 if (Char == EOF) { token.type=NONTOKEN; break; //读到文件终止符,词法分析结束 } //消除注释内容 if(Char=='-' || Char=='/' ) { //当前输入字符是 - 或 /,说明可能遇到注释引导符了 c=Char; //暂存已读的输入字符 Char = getc (InFile); //向前多读 1 个输入字符 if (Char == c) { //多读的输入字符与暂存字符相同,说明是注释引导符 -- 或 // //逐一读入注释文本(以换行符或文件终止符为结束),不作任何处理,即跳过了这些注释内容 while (Char != '\n' && Char != EOF) Char = getc (InFile); } else { //多读的字符不是 - 或 /,说明遇到的不是注释引导符 ungetc (Char, InFile); //将多读的这个字符退回输入流 Char=c; //当前输入字符恢复为暂存字符(暂存的字符 - 或 / 是运算符,需作为记号处理) } } if(isspace(Char)) continue; //过滤空白符(空格、制表符、换行符) if(Char=='-') { //减号 token.type=MINUS; token.lexeme="-"; } else if(Char=='/' ) { //除号 token.type=DIV; token.lexeme="/"; } else if(Char=='*' ) { //当前输入字符是 *,说明已读出乘号或遇到乘方算符的首字母 c=Char; //暂存已读的 * Char = getc (InFile); //向前多读 1 个输入字符 if (Char == c) { //多读的字符也是 *,说明已读出了乘方算符 token.type=POWER; token.lexeme="**"; } else { //多读的字符不是 *,说明是乘号 ungetc (Char, InFile); //将多读的字符退回输入流 token.type=MUL; token.lexeme="*"; } } else if(Char==',' ) { //逗号 token.type=COMMA; token.lexeme=","; } else if(Char==';' ) { //分号 token.type=SEMICO; token.lexeme=";"; } else if(Char=='(' ) { //左括号 token.type=L_BRACKET; token.lexeme="("; } else if(Char=='+' ) { //加号 token.type=PLUS; token.lexeme="+"; } else if(Char==')' ) { //右括号 token.type=R_BRACKET; token.lexeme=")"; } else if(isalpha(Char)) { //当前输入字符是字母,说明遇到了标识符的首字母 //将首字母以字符串的形式,保存到临时串 bufc=(char*)malloc(2); bufc[0]=toupper(Char); bufc[1]='\0'; bufval=bufc; //循环读取后续的输入字符 for(;;){ Char = getc (InFile); //读入 1 个输入字符 if (isalnum(Char)) { //当前输入字符仍然是字母或数字,说明还在标识符中 //将读入的输入字符,以字符串的形式,连接到临时串后 bufc=(char*)malloc(2); bufc[0]=toupper(Char); bufc[1]='\0'; strcat(bufval,bufc);//将字符串bufval追加到bufc后面 } else //当前输入字符不再是字母或数字,说明标识符已经读完,并且多读了一个不属于标识符的输入 break; } ungetc (Char, InFile);//将多读的字符退回到输入流中 //token.type=ID; //记号类别 = 标识符 //token.lexeme = bufval;//记号值 = 临时串值 token=iskeywords(bufval); //判定是否语言的关键字,结果以记号变量形式返回 } else if(isdigit(Char)) { //当前输入字符是数字,说明遇到了数值常量的首个数字字母 bufc=(char*)malloc(2); bufc[0]=Char; bufc[1]='\0'; bufval=bufc; //逐个字符处理数值常量的整数部分 for (;;) { Char = getc (InFile); if (isdigit(Char)) { bufc=(char*)malloc(2); bufc[0]=Char; bufc[1]='\0'; strcat(bufval,bufc); } else break; } if (Char == '.') { //当前输入字符是 .,说明遇到了数值常量的小数部分 bufc=(char*)malloc(2); bufc[0]=Char; bufc[1]='\0'; strcat(bufval,bufc); //逐个字符处理数值常量的小数部分 for (;;) { Char = getc (InFile); if (isdigit(Char)) { bufc=(char*)malloc(2); bufc[0]=Char; bufc[1]='\0'; strcat(bufval,bufc); } else break; } } ungetc (Char, InFile);//将多读的、不属于数值常量的字符,退回输入流 token.type=CONST_ID; //记号类别 = 常数 token.value=atof(bufval); //记号值 = 临时串转换成的浮点数 } else if (Char == EOF ){ //文件终止符(处理源文件最后一行是注释的情况) token.type=NONTOKEN; break; } else { //当前输入字符不是以上情况,说明该字符不在本语言的字母表中,出现词法错误 token.type=ERRTOKEN; } //putc(Char,stdout);//逐个字符地显示处理后的源文件 //输出记号信息 if(token.type==CONST_ID) printf(" %4d%12s%12f\n",token.type,"",token.value); else if(token.type==FUNC) printf(" %4d%12s%12f%12x\n",token.type,"",token.value,token.FuncPtr); else printf(" %4d%12s\n",token.type, token.lexeme); }; printf(" %4d%12s\n",token.type, token.lexeme);//显示分析结束记号 printf("______________________________\n"); fclose (InFile); //关闭源文件(即关闭词法分析器)}//判断标识符是否语言的预留单词Token iskeywords(const char* id){int i;Token token; token.lexeme=""; token.value=0; token.FuncPtr=NULL; for(i=0;i<NUMKEYWORDS;i++) if( strcmp(TokenTab[i].lexeme, id)==0) break; if(i<NUMKEYWORDS) token=TokenTab[i]; else token.type = ERRTOKEN; return token;}
阅读全文
0 0
- 词法分析
- 词法分析
- 词法分析
- 词法分析
- 词法分析
- 词法分析
- 词法分析
- 词法分析
- 词法分析
- 词法分析
- 词法分析
- 词法分析
- 词法分析
- 词法分析
- 词法分析
- 词法分析
- 词法分析
- 词法分析
- LDAP入门学习
- JavaWeb学习笔记-java基础-5-可变参数
- java IO 字符流之 Buffered缓冲区
- Eclipse集成Maven和Scala
- 童年经典小游戏,俄罗斯方块,让我们一起用javascript来制作自己的童年吧
- 词法分析
- bzoj2744 二分图 最大团
- spring aop学习8:spring对jdk和cglib动态代理的选择
- 高进度算法-补码运算
- [noip2014]子矩阵(dfs+dp)
- Java之进程与线程
- poj 3177 Redundant Paths
- 一些比较常用的在Markdown使用的数学符号
- [数据结构]实验五_顺序二叉树