root/usr.bin/menuc/parse.y
/*      $NetBSD: parse.y,v 1.19 2019/06/23 22:48:15 christos Exp $      */

/*
 * Copyright 1997 Piermont Information Systems Inc.
 * All rights reserved.
 *
 * Written by Philip A. Nelson for Piermont Information Systems Inc.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. The name of Piermont Information Systems Inc. may not be used to endorse
 *    or promote products derived from this software without specific prior
 *    written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY PIERMONT INFORMATION SYSTEMS INC. ``AS IS''
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL PIERMONT INFORMATION SYSTEMS INC. BE 
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 
 * THE POSSIBILITY OF SUCH DAMAGE.
 *
 */


%{

#include <stdio.h>
#include "defs.h"

static id_rec *cur_menu;
static optn_info *cur_optn;
#define OPT_NOMENU 0

%}

%union {
        char *s_value;
        int   i_value;
        optn_info *optn_value;
        action a_value;
}


%token <i_value> X Y W H NO BOX SUB HELP MENU NEXT EXIT ACTION ENDWIN OPTION 
%token <i_value> TITLE DEFAULT DISPLAY ERROR EXITSTRING EXPAND ALLOW DYNAMIC
                 MENUS SCROLLABLE SHORTCUT CLEAR MESSAGES ALWAYS SCROLL
                 CONTINUOUS
%token <s_value> STRING NAME CODE INT_CONST CHAR_CONST

%type <s_value> init_code system helpstr text
%type <optn_value> option option_list
%type <i_value> act_opt
%type <a_value> action exitact

%start system

%%

system : init_code menu_list
         { check_defined();
           if (!had_errors)
                   write_menu_file($1);
         }
       ;

init_code : /* empty */ { $$ = ""; }
          | CODE
          ;

menu_list :  /* empty */
          |  menu_list menu_def
          |  menu_list default_def
          |  menu_list initerror_def
          |  menu_list expand_def
          |  menu_list dynamic_def
          |  menu_list msgxlat_def
          ;

dynamic_def : ALLOW DYNAMIC MENUS ';'
                { do_dynamic = 1; }

expand_def : ALLOW EXPAND ';'
                { do_expands = 1; }

msgxlat_def : ALLOW DYNAMIC MESSAGES ';'
                { do_msgxlat = 1; }

initerror_def : ERROR action ';'
                { error_act = $2; }

default_def : DEFAULT
                { cur_menu = &default_menu; }
              opt opt_list ";"

menu_def  :  MENU NAME
                { cur_menu = get_menu ($2);
                  if (cur_menu->info != NULL)
                          yyerror ("Menu %s defined twice", $2);
                  else {
                          cur_menu->info = malloc (sizeof (menu_info));
                          *(cur_menu->info) = default_info;
                  }
                }
             opts ";" expaction dispact option_list exitact helpstr
                { optn_info *t;
                  cur_menu->info->optns = NULL;
                  while ($8 != NULL) {
                          t = $8;
                          $8 = $8->next;
                          t->next = cur_menu->info->optns;
                          cur_menu->info->optns = t;
                          cur_menu->info->numopt++;
                  }
                }
          ;

opts      : /* empty */
          | opt_list
          ;

opt_list  : "," opt
          | opt_list "," opt
          ;

text      : NAME | STRING

