Herzlich Willkommen, lieber Gast!
  Sie befinden sich hier:

  Forum » Rätselecke » 1. Guybrush Rätsel

Forum | Hilfe | Team | Links | Impressum | > Suche < | Mitglieder | Registrieren | Einloggen
  Quicklinks: MSDN-Online || STL || clib Reference Grundlagen || Literatur || E-Books || Zubehör || > F.A.Q. < || Downloads   

Autor Thread - Seiten: > 1 <
000
23.10.2003, 20:55 Uhr
Guybrush Threepwood
Gefürchteter Pirat
(Operator)


Hi,

da ich hier schon mehrere Rätsel mit interresse Verfolgt habe, hab ich mir gedacht ich meld mich mal an und stelle auch eins. Hoffentlich gefällt es euch

Alsooo, zu entwickeln ist ein Programm welches die Eingabe einer beliebig langen Rechnung erwartet.
Bsp: 1 + 2 * 3 / 5 + 1 - 10 * 3.54 usw.

Danach soll das Programm diese ausrechen und das Ergebnis ausgeben. Dabei soll natürlich die Punkt vor Strich Reglung beachtet werden.

Gruß
Guybrush
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
001
23.10.2003, 21:06 Uhr
Pablo
Supertux
(Operator)


Also ein Parser: (Achtung nicht von mir, aber ich habe das Programm verändert, ist aber zu lang um zu posten, deshalb nur die Basis)

C++:
#include <iostream>      // Ein-/Ausgabe
#include <string>        // Strings
#include <map>           // map
#include <cctype>        // isalpha() usw.
#include <sstream>

using namespace std;

enum Token_value {
    NAME,        NUMBER,      END,
    PLUS='+',    MINUS='-',   MUL='*', DIV='/',
    PRINT=';',   ASSIGN='=',  LP='(',  RP=')'
};

Token_value curr_tok = PRINT;

double term(bool);
double prim(bool);
double error(const string& s);
Token_value get_token(void);

double expr(bool get)         // Addieren und Substrahieren
{
    double left = term(get);

    for (;;)    // "'forver', siehe unten
        switch (curr_tok) {
            case PLUS:
                left += term(true);
                break;
            case MINUS:
                left -= term(true);
                break;
            default:
                return left;
        }
}

double term(bool get)        // Multipliziere und dividiere
{
    double left = prim(get);

    for (;;)
        switch (curr_tok) {
            case MUL:
                left *= prim(true);
                break;
            case DIV:
                if (double d = prim(true)) {
                    left /= d;
                    break;
                }
                return error("Division durch 0.");
            default:
                return left;
        }
}

double number_value;
string string_value;
double expr(bool);

map<string, double> table;

double prim(bool get)       // behandelt Primaries
{
    if (get)
        get_token();

    switch (curr_tok) {
        case NUMBER:              // Gleitkommakonstante
        {
            double v = number_value;
            get_token();
            return v;
        }
        case NAME:
        {
            double& v = table[string_value];
            if (get_token() == ASSIGN) v = expr(true);
            return v;
        }
        case MINUS:        // Einstelliges Minus
            return -prim(true);
        case LP:
        {
            double e = expr(true);
            if (curr_tok != RP) return error(") erwartet");
            get_token();      // Verschlucke ')'
            return e;
        }
        default:
        return error("primary erwartet");
    }
}

Token_value get_token()
{
    char ch;
    do {    // Überspringe Whitespaces außer '\n'
        if(!cin.get(ch)) return curr_tok = END;
    } while (ch!='\n' && isspace(ch));    
    switch (ch) {
        case 0:
        case ':':
            return curr_tok=END;
        case ';':
        case '\n':
            return curr_tok=PRINT;
        case '*':
        case '/':
        case '+':
        case '-':
        case '(':
        case ')':
        case '=':
             return curr_tok=Token_value(ch);
        case ':':
             return curr_tok=END; //:end oder:exit um das Prog. zu verlassen
        case '0': case '1': case '2': case '3': case '4':
        case '5': case '6': case '7': case '8': case '9':
        case '.':
            cin.putback(ch);
            cin >> number_value;
            return curr_tok=NUMBER;
        default:         // NAME, NAME=, oder Fehler
            if (isalpha(ch)) {
                string_value = ch;
                while (cin.get(ch) && isalnum(ch)) string_value.push_back(ch);
                cin.putback(ch);
                return curr_tok=NAME;
            }
            error("Falsches Token");
            return curr_tok=PRINT;
    }
}

int no_of_errors;

double error(const string& s)
{
    no_of_errors++;
    cerr << "Fehler: " << s << '\n';
    return 1;
}

int main()
{
    table["pi"] = 3.1415926535897932385;  // Vordefinierte Namen einfügen
    table["e"] = 2.7182818284590542354;


    while (cin) {
        get_token();
        if (curr_tok == END) break;
        if (curr_tok == PRINT) continue;
            cout << expr(false) << "\n";
    }

    return no_of_errors;
}


Du kannst sogar Variablen definiere, oder 2+4;8+pi; eingeben.
--
A! Elbereth Gilthoniel!
silivren penna míriel
o menel aglar elenath,
Gilthoniel, A! Elbereth!

