编译原理 语法分析

 

上接词法分析 


递归下降的方法实现算术表达式的语法分析器:

三个函数在词法分析的基础上,反复调用,指针沿着词法分析得到的二元组一直后移,

中间加一些判断条件  不符合就报错。

 

测试程序:

// pL/0语言词法分析器
#include<bits/stdc++.h>
using namespace std;

ifstream infile("c.txt");//词法分析的结果或语法分析的输入
string str;//string变量进行字符识别
string sym; //指针
string sym1;
int temp=0;

void expressionAnalysis();//表达式分析
void termAnaysis();//项分析
void factorAnalysis();//因子分析
int advance();

int conterr=0;//记录错误
int lpnum=0;//记录左括号
int found;//提取字符串中指针的位置
int flag=0;//记录往后移动一个指针SYM是否正确
string s;//用来保存要分析的字符串
struct _2tup
{
    string token;
    int id;
};

int advance() //SYM的移动
{
    if(!getline(infile,str)) //从文件中提取字符
    {
        return 0;
    }
    found=str.find(',',0);

    if(found==-1) //当为error的时候,没有‘,’
    {
        conterr++;
        cout<<"语法错误 识别字符错误"<<endl;
        return -1;
    }
    if(temp==1)
        sym1=sym;
    sym=str.substr(1,found-1);

//    cout<<str.substr(found+1,4)<<endl;

    if(temp==0)
    {
        sym1=sym;
        temp=1;
    }
//    cout<<sym<<"  "<<sym1<<endl;
   if(sym=="23" && sym1=="24")
   {
       conterr++;
       cout<<"')'和'('中间缺少运算符\n";
       return -1;
   }
   if(sym=="24" && sym1=="23")
   {
       conterr++;
       cout<<"'('和')'中间缺少项\n";
       return -1;
   }
   if(sym=="24"&&(sym1!="28"&&sym1!="29"))
   {
       conterr++;
       cout<<"')'前面缺少项\n";
       return -1;
   }
   if(sym1=="24"&&(sym=="28"||sym=="29"))
   {
       conterr++;
       cout<<"')'后缺少运算符\n";
       return -1;

   }
   if(sym1=="23"&&(sym=="12"||sym=="13"||sym=="14"||sym=="15"))
   {
       conterr++;
       cout<<"'('后缺少项\n";
       return -1;

   }



//    cout<<sym<<endl;
    return 1;
}

void factorAnalysis()
{
//    cout<<"factor\n"<<sym<<endl;
//    cout<<sym<<endl;
    if(sym=="28"||sym=="29") //如果是标识符和无符号整数,指针就往后移动
    {
        flag=advance();
        if(conterr)
        {
            return;
        }
        if(sym=="23")
        {
            conterr++;
            cout<<"'('前缺少运算符\n";
            return;
        }
        if(lpnum==0&&sym=="24")
        {
            conterr++;
            cout<<"语法错误 ')'不匹配"<<endl;
            return;
        }
    }
    else if(sym=="23") //如果是左括号,就要接下来判断是否为表达式,指针往后移动
    {
//        cout<<"hello"<<sym1<<endl;
        if(sym1=="28"||sym1=="29")
        {
            cout<<"(前面缺少运算符"<<endl;
            conterr++;
            return ;
        }
        lpnum++;
//        cout<<lpnum<<endl;
        flag=advance();
        if(conterr)
        {
            return;
        }
        if(flag==0) //当为最后一个标志的时候,若没有右括号匹配就错误
        {
            conterr++;
            cout<<"语法错误 '('后缺少表达式"<<endl;
            return;
        }
//        cout<<sym<<endl;
        expressionAnalysis();
        if(conterr)
        {
            return;
        }
        if(flag==0||sym!="24")
        {
            conterr++;
            cout<<"语法错误 表达式后面缺少')'"<<endl;
            return;
        }
        else
        {
            lpnum--;
            flag=advance();
            if(conterr)
            {
                return;
            }
            if(flag==0)
            {
                return;
            }
        }
    }
    else
    {
        cout<<"语法错误 因子首部不为<标识符>|<无符号整数>|'('"<<endl;
        conterr++;
        return;
    }
    return;
}

void termAnalysis()
{
//    cout<<"term\n"<<sym<<endl;
    factorAnalysis();
    if(conterr)
    {
        return;
    }
    while((sym=="14")||(sym=="15")) //当为'*'或'/'的时候,一直往后识别因子并循环
    {
        flag=advance();
        if(conterr)
        {
            return;
        }
        if(flag==0)
        {
            conterr++;
            cout<<"语法错误 <乘法运算符>后缺因子"<<endl;
            return;
        }
        if(conterr)
        {
            return;
        }
        factorAnalysis();
        if(conterr)
        {
            return;
        }
    }
    return;
}

