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

컴파일러 HW1 - Recursive-Descent for [+-*/]

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

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

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

int perfect = 1;
struct number num;

enum
{
    NULL_T,
    NUMBER,
    PLUS,
    STAR,
    // 빼기(-)
    MINUS,
    // 나누기(/)
    SLASH,
    LP,
    RP,
    END
} token;

struct number expression();
struct number term();
struct number factor();
void get_token();
void error(int i);
void warning();

void main()
{
    struct number result;
    get_token();
    result = expression();
    if (token != END)
        error(3);
    else
    {
        if (perfect == 0)
            warning();

        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;
        get_token();
        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)
            {
                perfect = 0;
                result.val.f = (float)result.val.i;
            }
            if (tmp_term.t == INT)
            {
                perfect = 0;
                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 == SLASH)
    {
        int operation = token;
        get_token();
        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)
            {
                perfect = 0;
                result.val.f = (float)result.val.i;
            }
            if (tmp_factor.t == INT)
            {
                perfect = 0;
                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;
        }
        get_token();
    }
    else if (token == LP)
    {
        get_token();
        result = expression();
        if (token == RP)
            get_token();
        else
            error(2);
    }
    else
    {
        error(1);
    }
    return (result);
}

void get_token()
{
    // next token --> token
    char ch = getchar();
    if (isdigit(ch))
    {
        token = NUMBER;

        // number value --> num
        num.val.i = ch - '0';
        while (isdigit(ch = getchar()))
        {
            num.val.i = num.val.i * 10 + (ch - '0');
        }
        num.t = INT;
        if (ch == '.')
        {
            num.t = FLT;
            num.val.f = num.val.i;
            float fraction = 1.0;
            while (isdigit(ch = getchar()))
            {
                num.val.f = num.val.f + (ch - '0') * (fraction /= 10.0);
            }
        }
        ungetc(ch, stdin);
    }
    else if (ch == '+')
        token = PLUS;
    else if (ch == '*')
        token = STAR;
    else if (ch == '-')
        token = MINUS;
    else if (ch == '/')
        token = SLASH;
    else if (ch == '(')
        token = LP;
    else if (ch == ')')
        token = RP;
    else if (ch == '\n' || ch == EOF)
        token = END;

    else
        token = NULL_T;
}

void error(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 warning()
{
    // 혼합연산
    printf("Warning: Mixed operation with float and int.\n");
}

 

댓글