Dieser Post wurde am 23.10.2003 um 21:06 Uhr von Pablo Yanez Trujillo editiert.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
002
23.10.2003, 21:14 Uhr
Guybrush Threepwood
Gefürchteter Pirat
(Operator)


Nicht schlecht, ist zumindest sehr viel kürzer und weniger umständlich als meine Überlegungen
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
003
24.10.2003, 06:41 Uhr
(un)wissender
Niveauwart


@Guybrush
Du müßtest noch definieren, welche Operationen erlaubt sind!
--
Wer früher stirbt ist länger tot.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
004
24.10.2003, 10:03 Uhr
Pablo
Supertux
(Operator)


Hier sind nur +, -, * und / erlaubt. Ich habe aber diesen Taschenrechner um ! ~ (für binär Zahlen), ^ als Expontent und andere Sachen erweitert. Aber der Code ist zu lang dafür.
--
A! Elbereth Gilthoniel!
silivren penna míriel
o menel aglar elenath,
Gilthoniel, A! Elbereth!
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
005
24.10.2003, 10:19 Uhr
virtual
Sexiest Bit alive
(Operator)


Naja, da ja nicht gefordert war, alles in C zu schreiben, hier mal ein Lösung, für Linux mit Hilfe des flex und bison
grammar.y

C++:
%{
#define YYSTYPE double
#include <math.h>
#include <stdio.h>
%}

%token  TOKEN_FLOAT
%left   TOKEN_SUB
%left   TOKEN_ADD
%left   TOKEN_DIV
%left   TOKEN_MUL
%left   TOKEN_EXP
%right  TOKEN_LN
%right  TOKEN_SIN
%right  TOKEN_COS
%right  TOKEN_TAN
%token  TOKEN_OPEN
%token  TOKEN_CLOSE
%token  TOKEN_END
%left   TOKEN_NEG

%%

input   : line { }
        | input line { }
line    : expr TOKEN_END { printf("%f\n", $1); }
expr    : TOKEN_FLOAT { $$ = $1; }
        | TOKEN_OPEN expr TOKEN_CLOSE { $$ = $2; }
        | expr TOKEN_ADD expr { $$ = $1 + $3; }
        | expr TOKEN_SUB expr { $$ = $1 - $3; }
        | expr TOKEN_MUL expr { $$ = $1 * $3; }
        | expr TOKEN_DIV expr { $$ = $1 / $3; }
        | expr TOKEN_EXP expr { $$ = pow($1, $3); }
        | TOKEN_LN expr { $$ = log($2); }
        | TOKEN_SIN expr { $$ = sin($2); }
        | TOKEN_COS expr { $$ = cos($2); }
        | TOKEN_TAN expr { $$ = tan($2); }
        | TOKEN_SUB expr %prec TOKEN_NEG { $$ = -$2; }


calc.l

C++:
%option noyywrap
%{
#define YYSTYPE double
#include "grammar.h"
#include <stdio.h>
%}

DIGIT [0-9]
FLOAT {DIGIT}+"."{DIGIT}+
INTEGER {DIGIT}+

%%

{INTEGER}   { yylval = (double)atoi(yytext); return TOKEN_FLOAT; }
{FLOAT}     { yylval = atof(yytext); return TOKEN_FLOAT; }
"sin"       { return TOKEN_SIN; }
"cos"       { return TOKEN_COS; }
"tan"       { return TOKEN_TAN; }
"ln"        { return TOKEN_LN; }
"^"         { return TOKEN_EXP; }
"*"         { return TOKEN_MUL; }
"/"         { return TOKEN_DIV; }
"+"         { return TOKEN_ADD; }
"-"         { return TOKEN_SUB; }
"("         { return TOKEN_OPEN; }
")"         { return TOKEN_CLOSE; }
"\n"        { return TOKEN_END; }
[ \t\r]+    /* Skip whitespace */
.           fprintf(stderr, "Unrecognized character: %s\n", yytext);
        
%%      
        
int yyerror(const char* s)
{      
    fprintf(stderr, "Parser Error: %s\n", s);
}      
        
int main()
{          
    printf("Bitte Ausdrücke eingeben, ENTER führt zur berechnung:\n");
    yyparse(stdin);
}


Makefile

Code:
all : calc

clean :
        rm -f calc *.h *.c *.o

calc : grammar.o calc.o
        gcc -lm -o$@ $^

calc.o : calc.c
        gcc -c -o$@ $<

calc.c : calc.l grammar.h
        flex -o$@ $<

grammar.o : grammar.c grammar.h
        gcc -c -o$@ $<

grammar.c grammar.h : grammar.y
        bison --defines -o$@ $<


Bauen mit

Code:
make


Beispieloutput für die Interessierten:

Code:
108 $ ./calc
Bitte Ausdrücke eingeben, ENTER führt zur berechnung:
sin(1)^2 + cos(1)^2
1.000000
2*3+4        
10.000000
ln(((17)))
2.833213


--
Gruß, virtual
Quote of the Month
Ich eß' nur was ein Gesicht hat (Creme 21)
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
Seiten: > 1 <     [ Rätselecke ]  


ThWBoard 2.73 FloSoft-Edition
© by Paul Baecher & Felix Gonschorek (www.thwboard.de)

Anpassungen des Forums
© by Flo-Soft (www.flo-soft.de)

Sie sind Besucher: