词法分析

来源:互联网 发布: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;}