%{ /* This file is part of GDBM, the GNU data base manager. Copyright (C) 1990-1991, 1993, 2007, 2011, 2013, 2016-2018 Free Software Foundation, Inc. GDBM is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GDBM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GDBM. If not, see . */ #include #include "gdbmtool.h" struct dsegm *dsdef[DS_MAX]; %} %error-verbose %locations %token T_TYPE %token T_OFF "off" T_PAD "pad" T_DEF "define" T_SET "set" T_UNSET "unset" T_BOGUS %token T_CMD "command verb" %token T_NUM "number" %token T_IDENT "identifier" T_WORD "word" %type string %type arg %type arglist arg1list %type def defbody %type deflist %type defid %type kvpair compound value %type kvlist %type slist %union { char *string; struct kvpair *kvpair; struct { struct kvpair *head, *tail; } kvlist; struct { struct slist *head, *tail; } slist; struct gdbmarg *arg; struct gdbmarglist arglist; int num; struct datadef *type; struct dsegm *dsegm; struct { struct dsegm *head, *tail; } dsegmlist; struct command *cmd; } %% input : /* empty */ | stmtlist ; stmtlist : stmt | stmtlist stmt ; stmt : /* empty */ eol { run_last_command (); } | T_CMD arglist eol { if (run_command ($1, &$2) && !interactive ()) exit (EXIT_USAGE); } | set eol | defn eol | T_BOGUS eol { if (interactive ()) { yyclearin; yyerrok; } else YYERROR; } | error { end_def(); } eol { if (interactive ()) { yyclearin; yyerrok; } else YYERROR; } ; eol : '\n' | ';' ; arglist : /* empty */ { gdbmarglist_init (&$$, NULL); } | arg1list ; arg1list : arg { gdbmarglist_init (&$$, $1); } | arg1list arg { gdbmarglist_add (&$1, $2); $$ = $1; } ; arg : string { $$ = gdbmarg_string ($1, &@1); } | compound { $$ = gdbmarg_kvpair ($1, &@1); } ; compound : '{' kvlist '}' { $$ = $2.head; } ; kvlist : kvpair { $$.head = $$.tail = $1; } | kvlist ',' kvpair { $1.tail->next = $3; $1.tail = $3; $$ = $1; } ; kvpair : value | T_IDENT '=' value { $3->key = $1; $$ = $3; } ; value : string { $$ = kvpair_string (&@1, $1); } | '{' slist '}' { $$ = kvpair_list (&@1, $2.head); } ; slist : string { $$.head = $$.tail = slist_new_s ($1); } | slist ',' string { struct slist *s = slist_new_s ($3); slist_insert (&$1.tail, s); $$ = $1; } ; string : T_IDENT | T_WORD ; defn : T_DEF defid { begin_def (); } defbody { end_def (); dsegm_free_list (dsdef[$2]); dsdef[$2] = $4; } ; defbody : '{' deflist optcomma '}' { $$ = $2.head; } | T_TYPE { $$ = dsegm_new_field ($1, NULL, 1); } ; optcomma : /* empty */ | ',' ; defid : T_IDENT { if (strcmp ($1, "key") == 0) $$ = DS_KEY; else if (strcmp ($1, "content") == 0) $$ = DS_CONTENT; else { terror (_("expected \"key\" or \"content\", " "but found \"%s\""), $1); YYERROR; } } ; deflist : def { $$.head = $$.tail = $1; } | deflist ',' def { $1.tail->next = $3; $1.tail = $3; $$ = $1; } ; def : T_TYPE T_IDENT { $$ = dsegm_new_field ($1, $2, 1); } | T_TYPE T_IDENT '[' T_NUM ']' { $$ = dsegm_new_field ($1, $2, $4); } | T_OFF T_NUM { $$ = dsegm_new (FDEF_OFF); $$->v.n = $2; } | T_PAD T_NUM { $$ = dsegm_new (FDEF_PAD); $$->v.n = $2; } ; set : T_SET { variable_print_all (stdout); } | T_SET asgnlist | T_UNSET varlist ; asgnlist : asgn | asgnlist asgn ; asgn : T_IDENT { int t = 1; int rc; char *varname = $1; rc = variable_set (varname, VART_BOOL, &t); if (rc == VAR_ERR_NOTDEF && strncmp (varname, "no", 2) == 0) { t = 0; varname += 2; rc = variable_set (varname, VART_BOOL, &t); } switch (rc) { case VAR_OK: break; case VAR_ERR_NOTDEF: lerror (&@1, _("no such variable: %s"), varname); break; case VAR_ERR_BADTYPE: lerror (&@1, _("%s is not a boolean variable"), varname); break; default: lerror (&@1, _("unexpected error setting %s: %d"), $1, rc); } free($1); } | T_IDENT '=' string { int rc = variable_set ($1, VART_STRING, $3); switch (rc) { case VAR_OK: break; case VAR_ERR_NOTDEF: lerror (&@1, _("no such variable: %s"), $1); break; case VAR_ERR_BADTYPE: lerror (&@1, _("%s: bad variable type"), $1); break; case VAR_ERR_BADVALUE: lerror (&@1, _("%s: value %s is not allowed"), $1, $3); break; default: lerror (&@1, _("unexpected error setting %s: %d"), $1, rc); } free ($1); free ($3); } ; varlist : var | varlist var ; var : T_IDENT { int rc = variable_unset ($1); switch (rc) { case VAR_OK: break; case VAR_ERR_NOTDEF: lerror (&@1, _("no such variable: %s"), $1); break; case VAR_ERR_BADVALUE: lerror (&@1, _("%s: variable cannot be unset"), $1); break; } free($1); } ; %% void terror (const char *fmt, ...) { va_list ap; va_start (ap, fmt); vlerror (&yylloc, fmt, ap); va_end (ap); } int yyerror (char const *s) { terror ("%s", s); return 0; } void gram_trace (int n) { #if GDBMTOOL_DEBUG yydebug = 1; #endif }