编译原理:一个简单的词法分析程序

算法描述
    程序总体是把一些布尔函数写在词法分析程序之前,词法分析函数写在主函数之前。主函数中写提示用户输入,当获得一个正确的输入时,调用词法分析程序进行分析。
    首先写出程序中关键字,运算符,分隔符,过滤符的集合,当单词与这些匹配时(遇到过滤符直接略过),判定是这其中的结果。遇到字母开头的单词可以分为两个小类,一是关键字,二是标识符;遇到数字开头的单词可以分为三个小类,一是定点数,二是浮点数,三是出错的标识符。如果是字母或者下划线开头的单词则是标识符。
    具体的单词分析,是申请一个名为out的string,将单词结果暂存在其中,跟行数和类型一起输出。运用file的I/O将代码内容从文件中读出,以及控制光标回退一个字符。

程序结构
  集合定义:关键字,运算符,分隔符,过滤符
  判断函数:关键字,过滤符,字母,数字

  词法分析程序
    过滤:回车,换行,空格
      字母开头
        属于关键字
        属于标识符
      数字开头
        属于定点数
        属于浮点数
        出错的标识符
      字母或_开头
        属于标识符
      属于分隔符
      属于运算符
        特判两位的运算符(后面有等号的)

  主程序
    文字提示
    用户输入
      进行词法分析
      文件名有误,提示重输

主要变量名说明
    KEYWORD:关键字集合
    OPERATOR:运算符集合
    SEPERATOR:分隔符集合
    FILTER:过滤符集合
    ch:当前面临的一个字符
    out:临时存储获取的一个字符串(单词)
    InputFile:将被分析的源文件的路径和后缀

调试情况
    1.数字开头的情况一开始出错了,遇到浮点数不能显示小数点后面的内容,遇到出错的标识符会报错但是会再单独输出数字和字母。思考了一下觉得是逻辑上的错误。利用在程序中插入输出当前ch值的方式,发现了错误,从而能够正确输出浮点数的值。
    2.行数的显示。一开始没有想到行数要怎么去统计,后来想到可以在回车时使Line+1,于是在整个判断的开头加上对此的判断。

tip:用到了fseek函数,这个函数的定义如下:
在这里插入图片描述

代码如下:

#include<iostream>
#include<fstream>
#include<cstdio>
#include<windows.h>
using namespace std;

string KEYWORD[20]={"main","return","int","double","float","unsigned","if",
                     "else","do","while","switch","case","goto","char",
                     "sizeof","struct","void","continue","break","const"};
char OPERATOR[10]={'+','-','*','/','>','>=','<','<=','=','!'};
char SEPERATOR[8]={',',';','(',')','[',']','{','}'};
char FILTER[4]={' ','\t','\n'};
int Line=1;
//int FlagE,FlagF=0;

//判断关键字
bool IsKeyword(string word)
{
    for(int i=0;i<20;i++)
    {
        if(KEYWORD[i]==word) {return true;}
    }
    return false;
}

//判断过滤符
bool IsFilter(char word)
{
    for(int i=0;i<4;i++)
    {
        if(FILTER[i]==word) {return true;}
    }
    return false;
}

//判断字母
bool IsLetter(char word)
{
    if((word>='a'&&word<='z')||(word>='A'&&word<='Z')) {return true;}
    return false;
}

//判断数字
bool IsDigit(char word)
{
    if(word>='0'&&word<='9') {return true;}
    return false;
}

