标记算术表达式

Tokenizing an arithmetic expression?

本文关键字:表达式      更新时间:2023-10-16

假设我有:

3.14 + 3 * (7.7/9.8^32.9  )

我需要标记这个输入字符串:

3.14
+
3
*
(
7.7
/
9.8
^
32.9
)

有没有一种方便的方法可以使用 STL 中的字符串流或其他东西来做到这一点,或者我应该一次查看输入 1 个字符并自己做吗?

这取决于你所说的"方便"是什么意思。您可以使用stringstream轻松完成此操作,但我不知道这是否是您正在寻找的:

#include <iostream>
#include <vector>
#include <sstream>
using namespace std;
struct token{
      char c;
      float f;
      bool number;
      token():number(false),c(0){};
};
vector<token> split(string input)
{
   stringstream parser(input);
   vector<token> output;
   while(parser)
   {
      token t;
      if(isalnum(parser.peek()))
         parser >> t.f;
      else
         parser >> t.c;
      t.number = (t.c==0); 
      output.push_back(t);
   }
   output.pop_back();
   return output;
}
int main()
{
    string input = "3.14 + 3 * (7.7/9.8^32.9  )";
    vector<token> tokens = split(input);
    for(unsigned int i=0;i<tokens.size();i++)
    {
       if(tokens[i].number) cout << "number: " << tokens[i].f << endl;
       else cout << "sign: " << tokens[i].c << endl;
    }
}

通常你会使用 Flex/Bison 来生成一个简单的词法分析器和可选的解析器。或者,如果您追求仅编译器解决方案C++ - Boost.Spirit(示例)。我相信,不存在你想要的纯粹STL解决方案。

我赞成 Flex/Bison 方法,所以你用 Flex 编写的分词器将是:

%{
#include <iostream>
#include <memory>
%}

%option prefix="Calc"
%option noyywrap
%option c++
ws      [ t]+
dig     [0-9]
num1    [-+]?{dig}+.?([eE][-+]?{dig}+)?
num2    [-+]?{dig}*.{dig}+([eE][-+]?{dig}+)?
number  {num1}|{num2}
%%
{ws} /* skip */
{number} std::cout << "=> number " << YYText() << 'n';
"+"|"-"|"*"|"/"|"^" std::cout << "=> operator " << YYText() << 'n';
"("|")" std::cout << "=> parenthesis " << YYText() << 'n';
. std::cout << "=> unknown " << YYText() << 'n';
%%
int main( int argc, char **argv )
{
    std::unique_ptr<FlexLexer> lexer(new CalcFlexLexer);
    while(lexer->yylex());
    return 0;
}

和编译命令行:

$ flex calc.l
$ g++-4.7 -std=c++11 -o calc lex.Calc.cc
$ calc
1 + (2e4^3)
=> number 1
=> operator +
=> parenthesis (
=> number 2e4
=> operator ^
=> number 3
=> parenthesis )