summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Phillips <david@sighup.nz>2017-12-28 21:59:59 +1300
committerDavid Phillips <david@sighup.nz>2017-12-28 21:59:59 +1300
commit499b193530a8e89223537e7da226fd5b77c04ca6 (patch)
tree2c5e106433869337bd117f1ae657d44ac263eafb
parentb6a3052c3ebde6114ec6166971b3072460c44814 (diff)
downloadhence-499b193530a8e89223537e7da226fd5b77c04ca6.tar.xz
Massive parser clamp-down
-rw-r--r--Makefile2
-rw-r--r--gate.c1
-rw-r--r--parser.c205
-rwxr-xr-xtest/test-duplicate-inputbin18808 -> 20664 bytes
-rwxr-xr-xtest/test-short-keywordbin19008 -> 25032 bytes
-rw-r--r--test/test-short-keyword.c14
6 files changed, 175 insertions, 47 deletions
diff --git a/Makefile b/Makefile
index 3fdfcd2..8c7b6eb 100644
--- a/Makefile
+++ b/Makefile
@@ -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
diff --git a/gate.c b/gate.c
index c196b91..f745143 100644
--- a/gate.c
+++ b/gate.c
@@ -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);
diff --git a/parser.c b/parser.c
index 822441c..b756eae 100644
--- a/parser.c
+++ b/parser.c
@@ -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
index 236c6fc..141d6aa 100755
--- a/test/test-duplicate-input
+++ b/test/test-duplicate-input
Binary files differ
diff --git a/test/test-short-keyword b/test/test-short-keyword
index 39f58dc..17b4858 100755
--- a/test/test-short-keyword
+++ b/test/test-short-keyword
Binary files differ
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) {