//词法分析函数
void LexicalAnalysis(FILE *fpin)
{
    char ch=' ';
    string out="";
    while((ch=fgetc(fpin))!=EOF)
    {
        out="";
        if(ch=='\n'){Line++;}
        else if(IsLetter(ch))
        {
            while(IsLetter(ch))
            {
                out+=ch;
                ch=fgetc(fpin);
            }
            fseek(fpin,-1,SEEK_CUR);
            if(IsKeyword(out)){cout<<Line<<"\t\t\t"<<out<<"\t\t\t"<<"Keyword"<<"\t\t\t"<<endl;}  //为关键字
            else{cout<<Line<<"\t\t\t"<<out<<"\t\t\t"<<"Idenifier"<<"\t\t\t"<<endl;}              //为标识符
        }
        else if(IsDigit(ch))
        {
            if(IsLetter(fgetc(fpin)))
            {
                fseek(fpin,-1,SEEK_CUR);
                while(IsDigit(ch))
                {
                    out+=ch;
                    ch=fgetc(fpin);
                }
                out+=ch;
                //FlagE=1;
                cout<<Line<<"\t\t\t"<<out<<"\t\t\t"<<"!!!!!Error!!!!!"<<"\t\t\t"<<endl;   //为标识符出错
            }
            else
            {
                fseek(fpin,-1,SEEK_CUR);
                while(IsDigit(ch)||ch=='.')
                {
                    out+=ch;
                    ch=fgetc(fpin);
                }
                //FlagF=1;
                cout<<Line<<"\t\t\t"<<out<<"\t\t\t"<<"Digit"<<"\t\t\t"<<endl;  //为常数
                //fseek(fpin,-1,SEEK_CUR);
            }
        }
        else if(IsLetter(ch)||ch=='_')
        {
            while(IsLetter(ch)||IsDigit(ch)||ch=='_')
            {
                out+=ch;
                ch=fgetc(fpin);
            }
            fseek(fpin,-1,SEEK_CUR);
            cout<<Line<<"\t\t\t"<<out<<"\t\t\t"<<"Idenifier"<<"\t\t\t"<<endl;   //为标识符
        }
        else switch(ch)
        {
            //符号为分隔符
            case',':
            case';':
            case'(':
            case')':
            case'[':
            case']':
            case'{':
            case'}':cout<<Line<<"\t\t\t"<<ch<<"\t\t\t"<<"Seperator"<<"\t\t\t"<<endl;break;
            //符号为运算符
            case'-':
            case'*':
            case'/':
            case'=':
            case'!':cout<<Line<<"\t\t\t"<<ch<<"\t\t\t"<<"Operator"<<"\t\t\t"<<endl;break;
            //注意判断+=
            case'+':
                {
                    ch=fgetc(fpin);
                    if(ch=='=') cout<<Line<<"\t\t\t"<<"+="<<"\t\t\t"<<"Operator"<<"\t\t\t"<<endl;
                }break;
            //注意判断>=
            case'>':
                {
                    ch=fgetc(fpin);
                    if(ch=='=') cout<<Line<<"\t\t\t"<<">="<<"\t\t\t"<<"Operator"<<"\t\t\t"<<endl;
                }break;
            //注意判断<=
            case'<':
                {
                    ch=fgetc(fpin);
                    if(ch=='=') cout<<Line<<"\t\t\t"<<"<="<<"\t\t\t"<<"Operator"<<"\t\t\t"<<endl;
                }break;
        }
    }
}

int main()
{
    char InputFile[100];
    FILE *fpin;
    cout<<"请输入源文件的路径和后缀:";
    //判断输入的文件名是否有效
    while(true)
    {
        cin>>InputFile;
        if((fpin=fopen(InputFile,"r"))!=NULL) break;
        else{cout<<"文件名错误!请输入源文件的路径和后缀:";}
    }
    cout<<endl;
    cout<<"\t\t\t"<<"--词法分析--"<<"\t\t\t"<<endl;
    cout<<"-Line-"<<"\t\t\t"<<"-Word-"<<"\t\t\t"<<"-Type-"<<"\t\t\t"<<endl;
    LexicalAnalysis(fpin);
    return 0;
}

输入:(斜体为文件内容)
input.txt
int main()
{
int 2b,a = 10;
double b = -20.9;
if(a<=b)
a+=b;
else
a=4b+5;
return a;
}

输出
在这里插入图片描述

  • 5
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值