程序最美(寻路)

你还在坚持练习你的技术吗?运动员天天训练,音乐家也会演练更难的曲章。你呢?

四则运算的词法分析

四则运算的词法分析

         之前我们处理四则运算的方法有两种,第一种是对输入的格式强制限定运算符两边都有空白符,另一种是我们根据输入的字符串,对其中的运算符进行添加空白符预处理。通过添加空白符进行处理里显然不太规范和方便,真正需要做的应该是我们对输入的四则运算表达式进行词法分析,解析出相应的运算符和操作符,然后在进行中缀转后缀、后缀表达式的计算等过程。

         我们的四则运算表达式只包含两种元素:操作符和操作数。

         其中,操作符目前限定为+、-、*、/四种,另外还有括号:左括号和右括号。

         操作数可以是小数也可以是整数。

         操作符和操作数我们将其视为token,其对应的种别码分别为:

token

id

+

1

-

2

*

3

/

4

(

5

)

6

操作符

7

 

         操作数的定义如下:操作数 = 数字 数字*

         空白符包括空格符、制表符,我们将其忽略,由于我们处理的四则运算表达式都是单行的输入,所以我们不对换行符\n进行考虑。

         程序输出的结果为二元组:<token,id>。

         以下为具体的程序实现

// 四则运算的词法分析
#include <iostream>
#include <string>
#include <vector>
#include <map>
using namespace std;

struct TI
{
    string token;
    int    id;
};

bool is_blank(char ch)
{
    return ch == ' ' || ch == '    ';
}

void get_exp(string& exp)
{
    getline(cin, exp);
}

void init_keys(map<string, int>& keys)
{
    keys.clear();
    keys["+"] = 1;
    keys["-"] = 2;
    keys["*"] = 3;
    keys["/"] = 4;
    keys["("] = 5;
    keys[")"] = 6;
    keys["__NUM__"] = 7;
}

void lex(const string& exp, vector<TI>& to_id, const map<string, int>& keys)
{
    to_id.clear();
    char ch;
    for (string::size_type pos = 0; pos < exp.size(); /* ++pos */)
    {
        TI ti;
        ch = exp[pos];

        if (is_blank(ch))
        {
            ++pos;
            continue;
        }
        if (ch >= '0' && ch <= '9' || ch == '.')
        {
            ti.token += ch;
            ++pos;
            if (pos >= exp.size())
            {
                ti.id = keys.size();
                to_id.push_back(ti);
                return;
            }
            ch = exp[pos];
            while (ch >= '0' && ch <= '9' || ch == '.')
            {
                ti.token += ch;
                ++pos;
                if (pos >= exp.size())
                {
                    ti.id = keys.size();
                    to_id.push_back(ti);
                    return;
                }
                ch = exp[pos];
            }
            ti.id = keys.size();
            to_id.push_back(ti);
        }
        else
        {
            map<string, int>::const_iterator cit;
            switch (ch)
            {
            case '+':
            case '-':
            case '*':
            case '/':
            case '(':
            case ')':
                ti.token += ch;
                cit = keys.find(ti.token);
                if (cit == keys.end())
                {
                    cout << "test" << endl;
                }
                ti.id = cit->second;
                to_id.push_back(ti);
                ++pos;
                break;

            default:
                ti.token += string("未知字符:") + ch;
                ti.id = -1;
                to_id.push_back(ti);
                ++pos;
                break;
            }
        }
    }
}

int main()
{
    string exp;
    get_exp(exp);
    map<string, int> keys;
    init_keys(keys);

    vector<TI> to_id;

    lex(exp, to_id, keys);

    for (vector<TI>::size_type i = 0; i != to_id.size(); ++i)
    {
        cout << '<' << to_id[i].token << ',' << to_id[i].id << '>' << endl;
    }
    return 0;
}

测试1:

测试2:

在我们的程序中,我们没有对操作数的合法性进行检测,关于操作数的合法性会在中缀表达式转换后缀表达式的过程中进行处理。

下一步工作将集中在:利用四则运算的词法分析进行四则运算表达式的计算;对含有字母未知量的代数表达式进行计算;语法分析;虚拟机等。

posted on 2013-08-16 11:02  unixfy  阅读(2182)  评论(0编辑  收藏  举报

导航