Re: Парсер математических выражений

From
Alexander Krotoff ()
To
Alex Astafiev
Date
2002-05-13T20:42:02Z
Area
RU.ALGORITHMS
From: krotoff@such.srcc.msu.su (Alexander Krotoff)

Alex Astafiev <Alex.Astafiev@p16.f228.n5000.z2.fidonet.org> wrote:
 AK>> Здравствуйте все!
 AK>>
 AK>> Хочу написать сабж. Какие грабли могут быть и какими алгоритмами лучше
 AK>> пользоваться?

AA> ==== Begin of вычислитель.txt ====
AA> От: Alexander Tsarev <Alexander.Tsarev@p1.f1061.n5020.z2.fidonet.org>
AA> Тема: Вычислитель
AA> Дата: 1 ноября 1999 г. 5:25

AA> Пpивет Maxim!

AA> 18 Окт 99 08:31, Maxim Razin -> Mark Shevchenko:

 MR>> Есть классический неpекypсивный алгоpитм на двyх стеках.  Устpоен он
 MR>> так:

Это адская смесь нисходящего разборщика со структурами данных
нужными для восходящего. Эту смесь лучше готовить несколько
по-другому:
+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=
From ank Wed Oct 25 18:41:53 2000
From: krotoff@such.srcc.msu.su (Alexander Krotoff)
Subject: Re: Синтаксический разбор мат. выражений
X-Comment-To: "Mike Korablin Jr." <Mike.Korablin.Jr.@p7.f2000.n5025.z2.fidonet.org>
Newsgroups: fido7.ru.algorithms
References: <972479423@p7.f2000.n5025.z2.FIDOnet.ftn>
Organization: Он знал Сашу Бло.
Mike Korablin Jr. <Mike.Korablin.Jr.@p7.f2000.n5025.z2.fidonet.org> wrote:
MKJ> Кто что подскажет по поводу субжа?

#include <algorithm>
#include <stack>
#include <memory>
#include <stdio.h>
#include <ctype.h>

struct Node {
        int op;
        Node *left, *right;
        Node (int op, Node *left=0, Node *right=0):
                op(op), left(left), right(right) {};
};

const int ID = 255;

inline int
bin_precedence (int op)
{
        switch (op) {
        case ',': return 0;
        case '=': return 1;
        case '-':
        case '+': return 2;
        case '*':
        case '/': return 3;
        default:  throw "Incorrect binary operator.";
        }
}

inline bool left_associative (int op) { return op!='='; }
inline bool unary_op (int op) { return op=='-' || op=='+'; }
inline bool primary (int op) { return op>ID; }

static Node *parse_expr (int term);
int lex ();

static Node *
unary_expr ()
{
        int l=lex();
        if (unary_op( l ))
                return new Node( l, unary_expr() );
        else if (l=='(')
                return parse_expr( ')' );
        else if (primary( l ))
                return new Node( l );
        else
                throw "Unexpected operator";
}

typedef stack< Node* > ExprStack;

static Node *
reduce (ExprStack &expr_stack, Node *last_arg, int op)
{
        int prec = op==EOF ? -1: bin_precedence( op );

        while (!expr_stack.empty()) {
                Node *prev = expr_stack.top();

                if (prec > bin_precedence( prev->op )
                 || prec == bin_precedence( prev->op )
                 && !left_associative( op ))
                        break;

                expr_stack.pop();
                prev->right = last_arg;
                last_arg = prev;
        }

        return last_arg;
}

static Node *
parse_expr (int term)
{
        ExprStack expr_stack;
        try {
                Node *last_arg = unary_expr();
                int op;
                while ((op=lex())!=term) {
                        if (op==EOF)
                                throw "Unexpected end of expression.";
                        if (op=='[')
                                last_arg = new Node(
                                        op, last_arg, parse_expr( ']' )
                                );
                        else {
                                last_arg = reduce( expr_stack, last_arg, op );
                                expr_stack.push( new Node( op, last_arg ));
                                last_arg = unary_expr();
                        }
                }
                return reduce( expr_stack, last_arg, EOF );
        } catch (...) {
                while (!expr_stack.empty()) {
                        delete expr_stack.top();
                        expr_stack.pop();
                }
                throw;
        }
}

Node *
parse_expr()
{
        try {
                return parse_expr( EOF );
        } catch (const char *msg) {
                fprintf( stderr, "%s\n", msg );
                return 0;
        }
}

int
lex()
{
        int c;

        do { c = getchar(); } while (c != EOF && isspace( c ));

        if (c==EOF)
                return c;
        else if (isalpha( c ))
                return ID+c;
        else
                return c;
}

void
print_tree (Node *p, int n=0)
{
        for (int i=0; i<n; i++)
                putchar( '\t' );
        if (p->op > ID)
                putchar( p->op-ID );
        else
                putchar( p->op );
        putchar( '\n' );

        if (p->left)
                print_tree( p->left, n+1 );
        if (p->right)
                print_tree( p->right, n+1 );
}

int
main ()
{
        Node *tree = parse_expr();
        if (tree)
                print_tree( tree );
}

--- ifmail v.2.15dev5
 * Origin: Он знал Сашу Бло. (2:5020/400)