diff options
-rw-r--r-- | Makefile | 2 | ||||
-rw-r--r-- | gate.c | 1 | ||||
-rw-r--r-- | parser.c | 205 | ||||
-rwxr-xr-x | test/test-duplicate-input | bin | 18808 -> 20664 bytes | |||
-rwxr-xr-x | test/test-short-keyword | bin | 19008 -> 25032 bytes | |||
-rw-r--r-- | test/test-short-keyword.c | 14 |
6 files changed, 175 insertions, 47 deletions
@@ -1,4 +1,4 @@ -CFLAGS += -std=c99 -D_XOPEN_SOURCE=500 -Wall -Wextra +CFLAGS += -std=c99 -D_XOPEN_SOURCE=500 -D_POSIX_C_SOURCE=200809L -Wall -Wextra all: simulator @@ -151,6 +151,7 @@ void gate_update(void) { for (i = 0; i < gate_count; i++) { g = &gates[i]; + emit_error("Name: '%s'\n", g->name); in1 = g->in1->output; in2 = g->in2->output; g->output = (g->operation)(in1, in2); @@ -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; diff --git a/test/test-duplicate-input b/test/test-duplicate-input Binary files differindex 236c6fc..141d6aa 100755 --- a/test/test-duplicate-input +++ b/test/test-duplicate-input diff --git a/test/test-short-keyword b/test/test-short-keyword Binary files differindex 39f58dc..17b4858 100755 --- a/test/test-short-keyword +++ b/test/test-short-keyword diff --git a/test/test-short-keyword.c b/test/test-short-keyword.c index 50d44d3..226c097 100644 --- a/test/test-short-keyword.c +++ b/test/test-short-keyword.c @@ -7,13 +7,25 @@ #include "parser.h" char *failures[] = { + "input" "input\n", "input \n", + "input aa aa\n", + "module", + " module ", + "\tmodule ", + " moudle \t\n ", }; char *passes[] = { + "input aa", "input a\n", "input aaaaaaaa\n", + "module test", + "module test", + "module test ", + "module test ", + " \tmodule \ttest \t", "\n", "\n\n", "\r", @@ -22,6 +34,8 @@ char *passes[] = { "\n\r", "\n\n\r", "\r\n\r", + "", + "\t" }; int main(void) { |