diff --git a/Makefile b/Makefile index ec15b0ab6ddbd883bc4ca0ed71b4eb9dd5c51c95..5951655ea65fa43749a2c9188f32ea4021833a97 100644 --- a/Makefile +++ b/Makefile @@ -29,7 +29,7 @@ $(MODULES): .PHONY: test test: all LD_LIBRARY_PATH=build \ - ./parse_config test/*/*.conf + valgrind ./parse_config test/*/*.conf LD_LIBRARY_PATH=build HOME=$$(pwd)/test \ valgrind -q --error-exitcode=1 test/test_c diff --git a/moberg_config_parser.h b/moberg_config_parser.h index ab68b415a3cb8af9f6f6c6fb8003c1f7e87405f5..faf48f104eef5d052572a612242c59f372607f8e 100644 --- a/moberg_config_parser.h +++ b/moberg_config_parser.h @@ -1,6 +1,8 @@ #ifndef __MOBERG_CONFIG_PARSER_H__ #define __MOBERG_CONFIG_PARSER_H__ +#include <stdio.h> + struct moberg_config_parser_context; struct moberg_config_parser_token; @@ -14,13 +16,6 @@ enum moberg_config_parser_token_kind { tok_COLON = ':', tok_SEMICOLON = ';', tok_INTEGER = 256, - tok_CONFIG, - tok_MAP, - tok_ANALOGIN, - tok_ANALOGOUT, - tok_DIGITALIN, - tok_DIGITALOUT, - tok_ENCODERIN, tok_IDENT, tok_STRING, }; @@ -46,8 +41,12 @@ int moberg_config_parser_acceptsym( enum moberg_config_parser_token_kind kind, struct moberg_config_parser_token *token); -int moberg_config_parser_peeksym( +int moberg_config_parser_acceptkeyword( struct moberg_config_parser_context *c, - struct moberg_config_parser_token *token); + const char *keyword); + +void moberg_config_parser_failed( + struct moberg_config_parser_context *c, + FILE *f); #endif diff --git a/modules/comedi/comedi.c b/modules/comedi/comedi.c index db2d6642d0d4c83a91e31377e978483630f9abc5..b91b0551326e583153c6636713832440cf397df9 100644 --- a/modules/comedi/comedi.c +++ b/modules/comedi/comedi.c @@ -4,11 +4,24 @@ #include <stdlib.h> #include <string.h> -#define acceptsym moberg_config_parser_acceptsym -#define peeksym moberg_config_parser_peeksym - +typedef enum moberg_config_parser_token_kind kind_t; typedef struct moberg_config_parser_token token_t; typedef struct moberg_config_parser_ident ident_t; +typedef struct moberg_config_parser_context context_t; + +static inline int acceptsym(context_t *c, + kind_t kind, + token_t *token) +{ + return moberg_config_parser_acceptsym(c, kind, token); +} + +static inline int acceptkeyword(context_t *c, + const char *keyword) +{ + return moberg_config_parser_acceptkeyword(c, keyword); +} + static struct moberg_driver_config parse_config( struct moberg_config_parser_context *c) @@ -20,30 +33,46 @@ static struct moberg_driver_config parse_config( for (;;) { if (acceptsym(c, tok_RBRACE, NULL)) { break; - } else if (acceptsym(c, tok_IDENT, &t) || - acceptsym(c, tok_CONFIG, &t)) { - const char *v = t.u.ident.value; - int l = t.u.ident.length; - if (strncmp("device", v, l) == 0) { - printf("DEVICE\n"); - } else if (strncmp("modprobe", v, l) == 0) { - printf("MODPROBE\n"); - } else if (strncmp("config", v, l) == 0) { - printf("CONFIG\n"); + } else if (acceptkeyword(c, "device")) { + token_t device; + if (! acceptsym(c, tok_EQUAL, NULL)) { goto err; } + if (! acceptsym(c, tok_STRING, &device)) { goto err; } + if (! acceptsym(c, tok_SEMICOLON, NULL)) { goto err; } + } else if (acceptkeyword(c, "config")) { + if (! acceptsym(c, tok_EQUAL, NULL)) { goto err; } + if (! acceptsym(c, tok_LBRACKET, NULL)) { goto err; } + for (;;) { + if (acceptsym(c, tok_RBRACKET, NULL)) { + break; + } else if (acceptsym(c, tok_IDENT, NULL) || + acceptsym(c, tok_STRING, NULL)) { + } else { + goto err; + } } - acceptsym(c, tok_EQUAL, NULL); + if (! acceptsym(c, tok_SEMICOLON, NULL)) { goto err; } + } else if (acceptkeyword(c, "modprobe")) { + if (! acceptsym(c, tok_EQUAL, NULL)) { goto err; } + if (! acceptsym(c, tok_LBRACKET, NULL)) { goto err; } for (;;) { - peeksym(c, &t); - acceptsym(c, t.kind, NULL); - printf("%d\n", t.kind); - if (t.kind == tok_SEMICOLON) { break; } + if (acceptsym(c, tok_RBRACKET, NULL)) { + break; + } else if (acceptsym(c, tok_IDENT, NULL) || + acceptsym(c, tok_STRING, NULL)) { + } else { + goto err; + } } + if (! acceptsym(c, tok_SEMICOLON, NULL)) { goto err; } } else { - break; + goto err; } } printf("PARSE_CONFIG DONE%s\n", __FILE__); return result; + err: + moberg_config_parser_failed(c, stderr); + exit(1); } static struct moberg_driver_map parse_map( @@ -54,14 +83,10 @@ static struct moberg_driver_map parse_map( token_t t; printf("PARSE_MAP %s\n", __FILE__); - if (acceptsym(c, tok_IDENT, &t)) { - if (strncmp("subdevice", t.u.ident.value, t.u.ident.length) != 0) { - goto err; - } - if (! acceptsym(c, tok_LBRACKET, NULL)) { goto err; } - if (! acceptsym(c, tok_INTEGER, &t)) { goto err; } - if (! acceptsym(c, tok_RBRACKET, NULL)) { goto err; } - } + if (! acceptkeyword(c, "subdevice") != 0) { goto err; } + if (! acceptsym(c, tok_LBRACKET, NULL)) { goto err; } + if (! acceptsym(c, tok_INTEGER, &t)) { goto err; } + if (! acceptsym(c, tok_RBRACKET, NULL)) { goto err; } /* const char *buf = context->buf; @@ -72,6 +97,7 @@ static struct moberg_driver_map parse_map( */ return result; err: + moberg_config_parser_failed(c, stderr); exit(1); } diff --git a/parse_config.c b/parse_config.c index cb7194431621cc5e164de1bad17431db23f2e245..f6f465918682802604925a6ffc776ea76a58bb13 100644 --- a/parse_config.c +++ b/parse_config.c @@ -8,21 +8,38 @@ #include <moberg_config_parser.h> #include <moberg_driver.h> -#define token moberg_config_parser_token -#define token_kind moberg_config_parser_token_kind -#define acceptsym moberg_config_parser_acceptsym -#define peeksym moberg_config_parser_peeksym - +typedef enum moberg_config_parser_token_kind kind_t; typedef struct moberg_config_parser_token token_t; typedef struct moberg_config_parser_ident ident_t; +typedef struct moberg_config_parser_context context_t; + +static inline int acceptsym(context_t *c, + kind_t kind, + token_t *token) +{ + return moberg_config_parser_acceptsym(c, kind, token); +} + +static inline int acceptkeyword(context_t *c, + const char *keyword) +{ + return moberg_config_parser_acceptkeyword(c, keyword); +} + +#define MAX_EXPECTED 10 +static char expected_char[256][2]; typedef struct moberg_config_parser_context { char *buf; /* Pointer to data to be parsed */ const char *p; /* current parse location */ token_t token; + struct { + int n; + const char *what[MAX_EXPECTED]; + } expected; } context_t; -static const void nextsym_ident_or_keyword(context_t *c) +static const void nextsym_ident(context_t *c) { c->token.u.ident.length = 1; c->token.u.ident.value = c->p; @@ -44,23 +61,7 @@ static const void nextsym_ident_or_keyword(context_t *c) out: ; const char *v = c->token.u.ident.value; int l = c->token.u.ident.length; - if (strncmp("config", v, l) == 0) { - c->token.kind = tok_CONFIG; - } else if (strncmp("map", v, l) == 0) { - c->token.kind = tok_MAP; - } else if (strncmp("analog_in", v, l) == 0) { - c->token.kind = tok_ANALOGIN; - } else if (strncmp("analog_out", v, l) == 0) { - c->token.kind = tok_ANALOGOUT; - } else if (strncmp("digital_in", v, l) == 0) { - c->token.kind = tok_DIGITALIN; - } else if (strncmp("digital_out", v, l) == 0) { - c->token.kind = tok_DIGITALOUT; - } else if (strncmp("encoder_in", v, l) == 0) { - c->token.kind = tok_ENCODERIN; - } else { - c->token.kind = tok_IDENT; - } + c->token.kind = tok_IDENT; printf("IDENT: %.*s %d\n", l, v, c->token.kind); } @@ -153,7 +154,7 @@ static int nextsym(context_t *c) case 'a'...'z': case 'A'...'Z': case '_': - nextsym_ident_or_keyword(c); + nextsym_ident(c); break; case '0'...'9': nextsym_integer(c); @@ -172,31 +173,100 @@ static int nextsym(context_t *c) } } +static int peeksym(context_t *c, + kind_t kind, + token_t *token) +{ + if (c->token.kind == kind) { + if (token) { + *token = c->token; + } + return 1; + } + return 0; +} + int moberg_config_parser_acceptsym(context_t *c, - enum token_kind kind, + kind_t kind, token_t *token) { if (c->token.kind == kind) { - printf("ACCEPT %d", c->token.kind); + printf("ACCEPT %d %s", c->token.kind, expected_char[kind]); if (token) { *token = c->token; } nextsym(c); + c->expected.n = 0; return 1; } + if (c->expected.n < MAX_EXPECTED) { + const char *what = NULL; + switch (kind) { + case tok_none: break; + case tok_LBRACE: what = "{"; break; + case tok_RBRACE: what = "}"; break; + case tok_LBRACKET: what = "["; break; + case tok_RBRACKET: what = "]"; break; + case tok_EQUAL: what = "="; break; + case tok_COLON: what = ":"; break; + case tok_SEMICOLON: what = "y;"; break; + case tok_INTEGER: what = "<INTEGER>"; break; + case tok_IDENT: what = "<IDENT>"; break; + case tok_STRING: what = "<STRING>"; break; + } + if (what) { + c->expected.what[c->expected.n] = what; + c->expected.n++; + } + } printf("REJECT %d (%d)", kind, c->token.kind); return 0; } -int moberg_config_parser_peeksym(context_t *c, - token_t *token) +int moberg_config_parser_acceptkeyword(context_t *c, + const char *keyword) { - if (token) { - *token = c->token; + token_t t; + if (peeksym(c, tok_IDENT, &t) && + strncmp(keyword, t.u.ident.value, t.u.ident.length) == 0) { + nextsym(c); + c->expected.n = 0; + return 1; } - return *c->p != 0; + if (c->expected.n < MAX_EXPECTED) { + c->expected.what[c->expected.n] = keyword; + c->expected.n++; + } + return 0; } +void moberg_config_parser_failed( + struct moberg_config_parser_context *c, + FILE *f) +{ + fprintf(f, "EXPECTED "); + for (int i = 0 ; i < c->expected.n ; i++) { + fprintf(f, "%s ", c->expected.what[i]); + } + const char *what = ""; + switch (c->token.kind) { + case tok_none: break; + case tok_LBRACE: what = "{"; break; + case tok_RBRACE: what = "}"; break; + case tok_LBRACKET: what = "["; break; + case tok_RBRACKET: what = "]"; break; + case tok_EQUAL: what = "="; break; + case tok_COLON: what = ":"; break; + case tok_SEMICOLON: what = ";"; break; + case tok_INTEGER: what = "<INTEGER>"; break; + case tok_IDENT: what = "<IDENT>"; break; + case tok_STRING: what = "<STRING>"; break; + } + + fprintf(f, "\nGOT %s %s\n", what, c->p); +} + + static int parse_map_range(context_t *c) { token_t low, high; @@ -210,7 +280,8 @@ static int parse_map_range(context_t *c) if (! acceptsym(c, tok_RBRACKET, NULL)) { goto err; } return 1; err: - printf("OOPS"); + moberg_config_parser_failed(c, stderr); + exit(1); return 0; } @@ -218,36 +289,23 @@ static int parse_map(context_t *c, struct moberg_driver *driver) { printf("parsemap"); - struct token t; - if (acceptsym(c, tok_ANALOGIN, &t) || - acceptsym(c, tok_ANALOGOUT, &t) || - acceptsym(c, tok_DIGITALIN, &t) || - acceptsym(c, tok_DIGITALOUT, &t) || - acceptsym(c, tok_ENCODERIN, &t)) { + if (acceptkeyword(c, "analog_in") || + acceptkeyword(c, "analog_out") || + acceptkeyword(c, "digital_in") || + acceptkeyword(c, "digital_out") || + acceptkeyword(c, "encoder_in")) { if (! parse_map_range(c)) { goto err; } if (! acceptsym(c, tok_EQUAL, NULL)) { goto err; } - driver->module.parse_map(c, t.kind); + driver->module.parse_map(c, 0); if (! parse_map_range(c)) { goto err; } if (! acceptsym(c, tok_SEMICOLON, NULL)) { goto err; } - switch (t.kind) { - case tok_ANALOGIN: - - case tok_ANALOGOUT: - - case tok_DIGITALIN: - - case tok_DIGITALOUT: - - case tok_ENCODERIN: - break; - default: - goto err; - } } else { goto err; } return 1; err: + moberg_config_parser_failed(c, stderr); + exit(1); return 0; } @@ -256,12 +314,9 @@ static int parse_device(context_t *c, { if (! acceptsym(c, tok_LBRACE, NULL)) { goto err; } for (;;) { - struct token t; - peeksym(c, &t); - printf("PEEK %d", t.kind); - if (acceptsym(c, tok_CONFIG, NULL)) { + if (acceptkeyword(c, "config")) { driver->module.parse_config(c); - } else if (acceptsym(c, tok_MAP, NULL)) { + } else if (acceptkeyword(c, "map")) { parse_map(c, driver); } else if (acceptsym(c, tok_RBRACE, NULL)) { break; @@ -294,9 +349,7 @@ err: static int parse_config(context_t *c) { for (;;) { - struct token t; - peeksym(c, &t); - printf("PEEK %d", t.kind); + token_t t; if (acceptsym(c, tok_IDENT, &t)) { printf("DRIVER=%.*s\n", t.u.ident.length, t.u.ident.value); if (! parse_driver(c, t.u.ident)) { goto err; } diff --git a/test/a/moberg.conf b/test/a/moberg.conf index 4a3c7c736c7a10c03da26c44fd5282b33e7f5352..81092d1b963d747e1dd5e26d6b6b1849915a2aa8 100644 --- a/test/a/moberg.conf +++ b/test/a/moberg.conf @@ -2,7 +2,7 @@ comedi { config { /* Parsed by parse_config in libmoberg_comedi.so */ device = "/dev/comedi0" ; - modprobe = [ comedi 8255 comedi_fc mite ni_tio ni_tiocmd ni_pcimio ] ; + modprobe = [ comedi "8255" comedi_fc mite ni_tio ni_tiocmd ni_pcimio ] ; config = [ ni_pcimio ] ; } /* Moberg mapping[indices] = {driver specific}[indices] @@ -11,7 +11,7 @@ comedi { map analog_out[0:1] = subdevice[1][0:1] ; map digital_in[0] = subdevice[7][15] ; map digital_in[1] = subdevice[7][2] ; - map digital_out[0:1] = subdevice[7][0:1] route 16 ; + map digital_out[0:1] = subdevice[7] route 16 [0:1]; } serial2002 { config {