编译原理单元实验3-1手工构造词法分析程序

一、实验目的

1. 理解词法分析器的基本功能

2. 能够编写简单的词法分析器

二、实验内容

1. 测试 toy.cpp

a) 编译 clang++ toy.cpp -o toy

b) 运行 ./toy 或者 cat example.txt | ./toy 或者 ./toy < example.txt

2. 扩展功能

a) 输出词素(lexeme)

b) 识别注释 ‘#’开头直至行尾

c) 识别注释 /* ..... */

d) 识别出正确的小数,例如 12.34 若格式错误,则报错,例如 12.34.56

e) 识别出十六进制数(0x 开头)和八进制数(0 开头),转换为十进制数,输出

★f) 识别出指数形式的常量,转换为小数形式,输出 例如: 2.5e3 被转换为 2500 3.7e-2 被转换为 0.037

★g) 增加符号表,将识别出的标识符(identifier)加入符号表,记录词素、标识符所在的行号

本文章只涉及前五小问。

该实验使用C++编程语言实现功能。第一小问利用C++的cout来输出词素;第二小问利用if判断语句判断输入字符流是否含有”#”来判断该句是否为#类注释;第三小问对于”/*…*/”类注释,首先设置一个自增int类型数据cnt=0,判断第一个输入字符是否为’/’,再判断第二个字符是否为’*’,该过程中如果为真则cnt自增1,若此时cnt为2则该句可能为只有一个’/*’的错误注释,需对后面语句进行判定,若后面出现连续的’*/’则为真注释,否则为假注释;第四小问利用对数字串中的小数点数量进行判断,如果小数点数量大于1则报错;第五小问对十六进制数和八进制数的判定与转化首先判断第一个字符是否为’0’,如果是则可能为八进制数或十六进制数,如果0后面为’ ’或’\n’则该数为0,否则判定下一个字符是否为’x’,是则为16进制数,否则为8进制数。

#include<bits/stdc++.h>
#include <stdlib.h>
#include <cctype>
#include <cstdio>
#include <string>
using namespace std;
char asc[15]= {'!','"','#','$','%','&',',','(',')','*','+',',','-','.','/'}; // !的asc吗为33(x-33)
char asc2[7]= {':',';','<','=','>','?','@'}; // :的asc吗为58(x-58)
int cnt=0,pointnum=0;// /*表示数和字符串目前长度
string s="",sixte="",eigh="";
bool cwzhushi=false,bef=false;
//===----------------------------------------------------------------------===//
// Lexer
//===----------------------------------------------------------------------===//

// The lexer returns tokens [0-255] if it is an unknown character, otherwise one
// of these for known things.
int fastpow(int a,int n)
{
    int ans=1;
    while(n)
    {
        if(n&1)
            ans*=a;
        a*=a;
        n>>=1;
    }
    return ans;
}
enum Token
{
    tok_eof = -1,

    // commands
    tok_def = -2,
    tok_extern = -3,

    // primary---标识符(identifier)
    tok_identifier = -4,
    tok_number = -5,
};

static std::string IdentifierStr; // Filled in if tok_identifier
static double NumVal;             // Filled in if tok_number