opt       : NO EXIT             { cur_menu->info->mopt |= MC_NOEXITOPT; }
          | EXIT                { cur_menu->info->mopt &= ~MC_NOEXITOPT; }
          | NO BOX              { cur_menu->info->mopt |= MC_NOBOX; }
          | BOX                 { cur_menu->info->mopt &= ~MC_NOBOX; }
          | NO SCROLLABLE       { cur_menu->info->mopt &= ~MC_SCROLL; }
          | SCROLLABLE          { cur_menu->info->mopt |= MC_SCROLL; }
          | NO SHORTCUT         { cur_menu->info->mopt |= MC_NOSHORTCUT; }
          | SHORTCUT            { cur_menu->info->mopt &= ~MC_NOSHORTCUT; }
          | NO CLEAR            { cur_menu->info->mopt |= MC_NOCLEAR; }
          | CLEAR               { cur_menu->info->mopt &= ~MC_NOCLEAR; }
          | NO DEFAULT EXIT     { cur_menu->info->mopt &= ~MC_DFLTEXIT; }
          | DEFAULT EXIT        { cur_menu->info->mopt |= MC_DFLTEXIT; }
          | NO ALWAYS SCROLL    { cur_menu->info->mopt &= ~MC_ALWAYS_SCROLL; }
          | ALWAYS SCROLL       { cur_menu->info->mopt |= MC_ALWAYS_SCROLL; }
          | NO SUB MENU         { cur_menu->info->mopt &= ~MC_SUBMENU; }
          | SUB MENU            { cur_menu->info->mopt |= MC_SUBMENU; }
          | CONTINUOUS TITLE    { cur_menu->info->mopt |= MC_CONTINUOUS; }
          | X "=" INT_CONST     { cur_menu->info->x = atoi($3); }
          | Y "=" INT_CONST     { cur_menu->info->y = atoi($3); }
          | W "=" INT_CONST     { cur_menu->info->w = atoi($3); }
          | H "=" INT_CONST     { cur_menu->info->h = atoi($3); }
          | TITLE text          { cur_menu->info->title = $2; }
          | EXITSTRING text     { cur_menu->info->exitstr = $2;
                                  cur_menu->info->mopt &= ~MC_NOEXITOPT; }
          ;

option_list : option
          | option_list option  { $2->next = $1; $$ = $2; }
          ;

option    : OPTION
                { cur_optn = calloc(1, sizeof(*cur_optn));
                  cur_optn->optact.code = "";
                }
            option_legend ","
            elem_list ";"
                { $$ = cur_optn; }
          ;

option_legend : text    { cur_optn->name = $1; }
          | CODE        { cur_optn->name = $1; cur_optn->name_is_code = TRUE;}

elem_list : elem
          | elem_list "," elem
          ;

elem      : NEXT MENU NAME
                { id_rec *t = get_menu ($3);
                  if (cur_optn->menu != OPT_NOMENU)
                          yyerror ("Double sub/next menu definition");
                  else {
                          cur_optn->menu = t->menu_no;
                  }
                }
          | SUB MENU NAME
                { id_rec *t = get_menu ($3);
                  if (cur_optn->menu != OPT_NOMENU)
                          yyerror ("Double sub/next menu definition");
                  else {
                          cur_optn->menu = t->menu_no;
                          cur_optn->issub = TRUE;
                  }
                }
          | action      { cur_optn->optact = $1; }
          | EXIT        { cur_optn->doexit = TRUE; }
          ;

action    : ACTION act_opt CODE
                { $$.code = $3;
                  $$.endwin = $2;
                }
          ;

act_opt   : /* empty */         { $$ = 0; }
          | "(" ENDWIN ")"      { $$ = 1; }
          ;

expaction : /* empty */         { cur_menu->info->expact.code = ""; }
          | EXPAND action ";"   { if (!do_expands) yyerror ("Menu expands "
                                                             "not enabled");
                                  cur_menu->info->expact = $2; }
          ;

dispact   : /* empty */         { cur_menu->info->postact.code = ""; }
          | DISPLAY action ";"  { cur_menu->info->postact = $2; }
          ;


exitact   : /* empty */         { cur_menu->info->exitact.code = ""; }
          | EXIT action ";"     { cur_menu->info->exitact = $2; }
          ;

helpstr   : /* empty */         { cur_menu->info->helpstr = NULL; }
          | HELP CODE ";"       { asprintf(&cur_menu->info->helpstr, "\"%s\"", $2); } 
          | HELP text ";"       { cur_menu->info->helpstr = $2; } 
          ;