diff options
| -rw-r--r-- | Makefile | 10 | ||||
| -rw-r--r-- | lib.c | 18 | ||||
| -rw-r--r-- | parse.c | 135 | ||||
| -rw-r--r-- | parse.h | 10 |
4 files changed, 137 insertions, 36 deletions
@@ -1,6 +1,8 @@ CFLAGS=-g -Wall -all: test-lexing test-parsing +PROGRAMS=test-lexing test-parsing + +all: $(PROGRAMS) test-lexing: test-lexing.o tokenize.o lib.o gcc -o $@ test-lexing.o tokenize.o lib.o @@ -8,10 +10,10 @@ test-lexing: test-lexing.o tokenize.o lib.o test-parsing: test-parsing.o parse.o tokenize.o lib.o gcc -o $@ test-parsing.o parse.o tokenize.o lib.o -test-parsing: token.h +test-parsing.o: token.h parse.h test-lexing.o: token.h tokenize.o: token.h -parse.o: token.h +parse.o: token.h parse.h clean: - rm -f *.o + rm -f *.[oasi] $(PROGRAMS) @@ -9,17 +9,25 @@ void warn(struct token *token, const char * fmt, ...) { static char buffer[512]; - struct stream *stream; + const char *name; + int pos,line; va_list args; va_start(args, fmt); vsprintf(buffer, fmt, args); va_end(args); - stream = input_streams + token->stream; - fprintf(stderr, "warning: %s:%d: %s\n", - stream->name, token->line, - buffer); + name = "EOF"; + pos = 0; + line = 0; + if (token) { + name = input_streams[token->stream].name; + pos = token->pos; + line = token->line; + } + + fprintf(stderr, "warning: %s:%d:%d: %s\n", + name, line, pos, buffer); } @@ -20,20 +20,34 @@ void show_expression(struct expression *expr) return; switch (expr->type) { - case EXPR_IDENT: - printf("%s", show_token(expr->token)); - break; case EXPR_BINOP: - printf("<"); + printf("< "); show_expression(expr->left); printf(" %s ", show_special(expr->op)); show_expression(expr->right); - printf(">"); + printf(" >"); + break; + case EXPR_PREOP: + printf("( "); + printf(" %s ", show_special(expr->op)); + show_expression(expr->unop); + printf(" )"); break; - case EXPR_UNARY: - printf("("); + case EXPR_POSTOP: + printf("( "); show_expression(expr->unop); - printf(")"); + printf(" %s ", show_special(expr->op)); + printf(" )"); + break; + case EXPR_PRIMARY: + printf("%s", show_token(expr->token)); + break; + case EXPR_DEREF: + printf("< "); + show_expression(expr->deref); + printf("%s", show_special(expr->op)); + printf("%s", show_token(expr->member)); + printf(" >"); break; default: printf("WTF"); @@ -52,35 +66,106 @@ static struct expression *alloc_expression(struct token *token, int type) return expr; } -struct token *cast_expression(struct token *token, struct expression **tree) +struct token *expect(struct token *token, int op) +{ + if (!token || + token->value.type != TOKEN_SPECIAL || + token->value.special != op) { + warn(token, "Expected %s", show_special(op)); + return token; + } + return token->next; +} + +struct token *primary_expression(struct token *token, struct expression **tree) { struct expression *expr = NULL; - if (token) { - switch (token->value.type) { - case TOKEN_IDENT: - expr = alloc_expression(token, EXPR_IDENT); - token = token->next; + switch (token->value.type) { + case TOKEN_IDENT: + case TOKEN_INTEGER: + case TOKEN_FP: + case TOKEN_STRING: + expr = alloc_expression(token, EXPR_PRIMARY); + token = token->next; + break; + + case TOKEN_SPECIAL: + if (token->value.special == '(') { + expr = alloc_expression(token, EXPR_PREOP); + expr->op = '('; + token = parse_expression(token->next, &expr->unop); + token = expect(token, ')'); break; - case TOKEN_SPECIAL: - if (token->value.special == '(') { - expr = alloc_expression(token, EXPR_UNARY); - expr->op = '('; - token = parse_expression(token->next, &expr->unop); - if (!token || token->value.type != TOKEN_SPECIAL || token->value.special != ')') - warn(token, "Expected ')'"); - else - token = token->next; + } + /* Fallthrough */ + default: + warn(token, "Expected primary expression"); + } + *tree = expr; + return token; +} + +struct token *postfix_expression(struct token *token, struct expression **tree) +{ + struct expression *expr = NULL; + + token = primary_expression(token, &expr); + while (expr && token && token->value.type == TOKEN_SPECIAL) { + switch (token->value.special) { + case '[': { /* Array dereference */ + struct expression *array_expr = alloc_expression(token, EXPR_BINOP); + array_expr->op = '['; + array_expr->left = expr; + token = parse_expression(token->next, &array_expr->right); + token = expect(token, ']'); + expr = array_expr; + continue; + } + case SPECIAL_INCREMENT: /* Post-increment */ + case SPECIAL_DECREMENT: { /* Post-decrement */ + struct expression *post = alloc_expression(token, EXPR_POSTOP); + post->op = token->value.special; + post->unop = expr; + expr = post; + token = token->next; + continue; + } + case '.': /* Structure member dereference */ + case SPECIAL_DEREFERENCE: { /* Structure pointer member dereference */ + struct expression *deref = alloc_expression(token, EXPR_DEREF); + deref->op = token->value.special; + deref->deref = expr; + token = token->next; + if (!token || token->value.type != TOKEN_IDENT) { + warn(token, "Expected member name"); break; } - default: - warn(token, "Syntax error"); + deref->member = token; + token = token->next; + expr = deref; + continue; } + + case '(': /* Function call */ + break; + } + break; } *tree = expr; return token; } +struct token *unary_expression(struct token *token, struct expression **tree) +{ + return postfix_expression(token, tree); +} + +struct token *cast_expression(struct token *token, struct expression **tree) +{ + return unary_expression(token, tree); +} + /* Generic left-to-right binop parsing */ struct token *lr_binop_expression(struct token *token, struct expression **tree, struct token *(*inner)(struct token *, struct expression **), ...) @@ -2,9 +2,11 @@ #define PARSE_H enum expression_type { - EXPR_UNARY, + EXPR_PRIMARY, EXPR_BINOP, - EXPR_IDENT, + EXPR_DEREF, + EXPR_PREOP, + EXPR_POSTOP, }; struct expression { @@ -15,6 +17,10 @@ struct expression { struct binop_arg { struct expression *left, *right; }; + struct deref_arg { + struct expression *deref; + struct token *member; + }; }; }; |