/// gettok - Return the next token from standard input.
static int gettok()
{
    static int LastChar = ' ';
    // Skip any whitespace.
    if(LastChar == '\n'&&cnt==2)
    {
        cwzhushi=true;///判断是否为错误注释
    }
    if(cnt==4)
    {
        cwzhushi=false;
    }
    //cout<<"cnt=="<<cnt<<endl;
    if(cwzhushi&&(cnt==2||cnt==3))
    {
        //cout<<s<<"(这是s)"<<endl;
        if(s[0]=='/'&&s[1]=='*')
        {
            cout<<"该句为错误注释"<<endl;
            s="";
            cnt=0;
            cwzhushi=false;
        }
    }
    while (isspace(LastChar))
    {
        LastChar = getchar();
    }

    if(cnt==2)
    {
        //cout<<"---------------------该语句可能为注释或错误注释,故在此进行提醒,如果最后未显示为注释则为错误注释---------------------"<<endl;
        cout<<"---------------------该语句可能为注释或错误注释,故在此进行提醒---------------------"<<endl;
    }
    if (isalpha(LastChar))   // identifier: [a-zA-Z][a-zA-Z0-9]*
    {
        pointnum=0;
        IdentifierStr = LastChar;
        while (isalnum((LastChar = getchar())))
            IdentifierStr += LastChar;

        cout<<"这个是IdentifierStr中的词素: "<<IdentifierStr<<endl;

        if (IdentifierStr == "def")
            return tok_def;//-2
        if (IdentifierStr == "extern")
            return tok_extern;//-3

        return tok_identifier;//-4
    }

    if (isdigit(LastChar) || LastChar == '.')     // Number: [0-9.]+,数字
    {
        std::string NumStr;
        bool not10=false;
        int pointcnt=0;
        do
        {
            NumStr += LastChar;
            LastChar = getchar();
            if(LastChar == '.')
                pointcnt++;
            pointnum++;
            //cout<<"NumStr是"<<NumStr<<endl;
            if(NumStr[0]=='0')///如果一组数据中第一个数字为0则该串数字可能为16进制数或8进制数
            {
                not10=true;
                if(LastChar =='x')///计算16进制转10进制
                {
                    NumStr += LastChar;
                    cout<<"16进制数标志"<<NumStr<<endl;
                    do
                    {
                        LastChar = getchar();
                        sixte+=LastChar;
                    }
                    while (isdigit(LastChar) || LastChar == '.'||(LastChar >='a'&&LastChar <='f'));
                    cout<<"16进制数位"<<sixte<<endl;
                    double si=0;int Point=-1;
                    for(int j=0;j<sixte.size();j++)
                    {
                        if(sixte[j]== '.')
                        {
                            Point=j;
                            break;
                        }
                    }
                    if(Point!=-1)
                    {
                        for(int j=0;j<Point;j++)
                        {
                            if(sixte[j]>='0'&&sixte[j]<='9')
                            {
                                double si1=int(sixte[j])-48;
                                si+=(si1*fastpow(16,Point-1-j));
                            }
                            if(sixte[j] >='a'&&sixte[j] <='f')
                            {
                                double si1=int(sixte[j])-87;
                                si+=(si1*fastpow(16,Point-1-j));
                            }
                        }
                        for(int j=Point+1;j<sixte.size();j++)
                        {
                            if(sixte[j]>='0'&&sixte[j]<='9')
                            {
                                double si1=int(sixte[j])-48;
                                si+=(si1*1.0/fastpow(16,j-Point));
                                //cout<<j-Point<<" "<<fastpow(16,j-Point)<<endl;
                            }
                            if(sixte[j] >='a'&&sixte[j] <='f')
                            {
                                double si1=int(sixte[j])-87;
                                si+=(si1*1.0/fastpow(16,j-Point));
                            }
                        }
                    }
                    else
                    {
                        //cout<<"nopoint"<<endl;
                        for(int j=0;j<sixte.size();j++)
                        {
                            if(sixte[j]>='0'&&sixte[j]<='9')
                            {
                                double si1=int(sixte[j])-48;
                                si+=(si1*fastpow(16,sixte.size()-2-j));
                                //cout<<" "<<fastpow(16,sixte.size()-2-j)<<endl;
                            }
                            if(sixte[j] >='a'&&sixte[j] <='f')
                            {
                                double si1=int(sixte[j])-87;
                                si+=(si1*fastpow(16,sixte.size()-2-j));
                                //cout<<si<<endl;
                            }
                        }
                    }
                    s="";
                    cout<<"16进制数转十进制结果为"<<si<<endl;
                    sixte="";
                }//----------------------------------------------------------------
                else///计算8进制转10进制---也有可能就是0
                {
                    do
                    {
                        if(LastChar==32||LastChar==10)///0的后面是' '或者\n
                        {
                            cout<<"这个是IdentifierStr中的词素(数字): 0"<<endl;
                            return tok_number;
                        }
                        eigh+=LastChar;
                        //cout<<"LastChar的值为"<<LastChar<<endl;
                        LastChar = getchar();
                    }
                    while (isdigit(LastChar) || LastChar == '.');
                    cout<<"8进制数标志"<<NumStr<<endl;
                    cout<<"8进制数位"<<eigh<<endl;
                    double si=0;int Point=-1;

                    for(int j=0; j<eigh.size(); j++)
                    {
                        if(eigh[j]== '.')
                        {
                            Point=j;
                            break;
                        }
                    }
                    if(Point!=-1)
                    {
                        for(int j=0; j<Point; j++)
                        {
                            if(eigh[j]>='0'&&eigh[j]<='9')
                            {
                                double si1=int(eigh[j])-48;
                                si+=(si1*fastpow(8,Point-1-j));
                            }
                            if(eigh[j] >='a'&&eigh[j] <='f')
                            {
                                double si1=int(eigh[j])-87;
                                si+=(si1*fastpow(8,Point-1-j));
                            }
                        }
                        for(int j=Point+1; j<eigh.size(); j++)
                        {
                            if(eigh[j]>='0'&&eigh[j]<='9')
                            {
                                double si1=int(eigh[j])-48;
                                si+=(si1*1.0/fastpow(8,j-Point));
                                //cout<<j-Point<<" "<<fastpow(16,j-Point)<<endl;
                            }
                            if(eigh[j] >='a'&&eigh[j] <='f')
                            {
                                double si1=int(eigh[j])-87;
                                si+=(si1*1.0/fastpow(8,j-Point));
                            }
                        }
                    }
                    else
                    {
                        //cout<<"nopoint"<<endl;
                        for(int j=0; j<eigh.size(); j++)
                        {
                            if(eigh[j]>='0'&&eigh[j]<='9')
                            {
                                double si1=int(eigh[j])-48;
                                si+=(si1*fastpow(8,eigh.size()-1-j));
                                //cout<<eigh.size()-2-j<<" "<<fastpow(8,eigh.size()-1-j)<<endl;
                            }
                            if(eigh[j] >='a'&&eigh[j] <='f')
                            {
                                double si1=int(eigh[j])-87;
                                si+=(si1*fastpow(8,eigh.size()-1-j));
                                //cout<<si<<endl;
                            }
                        }
                    }
                    s="";
                    cout<<"8进制数转十进制结果为"<<si<<endl;
                    eigh="";
                }
            }
        }
        while (isdigit(LastChar) || LastChar == '.');

        if(!not10)///如果是十进制数字(该代码意义为如果不是非十进制数)
        {
            NumVal = strtod(NumStr.c_str(), 0);
            s="";
            s+=LastChar;
            if(pointcnt<=1)///判断这串数字有多少小数点
                cout<<"这个是IdentifierStr中的词素(数字): "<<NumVal<<endl;
            else
                cout<<"该数字格式有误,有误数字为"<<NumStr<<endl;
            cout<<"该数长为"<<pointnum<<endl;
            pointnum=0;
        }
        return tok_number;
    }


    if (LastChar == '#')//#为开头的注释
    {
        pointnum=0;
        // Comment until end of line.
        string s1="";
        do
        {
            LastChar = getchar();
            s1+=LastChar;
        }
        while (LastChar != EOF && LastChar != '\n' && LastChar != '\r');

        cout<<"这段以#打头的语句--"<<"#"<<s1<<"是注释"<<endl;
        if (LastChar != EOF)
            return gettok();
    }


    // Check for end of file.  Don't eat the EOF.
    if (LastChar == EOF)
        return tok_eof;//-1

    // Otherwise, just return the character as its ascii value.
    int ThisChar = LastChar;

    if(ThisChar>=33&&ThisChar<=47)
    {
        pointnum=0;
        if(ThisChar==47&&cnt==0)//判断第一个字符是否为'/'
        {
            s="";
            cout<<"这个可能是IdentifierStr中的词素: "<<asc[ThisChar-33]<<endl;
            cnt++;
            bef=false;
        }
        else if(ThisChar==42&&cnt==1)//判断第二个字符是否为'*'
        {
            cout<<"这个可能是IdentifierStr中的词素: "<<asc[ThisChar-33]<<endl;
            cnt++;
        }
        else if(ThisChar==42&&cnt==2)
        {
            cout<<"这个可能是IdentifierStr中的词素: "<<asc[ThisChar-33]<<endl;
            cnt++;
            bef=true;
        }
        else if(ThisChar==47&&cnt==3&&bef)
        {
            cout<<"这个可能是IdentifierStr中的词素: "<<asc[ThisChar-33]<<endl;
            cnt++;
        }
        else if(cnt<2)
            cout<<"这个是IdentifierStr中的词素: "<<asc[ThisChar-33]<<endl;
        else
            cout<<"这个可能是IdentifierStr中的词素: "<<asc[ThisChar-33]<<endl;
    }
    if(ThisChar>=58&&ThisChar<=64)
    {
        pointnum=0;
        cout<<"这个是IdentifierStr中的词素: "<<asc2[ThisChar-58]<<endl;
    }

    //cout<<"这是cnt"<<cnt<<endl;
    s+=LastChar;
    //cout<<"这是s的:"<<s<<endl;

    LastChar = getchar();

    return ThisChar;
}


