数式の評価を原始的に #10

Readerを使って字句の切り出し関数を変更してみる。
切り出し関数そのものよりそれ以外の部分の変更の方が多いような。

...definitions and implementations of Reader
...snip
typedef struct {
    size_t length;
    char *value;
} Token;

#define LEXER_BUFFER_INIT_SIZE 4000
#define LEXER_BUFFER_INCREASE 1000

typedef struct {
    Token token;
    size_t buffer_size;
    char *buffer;
    Reader *reader;
    int internal_prepared_reader;
} Lexer;

void lexer_init(Lexer *lexer);
void lexer_init_with_reader(Lexer *lexer, Reader *reader);
void lexer_fin(Lexer *lexer);
Token *lexer_next_token(Lexer *lexer);

void lexer_init(Lexer *lexer)
{
    Reader *reader = malloc(sizeof(Reader));
    if (reader == NULL) {
        perror("fail to create Lexer default Reader");
        exit(1);
    }
    stdreader_init(reader);
    lexer_init_with_reader(lexer, reader);
    lexer->internal_prepared_reader = 1;
}

void lexer_init_with_reader(Lexer *lexer, Reader *reader)
{
    lexer->buffer = malloc(LEXER_BUFFER_INIT_SIZE);
    if (lexer->buffer == NULL) {
        perror("fail to allocate Lexer internal buffer");
        exit(1);
    }
    lexer->buffer_size = LEXER_BUFFER_INIT_SIZE;
    lexer->reader = reader;
    lexer->internal_prepared_reader = 0;
}

void lexer_fin(Lexer *lexer)
{
    free(lexer->buffer);
    lexer->reader->any.fin(lexer->reader);
    if (lexer->internal_prepared_reader) free(lexer->reader);
}

Token *lexer_next_token(Lexer *lexer)
{
    int c;
    size_t i = 0;

    while ((c = lexer->reader->any.get(lexer->reader)) != EOF) {
        if (isspace(c)) {
            if (i == 0) continue; else break;
        }
        lexer->buffer[i++] = c;
        if (i == lexer->buffer_size) {
            size_t s = lexer->buffer_size + LEXER_BUFFER_INCREASE;
            char *b = realloc(lexer->buffer, s);
            if (b == NULL) return NULL;
            lexer->buffer_size = s;
            lexer->buffer = b;
        }
    }
    lexer->token.length = i;
    lexer->token.value = lexer->buffer;
    return i > 0 ? &lexer->token : NULL;
}

int main(int argc, char *argv[])
{
    Lexer lexer;
    Token *token;
    Reader reader;
    size_t i;

    if (argc > 1) {
        strreader_init(&reader, argv[1]);
        lexer_init_with_reader(&lexer, &reader);
    } else {
        lexer_init(&lexer);
    }
    while ((token = lexer_next_token(&lexer)) != NULL) {
        for (i = 0; i < token->length; i++) putchar(token->value[i]);
        putchar('\n');
    }
    lexer_fin(&lexer);
    return 0;
}