#include #include #include #include #include "common.h" #include "error.h" #include "logic.h" #include "gate.h" int parse_input(char *); int parse_module(char *); int parse_expr(char *); struct tok_lookup { char *str; int (*handler)(char*); }; struct op_lookup { char *str; enum BINARY (*handler)(enum BINARY, enum BINARY); }; static struct op_lookup uop_handlers[] = { {.str = "not", .handler = logic_nand}, }; static struct op_lookup bop_handlers[] = { {.str = "and", .handler = logic_and}, {.str = "or", .handler = logic_or}, {.str = "nand", .handler = logic_nand}, {.str = "nor", .handler = logic_nor}, {.str = "xor", .handler = logic_xor} }; static struct tok_lookup tok_handlers[] = { {.str = "input", .handler = parse_input}, {.str = "module", .handler = parse_module}, {.str = "expr", .handler = parse_expr} }; int rtrim(char *string) { char *old_end = string + strlen(string); char *w = NULL; string[strcspn(string, "\r\n")] = '\0'; /* find first member of right whitespace */ for (w = old_end; w >= string; w--) { if (strchr("\t ", *w) == NULL) { break; } *w = '\0'; } return old_end - w; } char * eat_whitespace(char *string) { while (*string && isspace(*string)) { 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 *source_name = NULL; char *next = NULL; 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(source_name); free(source_name); return gate_add(name, handler, in, in); } int parse_bop(char *str, char *name, enum BINARY (*handler)(enum BINARY, enum BINARY)) { 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; } 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 */ in1 = gate_get_input_by_name(source_name1); in2 = gate_get_input_by_name(source_name2); 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; 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, tok) == 0) { match = 1; 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, tok) == 0) { match = 1; if (parse_uop(next, name, uop_handlers[i].handler)) { free(tok); return 1; } } } if (match == 0) { emit_error("Invalid operator \"%s\"\n", tok); free(tok); return 1; } free(tok); return 0; } int parse_expr(char *str) { const char *expr_sep = ": "; char *ident = NULL; char *next = NULL; char *op = NULL; if (NULL == (ident = get_token_special(str, &next, ": \t"))) { return 1; } if (expect(expr_sep, next)) { free(ident); return 1; } op = next + strlen(expr_sep); return parse_op(op, ident); } int parse_input(char *str) { 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; } 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) { 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 *next = NULL; char *tok = NULL; int match = 0; rtrim(line); if ( strlen(line) == 0 || (strlen(line) == 1 && isspace(line[0]))) { return 0; } 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)(next)) { free(tok); return 1; } } } free(tok); if (match == 0) { emit_error("invalid token \"%s\"", tok); return 1; } return 0; }