#include #include #include #include /******************************************************************************/ /* */ /* TOKENISER */ /* */ /******************************************************************************/ enum token_type { TOK_NONE, TOK_PAREN_OPEN, TOK_PAREN_CLOSE, TOK_NEWLINE, TOK_EOF, TOK_FUN, TOK_END, TOK_IDENT, TOK_LITERAL_INT }; struct token { enum token_type type; char* str; }; int ch; char* buf; int buf_len; struct token* tokens; int token_len; int isidentch(int c) { return isalnum(c) || c == '_'; } void next_ch() { ch = getchar(); } void accept_ch() { buf = realloc(buf, ++buf_len); buf[buf_len-1] = (char)ch; } void skip_ws() { //printf("attempting to skip whitespace, next (%d)\n", ch); while(ch == ' ' || ch == '\t') { //printf("skipping ws: (%d)\n", ch); next_ch(); } } void finalise_buf() { buf = realloc(buf, ++buf_len); buf[buf_len-1] = 0; } void reset_buf() { /* warning, memory leaking by design */ buf = 0; buf_len = 0; } void add_token(enum token_type type, char* str) { tokens = realloc(tokens, sizeof(struct token) * (++token_len)); tokens[token_len - 1].type = type; tokens[token_len - 1].str = str; } void tokenise() { enum token_type mode = TOK_NONE; reset_buf(); tokens = 0; token_len = 0; next_ch(); do { printf(">> %c <<\n", ch); switch(mode) { case TOK_NONE: if(ch == '(') { add_token(TOK_PAREN_OPEN, 0); next_ch(); skip_ws(); } else if(ch == ')') { add_token(TOK_PAREN_CLOSE, 0); next_ch(); skip_ws(); } else if(ch == '\n' || ch == '\r') { add_token(TOK_NEWLINE, 0); next_ch(); /* collapse all versions, and multiples to a single token */ while(ch == '\n' || ch == '\r') next_ch(); skip_ws(); } else if(isalpha(ch)) { mode = TOK_IDENT; accept_ch(); next_ch(); } else if(isdigit(ch)) { mode = TOK_LITERAL_INT; accept_ch(); next_ch(); } else { printf("ERROR: unexpected character '%c' (%d)\n", ch, ch); return; } break; case TOK_IDENT: if(isidentch(ch)) { accept_ch(); next_ch(); } else { finalise_buf(); if(strcmp(buf, "fun") == 0) add_token(TOK_FUN, buf); else if(strcmp(buf, "end") == 0) add_token(TOK_END, buf); else add_token(TOK_IDENT, buf); printf("ident: >>%s<<\n", buf); reset_buf(); mode = TOK_NONE; skip_ws(); } break; case TOK_LITERAL_INT: if(isdigit(ch)) { accept_ch(); next_ch(); } else { finalise_buf(); add_token(TOK_LITERAL_INT, buf); printf("int_literal: >>%s<<\n", buf); reset_buf(); mode = TOK_NONE; skip_ws(); } break; default: printf("ERROR: unknown mode\n"); return; } } while(ch != EOF); add_token(TOK_EOF, 0); } /******************************************************************************/ /* */ /* PARSER */ /* */ /******************************************************************************/ int parse_pos; struct node { struct node* childs; int child_count; }; struct token* expect(enum token_type type) { if(type == tokens[parse_pos].type) { ++parse_pos; return &tokens[parse_pos-1]; } else { printf("expected (%d), got (%d)\n", type, tokens[parse_pos].type); exit(-1); } } int is_next_tok(enum token_type type) { return tokens[parse_pos].type == type; } struct node* p_func_call() { char* name = expect(TOK_IDENT)->str; expect(TOK_PAREN_OPEN); expect(TOK_LITERAL_INT); expect(TOK_PAREN_CLOSE); } struct node* p_statement() { struct node* ret; switch(tokens[parse_pos].type) { case TOK_IDENT: ret = p_func_call(); expect(TOK_NEWLINE); break; default: printf("can't parse statement, (%d)\n", tokens[parse_pos].type); exit(-1); } } struct node* p_fun() { expect(TOK_FUN); char* name = expect(TOK_IDENT)->str; expect(TOK_PAREN_OPEN); expect(TOK_PAREN_CLOSE); expect(TOK_NEWLINE); while(!is_next_tok(TOK_END)) { p_statement(); } expect(TOK_END); expect(TOK_NEWLINE); } void parse() { parse_pos = 0; switch(tokens[parse_pos].type) { case TOK_EOF: return; case TOK_FUN: p_fun(); } } /******************************************************************************/ /* */ /* MAIN */ /* */ /******************************************************************************/ void print_tokens() { for(int i = 0; i < token_len; ++i) printf("TOKEN %d %s\n", tokens[i].type, tokens[i].str); } int main() { tokenise(); print_tokens(); parse(); return 0; }