X-Git-Url: https://git.draconx.ca/gitweb/cdecl99.git/blobdiff_plain/362559e5c1b4d138305f9edf2c2b7ee1a24a08f6..f5e2e659f116a49afd3b9d9f37553646e62fa4d4:/src/parse.y diff --git a/src/parse.y b/src/parse.y index 70e1878..fdffa40 100644 --- a/src/parse.y +++ b/src/parse.y @@ -16,28 +16,206 @@ * along with this program. If not, see . */ +%parse-param {struct cdecl **out} %define api.pure %error-verbose %locations %{ #include "scan.h" +#include "cdecl.h" + +#define FAIL(msg) do { \ + yyerror(&yylloc, NULL, msg); \ + YYERROR; \ +} while (0) + +#define ALLOC(ptr, size) do { \ + (ptr) = malloc(size); \ + if (!(ptr)) \ + FAIL("failed to allocate memory"); \ +} while (0) + +#define ALLOC_STRUCT(ptr, type, ...) do { \ + ALLOC(ptr, sizeof (type)); \ + *(ptr) = (type) { __VA_ARGS__ }; \ +} while (0) %} +%code requires { +#include +} + %code provides { -void yyerror(const char *); +void yyerror(YYLTYPE *, struct cdecl **, const char *); +int yyparse(struct cdecl **out); } %union { - int foo; + uintmax_t uintval; + char *strval; + struct cdecl_declspec *declspec; + struct cdecl_declarator *declarator; + struct cdecl *decl; +} + +%{ +static void free_declspec(struct cdecl_declspec *x) +{ + struct cdecl_declspec *p; + while (x) { + p = x->next; + free(x->ident); + free(x); + x = p; + } } +static void free_declarator(struct cdecl_declarator *x) +{ + struct cdecl_declarator *p; + while (x) { + p = x->next; + free(x->ident); + free(x); + x = p; + } +} + +void cdecl_free(struct cdecl *decl) +{ + free_declspec(decl->specifiers); + free_declarator(decl->declarators); + free(decl); +} +%} + +%destructor { free($$); } +%destructor { free_declspec($$); } +%destructor { free_declarator($$); } +%destructor { cdecl_free($$); } + +%token T_LEX_ERROR + +%token T_IDENT "identifier" +%token T_SEMICOLON ";" +%token T_ASTERISK "*" +%token T_LPAREN "(" +%token T_RPAREN ")" +%token T_LBRACKET "[" +%token T_RBRACKET "]" +%token T_COMMA "," + +%token T_TYPEDEF "typedef" +%token T_EXTERN "extern" +%token T_STATIC "static" +%token T_AUTO "auto" +%token T_REGISTER "register" + +%token T_INLINE "inline" + +%token T_RESTRICT "restrict" +%token T_VOLATILE "volatile" +%token T_CONST "const" + +%token T_VOID "void" +%token T_CHAR "char" +%token T_SHORT "short" +%token T_INT "int" +%token T_LONG "long" +%token T_FLOAT "float" +%token T_DOUBLE "double" +%token T_SIGNED "signed" +%token T_UNSIGNED "unsigned" +%token T_BOOL "_Bool" +%token T_COMPLEX "_Complex" + +%token T_STRUCT "struct" +%token T_UNION "union" +%token T_ENUM "enum" + +%type declspec_simple +%type declspec declspecs +%type declarator declarators +%type declaration + %% -input: ; +input: declaration { + *out = $1; +}; + +declaration: declspecs declarators T_SEMICOLON { + ALLOC_STRUCT($$, struct cdecl, + .specifiers = $1, + .declarators = $2); +}; + +declspecs: { $$ = NULL; } | declspecs declspec { + $$ = $2; + $$->next = $1; +} + +declarators: declarator | declarator T_COMMA declarators { + $$ = $1; + $$->next = $3; +}; + +declspec_simple: T_VOID { $$ = CDECL_TYPE_VOID; } + | T_CHAR { $$ = CDECL_TYPE_CHAR; } + | T_SHORT { $$ = CDECL_TYPE_SHORT; } + | T_INT { $$ = CDECL_TYPE_INT; } + | T_LONG { $$ = CDECL_TYPE_LONG; } + | T_FLOAT { $$ = CDECL_TYPE_FLOAT; } + | T_DOUBLE { $$ = CDECL_TYPE_DOUBLE; } + | T_SIGNED { $$ = CDECL_TYPE_SIGNED; } + | T_UNSIGNED { $$ = CDECL_TYPE_UNSIGNED; } + | T_BOOL { $$ = CDECL_TYPE_BOOL; } + | T_COMPLEX { $$ = CDECL_TYPE_COMPLEX; } + | T_TYPEDEF { $$ = CDECL_STOR_TYPEDEF; } + | T_EXTERN { $$ = CDECL_STOR_EXTERN; } + | T_STATIC { $$ = CDECL_STOR_STATIC; } + | T_AUTO { $$ = CDECL_STOR_AUTO; } + | T_REGISTER { $$ = CDECL_STOR_REGISTER; } + | T_RESTRICT { $$ = CDECL_QUAL_RESTRICT; } + | T_VOLATILE { $$ = CDECL_QUAL_VOLATILE; } + | T_CONST { $$ = CDECL_QUAL_CONST; } + | T_INLINE { $$ = CDECL_FUNC_INLINE; } + ; + +declspec: declspec_simple { + ALLOC_STRUCT($$, struct cdecl_declspec, .type = $1); +} | T_STRUCT T_IDENT { + ALLOC_STRUCT($$, struct cdecl_declspec, + .type = CDECL_TYPE_STRUCT, + .ident = $2); +} | T_UNION T_IDENT { + ALLOC_STRUCT($$, struct cdecl_declspec, + .type = CDECL_TYPE_UNION, + .ident = $2); +} | T_ENUM T_IDENT { + ALLOC_STRUCT($$, struct cdecl_declspec, + .type = CDECL_TYPE_ENUM, + .ident = $2); +} | T_IDENT { + ALLOC_STRUCT($$, struct cdecl_declspec, + .type = CDECL_TYPE_IDENT, + .ident = $1); +}; + +declarator: T_IDENT { + ALLOC_STRUCT($$, struct cdecl_declarator, + .type = CDECL_DECL_IDENT, + .ident = $1); +} | T_LPAREN declarator T_RPAREN { + $$ = $2; +}; %% -void yyerror(const char *err) +void yyerror(YYLTYPE *loc, struct cdecl **out, const char *err) { + if (strstr(err, "T_LEX_ERROR")) + return; + fprintf(stderr, "%s\n", err); }