본문 바로가기
카테고리 없음

컴파일러 HW1A - (Better) Recursive-Descent for [+-*/]

by swthewhite 2023. 10. 10.
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>

// enum 대신 define 활용
#define NUMBER 256
#define PLUS 257
#define STAR 258
#define LPAREN 259
#define RPAREN 260
#define END 261
#define MINUS 262
#define DIV 263
#define ACC 999

// 숫자 저장용
char yytext[100];

// token의 타입
typedef enum
{
    // 정수 및 실수
    INT,
    FLT
} kind;

struct number
{
    kind t;
    union
    {
        int i;
        float f;
    } val;
};

int token;
struct number num;

struct number expression();
struct number term();
struct number factor();
int yylex();
void yyerror();
void lex_error();
void warning();

void main()
{
    struct number result;
    token = yylex(); // get_token() 대신 yylex() 사용
    result = expression();
    if (token != END)
        yyerror(3);
    else
    {
        if (result.t == INT)
            printf("%d \n", result.val.i);
        else
            printf("%f \n", result.val.f);
    }
}

struct number expression()
{
    struct number result, tmp_term;
    result = term();

    while (token == PLUS || token == MINUS)
    {
        int operation = token;
        token = yylex(); // get_token() 대신 yylex() 사용

        tmp_term = term();

        if (result.t == INT && tmp_term.t == INT)
        {
            if (operation == PLUS)
                result.val.i = result.val.i + tmp_term.val.i;
            else
                result.val.i = result.val.i - tmp_term.val.i;
        }
        else
        {
            if (result.t == INT)
            {
                warning();
                result.val.f = (float)result.val.i;
            }
            if (tmp_term.t == INT)
            {
                warning();
                tmp_term.val.f = (float)tmp_term.val.i;
            }
            if (operation == PLUS)
                result.val.f = result.val.f + tmp_term.val.f;
            else
                result.val.f = result.val.f - tmp_term.val.f;

            result.t = FLT;
        }
    }
    return result;
}

struct number term()
{
    struct number result, tmp_factor;
    result = factor();

    while (token == STAR || token == DIV)
    {
        int operation = token;
        token = yylex(); // get_token() 대신 yylex() 사용

        tmp_factor = factor();

        if (result.t == INT && tmp_factor.t == INT)
        {
            if (operation == STAR)
                result.val.i = result.val.i * tmp_factor.val.i;
            else
                result.val.i = result.val.i / tmp_factor.val.i;
        }
        else
        {
            if (result.t == INT)
            {
                warning();
                result.val.f = (float)result.val.i;
            }
            if (tmp_factor.t == INT)
            {
                warning();
                tmp_factor.val.f = (float)tmp_factor.val.i;
            }
            if (operation == STAR)
                result.val.f = result.val.f * tmp_factor.val.f;
            else
                result.val.f = result.val.f / tmp_factor.val.f;

            result.t = FLT;
        }
    }
    return result;
}

struct number factor()
{
    struct number result;

    if (token == NUMBER)
    {
        if (num.t == INT)
        {
            result.t = INT;
            result.val.i = num.val.i;
        }
        else
        {
            result.t = FLT;
            result.val.f = num.val.f;
        }
        token = yylex(); // get_token() 대신 yylex() 사용
    }
    else if (token == LPAREN)
    {
        token = yylex(); // get_token() 대신 yylex() 사용
        result = expression();
        if (token == RPAREN)
            token = yylex(); // get_token() 대신 yylex() 사용
        else
            yyerror(2);
    }
    else
    {
        yyerror(1);
    }
    return result;
}

// get_token() 대신 yylex()로 수정
int yylex()
{
    static char ch = ' ';

    while (ch == ' ' || ch == '\t')
        ch = getchar();

    int i = 0, isFloat = 0;
    if (isdigit(ch) || ch == '.')
    {
        do
        {
            if (ch == '.')
            {
                if (isFloat) // 이미 한번 .을 발견한 경우
                    lex_error();
                isFloat = 1;
            }
            yytext[i++] = ch;
            ch = getchar();
        } while (isdigit(ch) || ch == '.');

        yytext[i] = 0;

        if (isFloat)
        {
            num.t = FLT;
            num.val.f = atof(yytext);
        }
        else
        {
            num.t = INT;
            num.val.i = atoi(yytext);
        }

        return (NUMBER);
    }
    else if (ch == '+')
    {
        ch = getchar();
        return (PLUS);
    }
    else if (ch == '*')
    {
        ch = getchar();
        return (STAR);
    }
    else if (ch == '(')
    {
        ch = getchar();
        return (LPAREN);
    }
    else if (ch == ')')
    {
        ch = getchar();
        return (RPAREN);
    }
    else if (ch == '-')
    {
        ch = getchar();
        return (MINUS);
    }
    else if (ch == '/')
    {
        ch = getchar();
        return (DIV);
    }
    else if (ch == EOF || ch == '\n')
        return (END);
    else
        lex_error();
}

void yyerror(int i)
{
    switch (i)
    {
    case 1:
        printf("Error: expected a number or a left parenthesis\n");
        break;
    case 2:
        printf("Error: expected a right parenthesis\n");
        break;
    case 3:
        printf("Error: expected end of input\n");
        break;
    }
    exit(1);
}

void lex_error()
{
    printf("Error: bad character\n");
    exit(1);
}

void warning()
{
    // 혼합연산
    printf("Warning: mixed operation with float and int\n");
}

댓글