//--------------------
int main()
{
    int tok;
    bool cwzhushi=false;
    fprintf(stderr, "ready> ");
    do
    {
        if(cnt==4&&!cwzhushi)
        {
            if(s[0]=='/'&&s[1]=='*')
            {
                //cout<<"yes1"<<endl;
                if(s[s.size()-1]=='/'&&s[s.size()-2]=='*')
                {
                    //system("cls");
                    cout<<"该句为注释"<<endl;
                }
            }
        }

        if(cnt==4)
        {
            s="";
            cnt=0;
        }

        tok = gettok();
        fprintf(stderr, "got token: %d\n",tok);
        cout<<endl;
    }
    while(tok != tok_eof);


    return 0;
}

输出截图:

 

 

 

 

 

 

实验一  手工构造简单词法分析程序(必修) 一、实验目的 了解词法分析程序的基本构造原理,掌握简单词法分析程序手工构造方法。 二、实验内容 对从键盘输入或从文件读入的形如: “const count=10,sum=81.5,char1=’f’,string1=”hj”, max=169;”的常量说明串进行处理,分析常量说明串中各常量名、常量类型及常量值,并统计各种类型常量个数。 三、实验要求 1、输入的常量说明串,要求最后以分号作结束标志; 2、根据输入串或读入的文本文件中第一个单词是否为“const”判断输入串或文本文件是否为常量说明内容; 3、识别输入串或打开的文本文件中的常量名。常量名必须是标识符,定义为字母开头,后跟若干个字母,数字或下划线; 4、根据各常量名紧跟等号“=”后面的内容判断常量的类型。其中:字符型常量定义为放在单引号内的一个字符;字符串常量定义为放在双引号内所有内容;整型常量定义为带或不带+、- 号,不以0开头的若干数字的组合;实型常量定义为带或不带+、- 号,不以0开头的若干数字加上小数点再后跟若干数字的组合; 5、统计并输出串或文件中包含的各种类型的常量个数; 6、以二元组(类型,值)的形式输出各常量的类型和值; 7、根据常量说明串置于高级语言源程序中时可能出现的错误情况,模仿高级语言编译器对不同错误情况做出相应处理。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值