diff options
Diffstat (limited to 'parser.c')
-rw-r--r-- | parser.c | 205 |
1 files changed, 159 insertions, 46 deletions
@@ -1,5 +1,6 @@ #include <ctype.h> #include <stdio.h> +#include <stdlib.h> #include <string.h> #include "common.h" @@ -41,16 +42,21 @@ static struct tok_lookup tok_handlers[] = { }; int -expect(const char *expect, char *actual) { - int min_len = 0; +rtrim(char *string) { + char *old_end = string + strlen(string); + char *w = NULL; - min_len = MIN(strlen(expect), strlen(actual)); + string[strcspn(string, "\r\n")] = '\0'; - if (strncmp(expect, actual, min_len) != 0) { - emit_error("Expected '%s' at start of '%s'\n", expect, actual); - return 1; + /* find first member of right whitespace */ + for (w = old_end; w >= string; w--) { + if (strchr("\t ", *w) == NULL) { + break; + } + *w = '\0'; } - return 0; + + return old_end - w; } char * @@ -61,131 +67,238 @@ eat_whitespace(char *string) { return string; } +char * +get_token_special(char *string, char **rest, char *delims) { + size_t tok_len = 0; + char *ret = NULL; + string = eat_whitespace(string); + tok_len = strcspn(string, delims); + if (tok_len == 0) { + emit_error("unexpected end of string"); + return NULL; + } + if (NULL == (ret = strndup(string, tok_len))) { + emit_error("get_token: "); + perror("strndup"); + return NULL; + } + *rest = string + tok_len; + return ret; +} + +char * +get_token(char *string, char **rest) { + return get_token_special(string, rest, " \t"); +} + +int +expect(const char *expect, char *actual) { + int min_len = 0; + + min_len = MIN(strlen(expect), strlen(actual)); + + if (strncmp(expect, actual, min_len) != 0) { + emit_error("Expected '%s' at start of '%s'\n", expect, actual); + return 1; + } + return 0; +} + int parse_uop(char *str, char *name, enum BINARY (*handler)(enum BINARY, enum BINARY)) { - char *gate_name = str; + char *source_name = NULL; + char *next = NULL; - strtok(gate_name, " "); + if (NULL == (source_name = get_token(str, &next))) { + return 1; + } /* FIXME allow input from other gates, not just inputs */ - struct gate *in = gate_get_input_by_name(gate_name); + struct gate *in = gate_get_input_by_name(source_name); + free(source_name); - gate_add(name, handler, in, in); - return 0; + return gate_add(name, handler, in, in); } int parse_bop(char *str, char *name, enum BINARY (*handler)(enum BINARY, enum BINARY)) { - char *gate_name1 = str; - char *gate_name2 = NULL; + char *source_name1 = NULL; + char *source_name2 = NULL; + char *next = NULL; + struct gate *in1 = NULL; + struct gate *in2 = NULL; + + if (NULL == (source_name1 = get_token(str, &next))) { + return 1; + } - strtok(gate_name1, " "); - gate_name2 = gate_name1 + strlen(gate_name1) + 1; - strtok(gate_name2, " "); + if (NULL == (source_name2 = get_token(next, &next))) { + free(source_name1); + return 1; + } + + if (*next != '\0') { + emit_error("superfluous text \"%s\"\n", next); + free(source_name1); + free(source_name2); + return 1; + } /* FIXME allow input from other gates, not just inputs */ - struct gate *in1 = gate_get_input_by_name(gate_name1); - struct gate *in2 = gate_get_input_by_name(gate_name2); + in1 = gate_get_input_by_name(source_name1); + in2 = gate_get_input_by_name(source_name2); - gate_add(name, handler, in1, in2); - return 0; + free(source_name1); + free(source_name2); + + if (in1 == NULL || in2 == NULL) { + emit_error("Undeclared identifier in source(s) for expression '%s'\n", + name); + return 1; + } + + return gate_add(name, handler, in1, in2); } int parse_op(char *str, char *name) { + char *tok = NULL; + char *next = NULL; int match = 0; size_t i = 0; - strtok(str, " "); + if (NULL == (tok = get_token(str, &next))) { + return 1; + } + match = 0; for (i = 0; i < sizeof(bop_handlers)/sizeof(bop_handlers[0]); i++) { - if (strcmp(bop_handlers[i].str, str) == 0) { + if (strcmp(bop_handlers[i].str, tok) == 0) { match = 1; - if (parse_bop(str+strlen(str)+1, name, bop_handlers[i].handler)) { + if (parse_bop(next, name, bop_handlers[i].handler)) { + free(tok); return 1; } } } for (i = 0; i < sizeof(uop_handlers)/sizeof(uop_handlers[0]); i++) { - if (strcmp(uop_handlers[i].str, str) == 0) { + if (strcmp(uop_handlers[i].str, tok) == 0) { match = 1; - if (parse_uop(str+strlen(str)+1, name, uop_handlers[i].handler)) { + if (parse_uop(next, name, uop_handlers[i].handler)) { + free(tok); return 1; } } } if (match == 0) { - emit_error("Invalid operator \"%s\"\n", str); + emit_error("Invalid operator \"%s\"\n", tok); + free(tok); return 1; } + free(tok); return 0; } int parse_expr(char *str) { const char *expr_sep = ": "; - size_t ident_len = 0; char *ident = NULL; + char *next = NULL; char *op = NULL; - /* FIXME magic constant string */ - ident_len = strspn(str, "abcdefghijklmnopqrstuvwxyz0123456789"); + if (NULL == (ident = get_token_special(str, &next, ": \t"))) { + return 1; + } - if (expect(expr_sep, str + ident_len)) { - return -1; + if (expect(expr_sep, next)) { + free(ident); + return 1; } - str[ident_len] = '\0'; - ident = str; - op = str + ident_len + strlen(expr_sep); + op = next + strlen(expr_sep); return parse_op(op, ident); } int parse_input(char *str) { - strtok(str, " "); - str = eat_whitespace(str); - if (strlen(str) == 0) { + char *ident = NULL; + char *next = NULL; + int ret = 0; + + if (NULL == (ident = get_token(str, &next))) { + return 1; + } + + if (strlen(ident) == 0) { emit_error("input label must not be empty"); + free(ident); return 1; } - emit_info("Add input '%s'\n", str); - return gate_input_add(str); + + if (*next != '\0') { + emit_error("superfluous text after \"%s\" identifier: \"%s\"\n", + ident, next); + free(ident); + return 1; + } + + emit_info("Add input '%s'\n", ident); + ret = gate_input_add(ident); + free(ident); + return ret; } int parse_module(char *str) { - printf("FIXME module name is \"%s\" but modules are not implemented\n", str); + char *mod_name = NULL; + char *next = NULL; + if (NULL == (mod_name = get_token(str, &next))) { + return 1; + } + + if (*next != '\0') { + emit_error("superfluous text following module name"); + free(mod_name); + return 1; + } + + printf("FIXME module name is \"%s\" but modules are not implemented\n", mod_name); + free(mod_name); return 0; } int parse_line(char *line) { size_t i = 0; - char *tok = line; - char *delim = " "; + char *next = NULL; + char *tok = NULL; int match = 0; - line[strcspn(line, "\r\n")] = '\0'; + rtrim(line); if ( strlen(line) == 0 || (strlen(line) == 1 && isspace(line[0]))) { return 0; } - tok = strtok(line, delim); + if (NULL == (tok = get_token(line, &next))) { + return 1; + } match = 0; for (i = 0; i < sizeof(tok_handlers)/sizeof(tok_handlers[0]); i++) { if (strcmp(tok_handlers[i].str, tok) == 0) { match = 1; - if ((tok_handlers[i].handler)(&tok[strlen(tok)+1])) { + if ((tok_handlers[i].handler)(next)) { + free(tok); return 1; } } } + free(tok); + if (match == 0) { emit_error("invalid token \"%s\"", tok); return 1; |