void expressionAnalysis()
{
//    cout<<"expression!\n"<<sym<<endl;
    if(conterr)
    {
        return;
    }
    if((sym=="14")||(sym=="15")) //当为'*'或'/'的时候
    {
        flag=advance();
        if(!conterr)
        {
            return;
        }
        if(flag==0)
        {
            cout<<"语法错误 <加法运算符>后缺项"<<endl;
            conterr++;
            return;
        }
    }
    termAnalysis();

     if((sym=="14")||(sym=="15")) //当为'*'或'/'的时候
    {
        flag=advance();
        if(!conterr)
        {
            return;
        }
        if(flag==0)
        {
            cout<<"语法错误 <加法运算符>后缺项"<<endl;
            conterr++;
            return;
        }
    }

    if(conterr)
    {
        return;
    }
    while((sym=="12")||(sym=="13")) //当为'+'或'-'的时候,一直往后识别项并循环
    {
//        cout<<str.substr(found+1,4)<<endl;



        flag=advance();
        if(conterr)
        {
            return;
        }
        if(flag==0)
        {
            cout<<"语法错误 <加法运算符>后缺项"<<endl;
            conterr++;
            return;
        }
        termAnalysis();
        if(conterr)
        {
            return;
        }
    }
    return;
}

bool is_blank(char ch)
{
    return ch == ' ' || ch == '    ';//空格或控制字符
}
bool gofor(char& ch, string::size_type& pos, const string& prog)//返回指定位置的字符
{
    ++pos;
    if (pos >= prog.size())
    {
        return false;
    }
    else
    {
        ch = prog[pos];
        return true;
    }
}

_2tup scanner(const string& prog, string::size_type& pos, const map<string, int>& keys, int& row)
{
    /*
    if
        标示符
    else if
        数字
    else
        符号
    */
    _2tup ret;
    string token;
    int id = 0;

    char ch;
    ch = prog[pos];

    while(is_blank(ch))
    {
        ++pos;
        ch = prog[pos];
    }
    // 判断标示符、关键字
    if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || ch == '_')
    {

        map<string, int>::const_iterator cit;
        //保证读取一个单词
        while((ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || ch == '_')
        {
            token += ch;//追加标示符、关键字
            if (!gofor(ch, pos, prog))
            {
                break;
            }
            if(token=="odd")
            {
                id=cit->second;
                goto end;
            }
        }
        // 这里先看做都是其他标示符
        id = keys.size();
        // 验证是否是关键字
        cit = keys.find(token);//根据string类型的token返回int类型的id赋值给cit

        if (cit != keys.end())
        {
            id = cit->second;//此时是关键字,记录他的id
//            if(id<=10)
//            cout<<cit->first<<"is true!"<<cit->second<<endl;
        }
    }
    // 识别常数
    else if ((ch >= '0' && ch <= '9'))
    {
        while (ch >= '0' && ch <= '9' )
        {
            token += ch;
            if (!gofor(ch, pos, prog))
            {
                break;
            }
        }
        id = keys.size() - 1;
        int dot_num = 0;
        for (string::size_type i = 0; i != token.size(); ++i)
        {
            if (token[i] == '.')
            {
                ++dot_num;
            }
        }
        if (dot_num > 1)
        {
            id = -1;
        }
    }
    else
    {
        map<string, int>::const_iterator cit;
        switch (ch)
        {
        case '-': // - 操作符
            token += ch;
            gofor(ch,pos,prog);
            cit = keys.find(token);
            if (cit != keys.end())
            {
                id = cit->second;
            }
            break;
        case ':':
            token += ch;
            if (gofor(ch, pos, prog))
            {
                if (ch == '=') // -- 操作符
                {
                    token += ch;
                    gofor(ch, pos, prog);  //不让:=  中的=重复使用
                }
            }
            cit = keys.find(token);
            if (cit != keys.end())
            {
                id = cit->second;
            }
            break;

        case '=':
            token += ch;
            gofor(ch,pos,prog);
            cit = keys.find(token);
            if (cit != keys.end())
            {
                id = cit->second;
            }
            break;

        case '/': // / 操作符
            token += ch;
            gofor(ch,pos,prog);
            cit = keys.find(token);
            if (cit != keys.end())
            {
                id = cit->second;
            }
            break;
        case '+':
            token += ch;
            cit = keys.find(token);
            if (cit != keys.end())
            {
                id = cit->second;
            }
            gofor(ch, pos, prog);
            break;

        case '<':
            token += ch;
            if (gofor(ch, pos, prog))
            {
                if (ch == '>')
                {
                    token += ch;
                    gofor(ch,pos,prog);
                }
                else if (ch == '=')
                {
                    token += ch;
                    gofor(ch, pos, prog);
                }
            }
            cit = keys.find(token);
            if (cit != keys.end())
            {
                id = cit->second;
            }
            break;

        case '>':
            token += ch;
            if (gofor(ch, pos, prog))
            {
                if (ch == '=')
                {
                    token += ch;
                    gofor(ch, pos, prog);
                }
            }
            cit = keys.find(token);
            if (cit != keys.end())
            {
                id = cit->second;
            }
            break;
        case '(': // / 操作符
            token += ch;
            gofor(ch,pos,prog);
            cit = keys.find(token);
            if (cit != keys.end())
            {
                id = cit->second;
            }
            break;
        case ')': // / 操作符
            token += ch;
            gofor(ch,pos,prog);
            cit = keys.find(token);
            if (cit != keys.end())
            {
                id = cit->second;
            }
            break;


        case '*':
            token += ch;
            cit = keys.find(token);
            if (cit != keys.end())
            {
                id = cit->second;
            }
            gofor(ch, pos, prog);
            break;

        case ',':
        case '.':
        case ';':
            token += ch;
            gofor(ch, pos, prog);
            //++pos;
            //ch = prog[pos];
            cit = keys.find(token);
            if (cit != keys.end())
            {
                id = cit->second;
            }
            break;

        case '\n':
            token += "换行";
            ++pos;
            ch = prog[pos];
            id = -2;
            break;
        default:
            token += "错误";
            ++pos;
            ch = prog[pos];
            id = -1;
            break;
        }
    }
end:

    ret.token = token;
    ret.id    = id;

    return ret;
}

