Kompilator działań arytmetycznych w C nie wie kiedy sie kończy input

0

Mam taki prosty "kompilator" działań typu mnożenie i dodawanie. Pracuje na getchar, więc powinno sie do niego wrzucać znaki pojedynczo, a na koniec ma wypluć pseudo komendy assemblera. Np dla: [pomiedzy 3 a 4, i 2 a nawiasy jest znak mnozenia gwiazdka, forum go usuwa] (2*((3 * 4) +9)) powinien wypluć:
PUSH 2
PUSH 3
PUSH 4
MULT
PUSH 9
ADD
MULT
PRINT

Niestety tego nie robi. Gdy wklepuje każdy z powyższych znaków pojedynczo (czyli: lewy cudzysłow enter, 2 enter, * enter itp) to dochodze do ostatniego cudzysłowa po którym kompilator powinien wypluć output wyżej. Niestety nie wypluwa nic, jedyny sposób na zakończenie programu tp wstawienie losowego znaku, po którym drukuje "Garbage at the end of file". Możecie mi powiedzieć dlaczego tak sie dzieje? Kod niżej

#include <stdio.h>
#include <stdlib.h>
#define DIGIT 257
#define EoF 256

typedef int Operator;

typedef struct _expression
{
    char type;
    int value;
    struct _expression *left, *right;
    Operator oper;
} Expression;
struct _token { int class; char repr; } Token;
//typedef Token_type Token;
typedef Expression AST_node;
//typedef Token_type *Token;

static int ls_layout_char(int ch) {
    switch (ch)
    {
        case ' ':  case '\t': case '\n': return 1;
        default: return 0;
    }
}
void error(char* error) {
    printf("%s\n",error);
    exit(1);
}
void get_next_token(void) {
    int ch;
    do {
        ch=getchar();
        if(ch<0) {
            Token.class = EoF;
            Token.repr='#';
            return;
        }
    } while(ls_layout_char(ch));
    if('0'<= ch && ch <= '9') Token.class=DIGIT;
    else Token.class=ch;
    Token.repr=ch;
    
}


static void Code_gen_expression(Expression *expr) {
    switch (expr->type)
    {
        case 'D':
            printf("PUSH %d\n", expr->value);
            break;
    
        case 'P':
            Code_gen_expression(expr->left);
            Code_gen_expression(expr->right);
            switch (expr->oper)
            {
                case '+': printf("ADD\n"); break; 
                case '*': printf("MULT\n"); break;
            }
            break;
    }
}

void Process(AST_node *icode) {
    Code_gen_expression(icode);
    printf("PRINT\n");

}
static int Interpret_expression(Expression *expr) {
    switch (expr->type)
    {
        case 'D':
            return expr->value;
            break;
    
        case 'P': {
            int e_left = Interpret_expression(expr->left);
            int e_right=Interpret_expression(expr->right);
            switch (expr->oper)
            {
                case '+': return e_left+e_right;
                case '*': return e_left*e_right;
            }
        }
        break;
    }
}
/*
void Process(AST_node *icode) {
    printf("%d\n", Interpret_expression(icode));
}
*/
static Expression *new_expression() {
    return (Expression*)malloc(sizeof(Expression));
}
static void free_expression(Expression *expr) {
    free((void*) expr);
}
static int Parse_operator(Operator *oper) {
    if(Token.class =='+') {
        *oper='+';
        get_next_token();
        return 1;
    }
    if(Token.class=='*') {
        *oper='*';
        get_next_token();
        return 1;
    }
    return 0;
}
static int Parse_expression(Expression **expr_p) {
    Expression *expr = *expr_p = new_expression();
    if(Token.class==DIGIT) {
        expr->type='D';
        //printf("%d \n", Token.repr-'0');
        expr->value=Token.repr-'0';
        get_next_token();
        return 1;
    }
    if(Token.class=='(') {
        expr->type ='P';
        get_next_token();
        if(!Parse_expression(&expr->left)) error("Missing expression");
        if(!Parse_operator(&expr->oper)) error("Missing operator");
        if(!Parse_expression(&expr->right)) error("Missing expression");
        if(Token.class !=')') error("Missing )");
        get_next_token();
        return 1;    
    }
    free_expression(expr);
    return 0;
}
int Parse_program(AST_node **icode_p) {
    Expression *expr;
    get_next_token();
    if(Parse_expression(&expr)) {
        if(Token.class!=EoF) {
            error("Garbage after end of program\n");
        }
        *icode_p=expr;
        return 1;
    }
    return 0;
}


int main() {

    AST_node *icode;
    if(!Parse_program(&icode)) printf("ERROR");
    Process(icode);
    return 0;
}
0

Oki, to po kolei:

dochodze do ostatniego cudzysłowa po którym kompilator powinien wypluć output wyżej

Dlaczego powinien? Który fragment kodu za to odpowiada?

0

na poczatku funkcja get_next_token czyta po kolei getcharem znaki, dla kazdego znaku przyporzadkowuje odpowiedni "typ": 'D' jeśli to cyfra, jeśli to "(" to typ='P' i czeka na drugi nawias: ")" Jak sie wszystko zgadza to powinien jako drugą funkcjie w mainie wywołać: Process. Funkcja Process wywołuje funkcje code_generation: ona przechodzi przez drzewo AST, sprawdza typ: jeśli to 'D' to drukuje "PUSH liczba" jeśli nie to w zależności od znaku (+, *) powinna drukowac ADD liczba, lub MULT liczba

0

Niestety nie widzę odpowiedzi na moje pytanie: która część kodu odpowiada za funkcję przestań wczytywać dane po napotkaniu ostatniego cudzysłowu? Ale tak konkretnie, bez lania wody.

0

funckcja get_next_token zawiera nieskończoną petle do która trwa dopóki funkcja ls_layout_char zwraca true. ls_layout_char zwraca false (return 1) jesli napotka znak nowej linii ("\n") w takim wypadku powinna sie skonczyc, gdy nacisne enter niewpisujac zadnego znaku: tzn ) enter enter. Niestety tak sie nie dzieje

0

IMO przekombinowałaś z tą Twoją funkcją:

void get_next_token(void) {
    int ch = getchar();
    
    if (ch == '\n') {
        Token.class = EoF;
        Token.repr = '#';
    } else if (ch >= '0' && ch <= '9') {
        Token.class = DIGIT;
        Token.repr = ch;
    } else {
        Token.class = ch;
        Token.repr = ch;
    }
}

Btw, bardziej naturalnym by było, aby ta metoda faktycznie zwracała wczytany token (jako rezultat) - najlepiej w ogóle zapomnij o tym, że istnieją zmienne globalne.

1 użytkowników online, w tym zalogowanych: 0, gości: 1