void init_keys(const string& file, map<string, int>& keys)//读取单词符号和种别码
{
    ifstream fin(file.c_str());//.c_str返回的是当前字符串的首地址
    if (!fin)
    {
        cerr << file << " doesn't exist!" << endl;//cerr不经过缓冲而直接输出,一般用于迅速输出出错信息
        //  exit(1);
    }
    keys.clear();//清空map对象里面的内容
    string line;
    string key;
    int id;
    while (getline(fin, line))//这个函数接收两个参数:一个输入流对象和一个string对象,getline函数从输入流的下一行读取,并保存读取的内容到string中
    {
        istringstream sin(line);//istringstream sin(s);定义一个字符串输入流的对象sin,并调用sin的复制构造函数,将line中所包含的字符串放入sin 对象中!
        sin >> key >> id;//读取里面的字符串每一行一个key id
        keys[key] = id;
    }
}

void read_prog(const string& file, string& prog) //读取代码,并追加到prog上
{
    ifstream fin(file.c_str());
    if (!fin)
    {
        cerr << file << " error!" << endl;
        //  exit(2);
    }
    prog.clear();
    string line;
    while (getline(fin, line))
    {
        prog += line + '\n';
    }
}

void cifafenxi()
{
    map<string, int> keys;
    init_keys("a.txt", keys);

    string prog;
    read_prog("b.txt", prog);

    vector< _2tup > tups;
    string token, id;

    string::size_type pos = 0;//size_type属于string标准库,作用可看做相当于unsigned·int
    int row  = 1;

    _2tup tu;
    int no = 0;
//    freopen("CON", "w", stdout);//结果在控制台上输出
    freopen("c.txt","w",stdout);

    do
    {
        tu = scanner(prog, pos, keys, row);

        switch (tu.id)
        {
        case -1://返回的是错误
            ++no;
            cout << no << ": ";
            cout << "Error in row" << row << "!" << '<' << tu.token<< "," << tu.id << '>' << endl;
            tups.push_back(tu);
            break;
        case -2:
            ++row;
            // cout << '<' << tu.token<< "," << tu.id << '>' << endl;
            break;
        default:

            s=prog;
            cout << '(' << tu.id<< "," << tu.token << ')' << endl;

            tups.push_back(tu);
            break;
        }
    }
    while (pos < prog.size());

}

void yufafenxi()//语法分析
{
    freopen("CON", "w", stdout);//结果在控制台上输出
    flag=advance();
    if(flag)
    {
        expressionAnalysis();
    }
    if(flag!=-1 && !conterr)
    {
        cout<<"正确:"<<s<<endl;
    }

}
int main()
{
    cifafenxi();
    yufafenxi();
    return 0;
}


测试结果:

 

 

 

a.txt

 

b.txt

 

c.txt

 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序猿的探索之路

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值