/*      $NetBSD: ntp_parser.y,v 1.20 2024/08/18 20:47:17 christos Exp $ */

/* ntp_parser.y
*
* The parser for the NTP configuration file.
*
* Written By:  Sachin Kamboj
*              University of Delaware
*              Newark, DE 19711
* Copyright (c) 2006
*/

%{
 #ifdef HAVE_CONFIG_H
 # include <config.h>
 #endif

 #include "ntp.h"
 #include "ntpd.h"
 #include "ntp_machine.h"
 #include "ntp_stdlib.h"
 #include "ntp_filegen.h"
 #include "ntp_scanner.h"
 #include "ntp_config.h"
 #include "ntp_crypto.h"
 #include "ntp_calendar.h"

 #include "ntpsim.h"           /* HMS: Do we really want this all the time? */
                               /* SK: It might be a good idea to always
                                  include the simulator code. That way
                                  someone can use the same configuration file
                                  for both the simulator and the daemon
                               */

 #define YYMALLOC      emalloc
 #define YYFREE        free
 #define YYERROR_VERBOSE
 #define YYMAXDEPTH    1000    /* stop the madness sooner */
 void yyerror(const char *msg);

 #ifdef SIM
 #  define ONLY_SIM(a) (a)
 #else
 #  define ONLY_SIM(a) NULL
 #endif
%}

/*
* Enable generation of token names array even without YYDEBUG.
* We access via token_name() defined below.
*/
%token-table

%union {
       char *                  String;
       double                  Double;
       int                     Integer;
       unsigned                U_int;
       gen_fifo *              Generic_fifo;
       attr_val *              Attr_val;
       attr_val_fifo *         Attr_val_fifo;
       int_fifo *              Int_fifo;
       string_fifo *           String_fifo;
       address_node *          Address_node;
       address_fifo *          Address_fifo;
       setvar_node *           Set_var;
       server_info *           Sim_server;
       server_info_fifo *      Sim_server_fifo;
       script_info *           Sim_script;
       script_info_fifo *      Sim_script_fifo;
}

/* TERMINALS (do not appear left of colon) */
%token  <Integer>       T_Abbrev
%token  <Integer>       T_Age
%token  <Integer>       T_All
%token  <Integer>       T_Allan
%token  <Integer>       T_Allpeers
%token  <Integer>       T_Auth
%token  <Integer>       T_Autokey
%token  <Integer>       T_Automax
%token  <Integer>       T_Average
%token  <Integer>       T_Basedate
%token  <Integer>       T_Bclient
%token  <Integer>       T_Bcpollbstep
%token  <Integer>       T_Beacon
%token  <Integer>       T_Broadcast
%token  <Integer>       T_Broadcastclient
%token  <Integer>       T_Broadcastdelay
%token  <Integer>       T_Burst
%token  <Integer>       T_Calibrate
%token  <Integer>       T_Ceiling
%token  <Integer>       T_Checkhash
%token  <Integer>       T_Clockstats
%token  <Integer>       T_Cohort
%token  <Integer>       T_ControlKey
%token  <Integer>       T_Crypto
%token  <Integer>       T_Cryptostats
%token  <Integer>       T_Ctl
%token  <Integer>       T_Day
%token  <Integer>       T_Default
%token  <Integer>       T_Delrestrict
%token  <Integer>       T_Device
%token  <Integer>       T_Digest
%token  <Integer>       T_Disable
%token  <Integer>       T_Discard
%token  <Integer>       T_Dispersion
%token  <Double>        T_Double                /* not a token */
%token  <Integer>       T_Driftfile
%token  <Integer>       T_Drop
%token  <Integer>       T_Dscp
%token  <Integer>       T_Ellipsis      /* "..." not "ellipsis" */
%token  <Integer>       T_Enable
%token  <Integer>       T_End
%token  <Integer>       T_Epeer
%token  <Integer>       T_False
%token  <Integer>       T_File
%token  <Integer>       T_Filegen
%token  <Integer>       T_Filenum
%token  <Integer>       T_Flag1
%token  <Integer>       T_Flag2
%token  <Integer>       T_Flag3
%token  <Integer>       T_Flag4
%token  <Integer>       T_Flake
%token  <Integer>       T_Floor
%token  <Integer>       T_Freq
%token  <Integer>       T_Fudge
%token  <Integer>       T_Fuzz
%token  <Integer>       T_Host
%token  <Integer>       T_Huffpuff
%token  <Integer>       T_Iburst
%token  <Integer>       T_Ident
%token  <Integer>       T_Ignore
%token  <Integer>       T_Ignorehash
%token  <Integer>       T_Incalloc
%token  <Integer>       T_Incmem
%token  <Integer>       T_Initalloc
%token  <Integer>       T_Initmem
%token  <Integer>       T_Includefile
%token  <Integer>       T_Integer               /* not a token */
%token  <Integer>       T_Interface
%token  <Integer>       T_Intrange              /* not a token */
%token  <Integer>       T_Io
%token  <Integer>       T_Ippeerlimit
%token  <Integer>       T_Ipv4
%token  <Integer>       T_Ipv4_flag
%token  <Integer>       T_Ipv6
%token  <Integer>       T_Ipv6_flag
%token  <Integer>       T_Kernel
%token  <Integer>       T_Key
%token  <Integer>       T_Keys
%token  <Integer>       T_Keysdir
%token  <Integer>       T_Kod
%token  <Integer>       T_Leapfile
%token  <Integer>       T_Leapsmearinterval
%token  <Integer>       T_Limited
%token  <Integer>       T_Link
%token  <Integer>       T_Listen
%token  <Integer>       T_Logconfig
%token  <Integer>       T_Logfile
%token  <Integer>       T_Loopstats
%token  <Integer>       T_Lowpriotrap
%token  <Integer>       T_Manycastclient
%token  <Integer>       T_Manycastserver
%token  <Integer>       T_Mask
%token  <Integer>       T_Maxage
%token  <Integer>       T_Maxclock
%token  <Integer>       T_Maxdepth
%token  <Integer>       T_Maxdist
%token  <Integer>       T_Maxmem
%token  <Integer>       T_Maxpoll
%token  <Integer>       T_Mdnstries
%token  <Integer>       T_Mem
%token  <Integer>       T_Memlock
%token  <Integer>       T_Minclock
%token  <Integer>       T_Mindepth
%token  <Integer>       T_Mindist
%token  <Integer>       T_Minimum
%token  <Integer>       T_Minjitter
%token  <Integer>       T_Minpoll
%token  <Integer>       T_Minsane
%token  <Integer>       T_Mode
%token  <Integer>       T_Mode7
%token  <Integer>       T_Monitor
%token  <Integer>       T_Month
%token  <Integer>       T_Mru
%token  <Integer>       T_Mssntp
%token  <Integer>       T_Multicastclient
%token  <Integer>       T_Nic
%token  <Integer>       T_Nolink
%token  <Integer>       T_Nomodify
%token  <Integer>       T_Nomrulist
%token  <Integer>       T_None
%token  <Integer>       T_Nonvolatile
%token  <Integer>       T_Noepeer
%token  <Integer>       T_Nopeer
%token  <Integer>       T_Noquery
%token  <Integer>       T_Noselect
%token  <Integer>       T_Noserve
%token  <Integer>       T_Notrap
%token  <Integer>       T_Notrust
%token  <Integer>       T_Ntp
%token  <Integer>       T_Ntpport
%token  <Integer>       T_NtpSignDsocket
%token  <Integer>       T_Orphan
%token  <Integer>       T_Orphanwait
%token  <Integer>       T_PCEdigest
%token  <Integer>       T_Panic
%token  <Integer>       T_Peer
%token  <Integer>       T_Peerstats
%token  <Integer>       T_Phone
%token  <Integer>       T_Pid
%token  <Integer>       T_Pidfile
%token  <Integer>       T_Poll
%token  <Integer>       T_PollSkewList
%token  <Integer>       T_Pool
%token  <Integer>       T_Port
%token  <Integer>       T_PpsData
%token  <Integer>       T_Preempt
%token  <Integer>       T_Prefer
%token  <Integer>       T_Protostats
%token  <Integer>       T_Pw
%token  <Integer>       T_Randfile
%token  <Integer>       T_Rawstats
%token  <Integer>       T_Refid
%token  <Integer>       T_Requestkey
%token  <Integer>       T_Reset
%token  <Integer>       T_Restrict
%token  <Integer>       T_Revoke
%token  <Integer>       T_Rlimit
%token  <Integer>       T_Saveconfigdir
%token  <Integer>       T_Server
%token  <Integer>       T_Serverresponse
%token  <Integer>       T_ServerresponseFuzz    /* Not a token */
%token  <Integer>       T_Setvar
%token  <Integer>       T_Source
%token  <Integer>       T_Stacksize
%token  <Integer>       T_Statistics
%token  <Integer>       T_Stats
%token  <Integer>       T_Statsdir
%token  <Integer>       T_Step
%token  <Integer>       T_Stepback
%token  <Integer>       T_Stepfwd
%token  <Integer>       T_Stepout
%token  <Integer>       T_Stratum
%token  <String>        T_String                /* not a token */
%token  <Integer>       T_Sys
%token  <Integer>       T_Sysstats
%token  <Integer>       T_Tick
%token  <Integer>       T_Time1
%token  <Integer>       T_Time2
%token  <Integer>       T_TimeData
%token  <Integer>       T_Timer
%token  <Integer>       T_Timingstats
%token  <Integer>       T_Tinker
%token  <Integer>       T_Tos
%token  <Integer>       T_Trap
%token  <Integer>       T_True
%token  <Integer>       T_Trustedkey
%token  <Integer>       T_Ttl
%token  <Integer>       T_Type
%token  <Integer>       T_U_int                 /* Not a token */
%token  <Integer>       T_UEcrypto
%token  <Integer>       T_UEcryptonak
%token  <Integer>       T_UEdigest
%token  <Integer>       T_Unconfig
%token  <Integer>       T_Unpeer
%token  <Integer>       T_Version
%token  <Integer>       T_WanderThreshold       /* Not a token */
%token  <Integer>       T_Week
%token  <Integer>       T_Wildcard
%token  <Integer>       T_Xleave
%token  <Integer>       T_Xmtnonce
%token  <Integer>       T_Year
%token  <Integer>       T_Flag                  /* Not a token */
%token  <Integer>       T_EOC


/* NTP Simulator Tokens */
%token  <Integer>       T_Simulate
%token  <Integer>       T_Beep_Delay
%token  <Integer>       T_Sim_Duration
%token  <Integer>       T_Server_Offset
%token  <Integer>       T_Duration
%token  <Integer>       T_Freq_Offset
%token  <Integer>       T_Wander
%token  <Integer>       T_Jitter
%token  <Integer>       T_Prop_Delay
%token  <Integer>       T_Proc_Delay



/*** NON-TERMINALS ***/
%type   <Integer>       access_control_flag
%type   <Attr_val_fifo> ac_flag_list
%type   <Address_node>  address
%type   <Integer>       address_fam
%type   <Address_fifo>  address_list
%type   <Integer>       basedate
%type   <Integer>       boolean
%type   <Integer>       client_type
%type   <Integer>       counter_set_keyword
%type   <Int_fifo>      counter_set_list
%type   <Attr_val>      crypto_command
%type   <Attr_val_fifo> crypto_command_list
%type   <Integer>       crypto_str_keyword
%type   <Attr_val>      device_item
%type   <Integer>       device_item_path_keyword
%type   <Attr_val_fifo> device_item_list
%type   <Attr_val>      discard_option
%type   <Integer>       discard_option_keyword
%type   <Attr_val_fifo> discard_option_list
%type   <Integer>       enable_disable
%type   <Attr_val>      filegen_option
%type   <Attr_val_fifo> filegen_option_list
%type   <Integer>       filegen_type
%type   <Attr_val>      fudge_factor
%type   <Integer>       fudge_factor_bool_keyword
%type   <Integer>       fudge_factor_dbl_keyword
%type   <Attr_val_fifo> fudge_factor_list
%type   <Attr_val_fifo> integer_list
%type   <Attr_val_fifo> integer_list_range
%type   <Attr_val>      integer_list_range_elt
%type   <Attr_val>      integer_range
%type   <Integer>       nic_rule_action
%type   <Integer>       interface_command
%type   <Integer>       interface_nic
%type   <Address_node>  ip_address
%type   <Integer>       res_ippeerlimit
%type   <Integer>       link_nolink
%type   <Attr_val>      log_config_command
%type   <Attr_val_fifo> log_config_list
%type   <Integer>       misc_cmd_dbl_keyword
%type   <Integer>       misc_cmd_int_keyword
%type   <Integer>       misc_cmd_str_keyword
%type   <Integer>       misc_cmd_str_lcl_keyword
%type   <Attr_val>      mru_option
%type   <Integer>       mru_option_keyword
%type   <Attr_val_fifo> mru_option_list
%type   <Integer>       nic_rule_class
%type   <Double>        number
%type   <Integer>       opt_hash_check
%type   <Attr_val>      option
%type   <Attr_val>      option_flag
%type   <Integer>       option_flag_keyword
%type   <Attr_val_fifo> option_list
%type   <Attr_val>      option_int
%type   <Integer>       option_int_keyword
%type   <Attr_val>      option_str
%type   <Integer>       option_str_keyword
%type   <Attr_val_fifo> pollskew_list
%type   <Attr_val>      pollskew_cycle
%type   <Attr_val>      pollskew_spec
%type   <Integer>       reset_command
%type   <Address_node>  restrict_mask
%type   <Integer>       rlimit_option_keyword
%type   <Attr_val>      rlimit_option
%type   <Attr_val_fifo> rlimit_option_list
%type   <Integer>       stat
%type   <Int_fifo>      stats_list
%type   <String_fifo>   string_list
%type   <Attr_val>      system_option
%type   <Integer>       system_option_flag_keyword
%type   <Integer>       system_option_local_flag_keyword
%type   <Attr_val_fifo> system_option_list
%type   <Integer>       t_default_or_zero
%type   <Integer>       tinker_option_keyword
%type   <Attr_val>      tinker_option
%type   <Attr_val_fifo> tinker_option_list
%type   <Attr_val>      tos_option
%type   <Integer>       tos_option_dbl_keyword
%type   <Integer>       tos_option_int_keyword
%type   <Attr_val_fifo> tos_option_list
%type   <Attr_val>      trap_option
%type   <Attr_val_fifo> trap_option_list
%type   <Integer>       unpeer_keyword
%type   <Set_var>       variable_assign

/* NTP Simulator non-terminals */
%type   <Attr_val>              sim_init_statement
%type   <Attr_val_fifo>         sim_init_statement_list
%type   <Integer>               sim_init_keyword
%type   <Sim_server_fifo>       sim_server_list
%type   <Sim_server>            sim_server
%type   <Double>                sim_server_offset
%type   <Address_node>          sim_server_name
%type   <Sim_script>            sim_act
%type   <Sim_script_fifo>       sim_act_list
%type   <Integer>               sim_act_keyword
%type   <Attr_val_fifo>         sim_act_stmt_list
%type   <Attr_val>              sim_act_stmt

%%

/* ntp.conf
* Configuration File Grammar
* --------------------------
*/

configuration
       :       command_list
       ;

command_list
       :       command_list command T_EOC
       |       command T_EOC
       |       error T_EOC
               {
                       /* I will need to incorporate much more fine grained
                        * error messages. The following should suffice for
                        * the time being.
                        */
                       struct FILE_INFO * ip_ctx = lex_current();
                       msyslog(LOG_ERR,
                               "syntax error in %s line %d, column %d",
                               ip_ctx->fname,
                               ip_ctx->errpos.nline,
                               ip_ctx->errpos.ncol);
               }
       ;

command :       /* NULL STATEMENT */
       |       server_command
       |       unpeer_command
       |       other_mode_command
       |       authentication_command
       |       monitoring_command
       |       access_control_command
       |       orphan_mode_command
       |       fudge_command
       |       rlimit_command
       |       system_option_command
       |       tinker_command
       |       miscellaneous_command
       |       simulate_command
       |       device_command
       ;

/* Server Commands
* ---------------
*/

server_command
       :       client_type address option_list
               {
                       peer_node *my_node;

                       my_node = create_peer_node($1, $2, $3);
                       APPEND_G_FIFO(cfgt.peers, my_node);
               }
       ;

client_type
       :       T_Server
       |       T_Pool
       |       T_Peer
       |       T_Broadcast
       |       T_Manycastclient
       ;

address
       :       ip_address
       |       address_fam T_String
                       { $$ = create_address_node($2, $1); }
       ;

ip_address
       :       T_String
                       { $$ = create_address_node($1, AF_UNSPEC); }
       ;

address_fam
       :       T_Ipv4_flag
                       { $$ = AF_INET; }
       |       T_Ipv6_flag
                       { $$ = AF_INET6; }
       ;

option_list
       :       /* empty list */
                       { $$ = NULL; }
       |       option_list option
               {
                       $$ = $1;
                       APPEND_G_FIFO($$, $2);
               }
       ;

option
       :       option_flag
       |       option_int
       |       option_str
       ;

option_flag
       :       option_flag_keyword
                       { $$ = create_attr_ival(T_Flag, $1); }
       ;

option_flag_keyword
       :       T_Autokey
       |       T_Burst
       |       T_Iburst
       |       T_Noselect
       |       T_Preempt
       |       T_Prefer
       |       T_True
       |       T_Xleave
       |       T_Xmtnonce
       ;

option_int
       :       option_int_keyword T_Integer
                       { $$ = create_attr_ival($1, $2); }
       |       option_int_keyword T_U_int
                       { $$ = create_attr_uval($1, $2); }
       ;

option_int_keyword
       :       T_Key
       |       T_Minpoll
       |       T_Maxpoll
       |       T_Ttl
       |       T_Mode
       |       T_Version
       ;

option_str
       :       option_str_keyword T_String
                       { $$ = create_attr_sval($1, $2); }
       ;

option_str_keyword
       :       T_Ident
       ;


/* unpeer commands
* ---------------
*/

unpeer_command
       :       unpeer_keyword address
               {
                       unpeer_node *my_node;

                       my_node = create_unpeer_node($2);
                       if (my_node)
                               APPEND_G_FIFO(cfgt.unpeers, my_node);
               }
       ;
unpeer_keyword
       :       T_Unconfig
       |       T_Unpeer
       ;


/* Other Modes
* (broadcastclient manycastserver multicastclient)
* ------------------------------------------------
*/

other_mode_command
       :       T_Broadcastclient
                       { cfgt.broadcastclient = 1; }
       |       T_Manycastserver address_list
                       { CONCAT_G_FIFOS(cfgt.manycastserver, $2); }
       |       T_Multicastclient address_list
                       { CONCAT_G_FIFOS(cfgt.multicastclient, $2); }
       |       T_Mdnstries T_Integer
                       { cfgt.mdnstries = $2; }
       ;



/* Authentication Commands
* -----------------------
*/

authentication_command
       :       T_Automax T_Integer
               {
                       attr_val *atrv;

                       atrv = create_attr_ival($1, $2);
                       APPEND_G_FIFO(cfgt.vars, atrv);
               }
       |       T_ControlKey T_Integer
                       { cfgt.auth.control_key = $2; }
       |       T_Crypto crypto_command_list
               {
                       cfgt.auth.cryptosw++;
                       CONCAT_G_FIFOS(cfgt.auth.crypto_cmd_list, $2);
               }
       |       T_Keys T_String
                       { cfgt.auth.keys = $2; }
       |       T_Keysdir T_String
                       { cfgt.auth.keysdir = $2; }
       |       T_Requestkey T_Integer
                       { cfgt.auth.request_key = $2; }
       |       T_Revoke T_Integer
                       { cfgt.auth.revoke = $2; }
       |       T_Trustedkey integer_list_range
               {
                       /* [Bug 948] leaves it open if appending or
                        * replacing the trusted key list is the right
                        * way. In any case, either alternative should
                        * be coded correctly!
                        */
                       DESTROY_G_FIFO(cfgt.auth.trusted_key_list, destroy_attr_val); /* remove for append */
                       CONCAT_G_FIFOS(cfgt.auth.trusted_key_list, $2);
               }
       |       T_NtpSignDsocket T_String
                       { cfgt.auth.ntp_signd_socket = $2; }
       ;

crypto_command_list
       :       /* empty list */
                       { $$ = NULL; }
       |       crypto_command_list crypto_command
               {
                       $$ = $1;
                       APPEND_G_FIFO($$, $2);
               }
       ;

crypto_command
       :       crypto_str_keyword T_String
                       { $$ = create_attr_sval($1, $2); }
       |       T_Revoke T_Integer
               {
                       $$ = NULL;
                       cfgt.auth.revoke = $2;
                       msyslog(LOG_WARNING,
                               "'crypto revoke %d' is deprecated, "
                               "please use 'revoke %d' instead.",
                               cfgt.auth.revoke, cfgt.auth.revoke);
               }
       ;

crypto_str_keyword
       :       T_Host
       |       T_Ident
       |       T_Pw
       |       T_Randfile
       |       T_Digest
       ;


/* Orphan Mode Commands
* --------------------
*/

orphan_mode_command
       :       T_Tos tos_option_list
                       { CONCAT_G_FIFOS(cfgt.orphan_cmds, $2); }
       ;

tos_option_list
       :       tos_option_list tos_option
               {
                       $$ = $1;
                       APPEND_G_FIFO($$, $2);
               }
       |       tos_option
               {
                       $$ = NULL;
                       APPEND_G_FIFO($$, $1);
               }
       ;

tos_option
       :       tos_option_int_keyword T_Integer
                       { $$ = create_attr_dval($1, (double)$2); }
       |       tos_option_dbl_keyword number
                       { $$ = create_attr_dval($1, $2); }
       |       T_Cohort boolean
                       { $$ = create_attr_dval($1, (double)$2); }
       |       basedate
                       { $$ = create_attr_ival(T_Basedate, $1); }
       ;

tos_option_int_keyword
       :       T_Bcpollbstep
       |       T_Beacon
       |       T_Ceiling
       |       T_Floor
       |       T_Maxclock
       |       T_Minclock
       |       T_Minsane
       |       T_Orphan
       |       T_Orphanwait
       ;

tos_option_dbl_keyword
       :       T_Mindist
       |       T_Maxdist
       ;


/* Monitoring Commands
* -------------------
*/

monitoring_command
       :       T_Statistics stats_list
                       { CONCAT_G_FIFOS(cfgt.stats_list, $2); }
       |       T_Statsdir T_String
               {
                       if (lex_from_file()) {
                               cfgt.stats_dir = $2;
                       } else {
                               YYFREE($2);
                               yyerror("statsdir remote configuration ignored");
                       }
               }
       |       T_Filegen stat filegen_option_list
               {
                       filegen_node *fgn;

                       fgn = create_filegen_node($2, $3);
                       APPEND_G_FIFO(cfgt.filegen_opts, fgn);
               }
       ;

stats_list
       :       stats_list stat
               {
                       $$ = $1;
                       APPEND_G_FIFO($$, create_int_node($2));
               }
       |       stat
               {
                       $$ = NULL;
                       APPEND_G_FIFO($$, create_int_node($1));
               }
       ;

stat
       :       T_Clockstats
       |       T_Cryptostats
       |       T_Loopstats
       |       T_Peerstats
       |       T_Rawstats
       |       T_Sysstats
       |       T_Timingstats
       |       T_Protostats
       ;

filegen_option_list
       :       /* empty list */
                       { $$ = NULL; }
       |       filegen_option_list filegen_option
               {
                       $$ = $1;
                       APPEND_G_FIFO($$, $2);
               }
       ;

filegen_option
       :       T_File T_String
               {
                       if (lex_from_file()) {
                               $$ = create_attr_sval($1, $2);
                       } else {
                               $$ = NULL;
                               YYFREE($2);
                               yyerror("filegen file remote config ignored");
                       }
               }
       |       T_Type filegen_type
               {
                       if (lex_from_file()) {
                               $$ = create_attr_ival($1, $2);
                       } else {
                               $$ = NULL;
                               yyerror("filegen type remote config ignored");
                       }
               }
       |       link_nolink
               {
                       const char *err;

                       if (lex_from_file()) {
                               $$ = create_attr_ival(T_Flag, $1);
                       } else {
                               $$ = NULL;
                               if (T_Link == $1)
                                       err = "filegen link remote config ignored";
                               else
                                       err = "filegen nolink remote config ignored";
                               yyerror(err);
                       }
               }
       |       enable_disable
                       { $$ = create_attr_ival(T_Flag, $1); }
       ;

link_nolink
       :       T_Link
       |       T_Nolink
       ;

enable_disable
       :       T_Enable
       |       T_Disable
       ;

filegen_type
       :       T_None
       |       T_Pid
       |       T_Day
       |       T_Week
       |       T_Month
       |       T_Year
       |       T_Age
       ;


/* Access Control Commands
* -----------------------
*/

access_control_command
       :       T_Discard discard_option_list
               {
                       CONCAT_G_FIFOS(cfgt.discard_opts, $2);
               }
       |       T_Mru mru_option_list
               {
                       CONCAT_G_FIFOS(cfgt.mru_opts, $2);
               }
       |       T_Restrict address restrict_mask res_ippeerlimit ac_flag_list
               {
                       restrict_node *rn;

                       rn = create_restrict_node($2, $3, $4, $5, FALSE,
                                                 lex_current()->curpos.nline,
                                                 lex_current()->curpos.ncol);
                       APPEND_G_FIFO(cfgt.restrict_opts, rn);
               }
       |       T_Restrict T_Default res_ippeerlimit ac_flag_list
               {
                       restrict_node *rn;

                       rn = create_restrict_node(NULL, NULL, $3, $4, FALSE,
                                                 lex_current()->curpos.nline,
                                                 lex_current()->curpos.ncol);
                       APPEND_G_FIFO(cfgt.restrict_opts, rn);
               }
       |       T_Restrict T_Ipv4_flag T_Default res_ippeerlimit ac_flag_list
               {
                       restrict_node *rn;

                       rn = create_restrict_node(
                               create_address_node(
                                       estrdup("0.0.0.0"),
                                       AF_INET),
                               create_address_node(
                                       estrdup("0.0.0.0"),
                                       AF_INET),
                               $4, $5, FALSE,
                               lex_current()->curpos.nline,
                               lex_current()->curpos.ncol);
                       APPEND_G_FIFO(cfgt.restrict_opts, rn);
               }
       |       T_Restrict T_Ipv6_flag T_Default res_ippeerlimit ac_flag_list
               {
                       restrict_node *rn;

                       rn = create_restrict_node(
                               create_address_node(
                                       estrdup("::"),
                                       AF_INET6),
                               create_address_node(
                                       estrdup("::"),
                                       AF_INET6),
                               $4, $5, FALSE,
                               lex_current()->curpos.nline,
                               lex_current()->curpos.ncol);
                       APPEND_G_FIFO(cfgt.restrict_opts, rn);
               }
       |       T_Restrict T_Source res_ippeerlimit ac_flag_list
               {
                       restrict_node * rn;

                       APPEND_G_FIFO($4, create_attr_ival($2, 1));
                       rn = create_restrict_node(NULL, NULL, $3, $4, FALSE,
                                                 lex_current()->curpos.nline,
                                                 lex_current()->curpos.ncol);
                       APPEND_G_FIFO(cfgt.restrict_opts, rn);
               }
       |       T_Delrestrict ip_address restrict_mask
               {
                       restrict_node * rn;

                       rn = create_restrict_node($2, $3, -1, NULL, TRUE,
                                                 lex_current()->curpos.nline,
                                                 lex_current()->curpos.ncol);
                       APPEND_G_FIFO(cfgt.restrict_opts, rn);
               }
       |       T_Delrestrict T_Source ip_address
               {
                       restrict_node * rn;
                       attr_val_fifo * avf;

                       avf = NULL;
                       APPEND_G_FIFO(avf, create_attr_ival($2, 1));
                       rn = create_restrict_node($3, NULL, -1, avf, TRUE,
                                                 lex_current()->curpos.nline,
                                                 lex_current()->curpos.ncol);
                       APPEND_G_FIFO(cfgt.restrict_opts, rn);
               }
       ;

restrict_mask
       :       /* no mask is allowed */
                       { $$ = NULL; }
       |       T_Mask ip_address
               {
                       $$ = $2;
               }
       ;

res_ippeerlimit
       :       /* empty ippeerlimit defaults to -1 (unlimited) */
                       { $$ = -1; }
       |       T_Ippeerlimit  T_Integer
               {
                       if (($2 < -1) || ($2 > 100)) {
                               struct FILE_INFO * ip_ctx;

                               ip_ctx = lex_current();
                               msyslog(LOG_ERR,
                                       "Unreasonable ippeerlimit value (%d) in %s line %d, column %d.  Using 0.",
                                       $2,
                                       ip_ctx->fname,
                                       ip_ctx->curpos.nline,
                                       ip_ctx->curpos.ncol);
                               $2 = 0;
                       }
                       $$ = $2;
               }
       ;

ac_flag_list
       :       /* empty list is allowed */
                       { $$ = NULL; }
       |       ac_flag_list access_control_flag
               {
                       attr_val *av;

                       $$ = $1;
                       av = create_attr_ival($2, 1);
                       APPEND_G_FIFO($$, av);
               }
       |       ac_flag_list T_Serverresponse T_Fuzz
               {
                       attr_val *av;

                       $$ = $1;
                       av = create_attr_ival(T_ServerresponseFuzz, 1);
                       APPEND_G_FIFO($$, av);
               }
       ;

access_control_flag
       :       T_Epeer
       |       T_Flake
       |       T_Ignore
       |       T_Kod
       |       T_Limited
       |       T_Lowpriotrap
       |       T_Mssntp
       |       T_Noepeer
       |       T_Nomodify
       |       T_Nomrulist
       |       T_Nopeer
       |       T_Noquery
       |       T_Noserve
       |       T_Notrap
       |       T_Notrust
       |       T_Ntpport
       |       T_Version
       ;

discard_option_list
       :       discard_option_list discard_option
               {
                       $$ = $1;
                       APPEND_G_FIFO($$, $2);
               }
       |       discard_option
               {
                       $$ = NULL;
                       APPEND_G_FIFO($$, $1);
               }
       ;

discard_option
       :       discard_option_keyword T_Integer
                       { $$ = create_attr_ival($1, $2); }
       ;

discard_option_keyword
       :       T_Average
       |       T_Minimum
       |       T_Monitor
       ;

mru_option_list
       :       mru_option_list mru_option
               {
                       $$ = $1;
                       APPEND_G_FIFO($$, $2);
               }
       |       mru_option
               {
                       $$ = NULL;
                       APPEND_G_FIFO($$, $1);
               }
       ;

mru_option
       :       mru_option_keyword T_Integer
                       { $$ = create_attr_ival($1, $2); }
       ;

mru_option_keyword
       :       T_Incalloc
       |       T_Incmem
       |       T_Initalloc
       |       T_Initmem
       |       T_Maxage
       |       T_Maxdepth
       |       T_Maxmem
       |       T_Mindepth
       ;

/* Fudge Commands
* --------------
*/

fudge_command
       :       T_Fudge address fudge_factor_list
               {
                       addr_opts_node *aon;

                       aon = create_addr_opts_node($2, $3);
                       APPEND_G_FIFO(cfgt.fudge, aon);
               }
       ;

fudge_factor_list
       :       fudge_factor_list fudge_factor
               {
                       $$ = $1;
                       APPEND_G_FIFO($$, $2);
               }
       |       fudge_factor
               {
                       $$ = NULL;
                       APPEND_G_FIFO($$, $1);
               }
       ;

fudge_factor
       :       fudge_factor_dbl_keyword number
                       { $$ = create_attr_dval($1, $2); }
       |       fudge_factor_bool_keyword boolean
                       { $$ = create_attr_ival($1, $2); }
       |       T_Stratum T_Integer
               {
                       if ($2 >= 0 && $2 <= 16) {
                               $$ = create_attr_ival($1, $2);
                       } else {
                               $$ = NULL;
                               yyerror("fudge factor: stratum value not in [0..16], ignored");
                       }
               }
       |       T_Abbrev T_String
                       { $$ = create_attr_sval($1, $2); }
       |       T_Refid T_String
                       { $$ = create_attr_sval($1, $2); }
       ;

fudge_factor_dbl_keyword
       :       T_Time1
       |       T_Time2
       |       T_Minjitter
       ;

fudge_factor_bool_keyword
       :       T_Flag1
       |       T_Flag2
       |       T_Flag3
       |       T_Flag4
       ;

/* Device Commands
* --------------
*/

device_command
       :       T_Device address device_item_list
               {
                       addr_opts_node *aon;

                       aon = create_addr_opts_node($2, $3);
                       APPEND_G_FIFO(cfgt.device, aon);
               }
       ;

device_item_list
       :       device_item_list device_item
               {
                       $$ = $1;
                       APPEND_G_FIFO($$, $2);
               }
       |       device_item
               {
                       $$ = NULL;
                       APPEND_G_FIFO($$, $1);
               }
       ;

device_item
       :       device_item_path_keyword T_String
                       { $$ = create_attr_sval($1, $2); }
       ;

device_item_path_keyword
       :       T_TimeData
       |       T_PpsData
       ;

/* rlimit Commands
* ---------------
*/

rlimit_command
       :       T_Rlimit rlimit_option_list
                       { CONCAT_G_FIFOS(cfgt.rlimit, $2); }
       ;

rlimit_option_list
       :       rlimit_option_list rlimit_option
               {
                       $$ = $1;
                       APPEND_G_FIFO($$, $2);
               }
       |       rlimit_option
               {
                       $$ = NULL;
                       APPEND_G_FIFO($$, $1);
               }
       ;

rlimit_option
       :       rlimit_option_keyword T_Integer
                       { $$ = create_attr_ival($1, $2); }
       ;

rlimit_option_keyword
       :       T_Memlock
       |       T_Stacksize
       |       T_Filenum
       ;


/* Command for System Options
* --------------------------
*/

system_option_command
       :       T_Enable system_option_list
                       { CONCAT_G_FIFOS(cfgt.enable_opts, $2); }
       |       T_Disable system_option_list
                       { CONCAT_G_FIFOS(cfgt.disable_opts, $2); }
       ;

system_option_list
       :       system_option_list system_option
               {
                       $$ = $1;
                       APPEND_G_FIFO($$, $2);
               }
       |       system_option
               {
                       $$ = NULL;
                       APPEND_G_FIFO($$, $1);
               }
       ;

system_option
       :       system_option_flag_keyword
                       { $$ = create_attr_ival(T_Flag, $1); }
       |       system_option_local_flag_keyword
               {
                       if (lex_from_file()) {
                               $$ = create_attr_ival(T_Flag, $1);
                       } else {
                               char err_str[128];

                               $$ = NULL;
                               snprintf(err_str, sizeof(err_str),
                                        "enable/disable %s remote configuration ignored",
                                        keyword($1));
                               yyerror(err_str);
                       }
               }
       ;

system_option_flag_keyword
       :       T_Auth
       |       T_Bclient
       |       T_Calibrate
       |       T_Kernel
       |       T_Monitor
       |       T_Ntp
       ;

system_option_local_flag_keyword
       :       T_Mode7
       |       T_PCEdigest
       |       T_Stats
       |       T_UEcrypto
       |       T_UEcryptonak
       |       T_UEdigest
       ;

/* Tinker Commands
* ---------------
*/

tinker_command
       :       T_Tinker tinker_option_list
                       { CONCAT_G_FIFOS(cfgt.tinker, $2); }
       ;

tinker_option_list
       :       tinker_option_list tinker_option
               {
                       $$ = $1;
                       APPEND_G_FIFO($$, $2);
               }
       |       tinker_option
               {
                       $$ = NULL;
                       APPEND_G_FIFO($$, $1);
               }
       ;

tinker_option
       :       tinker_option_keyword number
                       { $$ = create_attr_dval($1, $2); }
       ;

tinker_option_keyword
       :       T_Allan
       |       T_Dispersion
       |       T_Freq
       |       T_Huffpuff
       |       T_Panic
       |       T_Step
       |       T_Stepback
       |       T_Stepfwd
       |       T_Stepout
       |       T_Tick
       ;


/* Miscellaneous Commands
* ----------------------
*/

miscellaneous_command
       :       interface_command
       |       reset_command
       |       misc_cmd_dbl_keyword number
               {
                       attr_val *av;

                       av = create_attr_dval($1, $2);
                       APPEND_G_FIFO(cfgt.vars, av);
               }
       |       misc_cmd_int_keyword T_Integer
               {
                       attr_val *av;

                       av = create_attr_ival($1, $2);
                       APPEND_G_FIFO(cfgt.vars, av);
               }
       |       misc_cmd_str_keyword T_String
               {
                       attr_val *av;

                       av = create_attr_sval($1, $2);
                       APPEND_G_FIFO(cfgt.vars, av);
               }
       |       misc_cmd_str_lcl_keyword T_String
               {
                       char error_text[64];
                       attr_val *av;

                       if (lex_from_file()) {
                               av = create_attr_sval($1, $2);
                               APPEND_G_FIFO(cfgt.vars, av);
                       } else {
                               YYFREE($2);
                               snprintf(error_text, sizeof(error_text),
                                        "%s remote config ignored",
                                        keyword($1));
                               yyerror(error_text);
                       }
               }
       |       T_Includefile T_String command
               {
                       if (!lex_from_file()) {
                               YYFREE($2); /* avoid leak */
                               yyerror("remote includefile ignored");
                               break;
                       }
                       if (lex_level() > MAXINCLUDELEVEL) {
                               fprintf(stderr, "getconfig: Maximum include file level exceeded.\n");
                               msyslog(LOG_ERR, "getconfig: Maximum include file level exceeded.");
                       } else {
                               const char * path = FindConfig($2); /* might return $2! */
                               if (!lex_push_file(path, "r")) {
                                       fprintf(stderr, "getconfig: Couldn't open <%s>\n", path);
                                       msyslog(LOG_ERR, "getconfig: Couldn't open <%s>", path);
                               }
                       }
                       YYFREE($2); /* avoid leak */
               }
       |       T_Leapfile T_String opt_hash_check
               {
                       attr_val *av;

                       av = create_attr_sval($1, $2);
                       av->flag = $3;
                       APPEND_G_FIFO(cfgt.vars, av);
               }
       |       T_End
                       { lex_flush_stack(); }
       |       T_Driftfile drift_parm
                       { /* see drift_parm below for actions */ }
       |       T_Logconfig log_config_list
                       { CONCAT_G_FIFOS(cfgt.logconfig, $2); }
       |       T_Phone string_list
                       { CONCAT_G_FIFOS(cfgt.phone, $2); }
       |       T_PollSkewList pollskew_list
                       { CONCAT_G_FIFOS(cfgt.pollskewlist, $2); }
       |       T_Setvar variable_assign
                       { APPEND_G_FIFO(cfgt.setvar, $2); }
       |       T_Trap ip_address trap_option_list
               {
                       addr_opts_node *aon;

                       aon = create_addr_opts_node($2, $3);
                       APPEND_G_FIFO(cfgt.trap, aon);
               }
       |       T_Ttl integer_list
                       { CONCAT_G_FIFOS(cfgt.ttl, $2); }
       ;

misc_cmd_dbl_keyword
       :       T_Broadcastdelay
       |       T_Nonvolatile
       |       T_Tick
       ;

misc_cmd_int_keyword
       :       T_Dscp
       ;

misc_cmd_int_keyword
       :       T_Leapsmearinterval
               {
#ifndef LEAP_SMEAR
                       yyerror("Built without LEAP_SMEAR support.");
#endif
               }
       ;

opt_hash_check
       :       T_Ignorehash
                       { $$ = FALSE; }
       |       T_Checkhash
                       { $$ = TRUE; }
       |       /*EMPTY*/
                       {  $$ = TRUE; }
       ;

misc_cmd_str_keyword
       :       T_Ident
       ;

misc_cmd_str_lcl_keyword
       :       T_Logfile
       |       T_Pidfile
       |       T_Saveconfigdir
       ;

drift_parm
       :       T_String
               {
                       if (lex_from_file()) {
                               attr_val *av;
                               av = create_attr_sval(T_Driftfile, $1);
                               APPEND_G_FIFO(cfgt.vars, av);
                       } else {
                               YYFREE($1);
                               yyerror("driftfile remote configuration ignored");
                       }
               }
       |       T_String T_Double
               {
                       if (lex_from_file()) {
                               attr_val *av;
                               av = create_attr_sval(T_Driftfile, $1);
                               APPEND_G_FIFO(cfgt.vars, av);
                               av = create_attr_dval(T_WanderThreshold, $2);
                               APPEND_G_FIFO(cfgt.vars, av);
                       msyslog(LOG_WARNING,
                               "'driftfile FILENAME WanderValue' is deprecated, "
                               "please use separate 'driftfile FILENAME' and "
                               "'nonvolatile WanderValue' lines instead.");
                       } else {
                               YYFREE($1);
                               yyerror("driftfile remote configuration ignored");
                       }
               }
       |       /* Null driftfile,  indicated by empty string "" */
               {
                       if (lex_from_file()) {
                               attr_val *av;
                               av = create_attr_sval(T_Driftfile, estrdup(""));
                               APPEND_G_FIFO(cfgt.vars, av);
                       } else {
                               yyerror("driftfile remote configuration ignored");
                       }
               }
       ;

pollskew_list
       :       /* empty */
                       { $$ = NULL; }
       |       pollskew_list pollskew_spec
                       { $$ = append_gen_fifo($1, $2); }
       ;

pollskew_spec
       :       pollskew_cycle T_Integer '|' T_Integer
               {
                       if ($2 < 0 || $4 < 0) {
                               /* bad numbers */
                               yyerror("pollskewlist: skew values must be >=0");
                               destroy_attr_val($1);
                               $1 = NULL;
                       } else if ($1 == NULL) {
                               yyerror("pollskewlist: poll value must be 3-17, inclusive");
                       } else if ($1->attr <= 0) {
                               /* process default range */
                               $1->value.r.first = $2;
                               $1->value.r.last  = $4;
                       } else if ($2 < (1 << ($1->attr - 1)) && $4 < (1 << ($1->attr - 1))) {
                               $1->value.r.first = $2;
                               $1->value.r.last  = $4;
                       } else {
                               yyerror("pollskewlist: randomization limit must be <= half the poll interval");
                               destroy_attr_val($1);
                               $1 = NULL;
                       }
                       $$ = $1;
               }
       ;

pollskew_cycle
       :       T_Integer
               {
                       $$ = ($1 >= NTP_MINPOLL && $1 <= NTP_MAXPOLL)
                               ? create_attr_rval($1, 0, 0)
                               : NULL;
               }
       |       T_Default { $$ = create_attr_rval(-1, 0, 0); }
       ;


variable_assign
       :       T_String '=' T_String t_default_or_zero
                       { $$ = create_setvar_node($1, $3, $4); }
       ;

t_default_or_zero
       :       T_Default
       |       /* empty, no "default" modifier */
                       { $$ = 0; }
       ;

trap_option_list
       :       /* empty list */
                       { $$ = NULL; }
       |       trap_option_list trap_option
               {
                       $$ = $1;
                       APPEND_G_FIFO($$, $2);
               }
       ;

trap_option
       :       T_Port T_Integer
                       { $$ = create_attr_ival($1, $2); }
       |       T_Interface ip_address
               {
                       $$ = create_attr_sval($1, estrdup($2->address));
                       destroy_address_node($2);
               }
       ;

log_config_list
       :       log_config_list log_config_command
               {
                       $$ = $1;
                       APPEND_G_FIFO($$, $2);
               }
       |       log_config_command
               {
                       $$ = NULL;
                       APPEND_G_FIFO($$, $1);
               }
       ;

log_config_command
       :       T_String
               {
                       char    prefix;
                       char *  type;

                       switch ($1[0]) {

                       case '+':
                       case '-':
                       case '=':
                               prefix = $1[0];
                               type = $1 + 1;
                               break;

                       default:
                               prefix = '=';
                               type = $1;
                       }

                       $$ = create_attr_sval(prefix, estrdup(type));
                       YYFREE($1);
               }
       ;

interface_command
       :       interface_nic nic_rule_action nic_rule_class
               {
                       nic_rule_node *nrn;

                       nrn = create_nic_rule_node($3, NULL, $2);
                       APPEND_G_FIFO(cfgt.nic_rules, nrn);
               }
       |       interface_nic nic_rule_action T_String
               {
                       nic_rule_node *nrn;

                       nrn = create_nic_rule_node(0, $3, $2);
                       APPEND_G_FIFO(cfgt.nic_rules, nrn);
               }
       ;

interface_nic
       :       T_Interface
       |       T_Nic
       ;

nic_rule_class
       :       T_All
       |       T_Ipv4
       |       T_Ipv6
       |       T_Wildcard
       ;

nic_rule_action
       :       T_Listen
       |       T_Ignore
       |       T_Drop
       ;

reset_command
       :       T_Reset counter_set_list
                       { CONCAT_G_FIFOS(cfgt.reset_counters, $2); }
       ;

counter_set_list
       :       counter_set_list counter_set_keyword
               {
                       $$ = $1;
                       APPEND_G_FIFO($$, create_int_node($2));
               }
       |       counter_set_keyword
               {
                       $$ = NULL;
                       APPEND_G_FIFO($$, create_int_node($1));
               }
       ;

counter_set_keyword
       :       T_Allpeers
       |       T_Auth
       |       T_Ctl
       |       T_Io
       |       T_Mem
       |       T_Sys
       |       T_Timer
       ;



/* Miscellaneous Rules
* -------------------
*/

integer_list
       :       integer_list T_Integer
               {
                       $$ = $1;
                       APPEND_G_FIFO($$, create_int_node($2));
               }
       |       T_Integer
               {
                       $$ = NULL;
                       APPEND_G_FIFO($$, create_int_node($1));
               }
       ;

integer_list_range
       :       integer_list_range integer_list_range_elt
               {
                       $$ = $1;
                       APPEND_G_FIFO($$, $2);
               }
       |       integer_list_range_elt
               {
                       $$ = NULL;
                       APPEND_G_FIFO($$, $1);
               }
       ;

integer_list_range_elt
       :       T_Integer
                       { $$ = create_attr_ival('i', $1); }
       |       integer_range
       ;

integer_range
       :       '(' T_Integer T_Ellipsis T_Integer ')'
                       { $$ = create_attr_rval('-', $2, $4); }
       ;

string_list
       :       string_list T_String
               {
                       $$ = $1;
                       APPEND_G_FIFO($$, create_string_node($2));
               }
       |       T_String
               {
                       $$ = NULL;
                       APPEND_G_FIFO($$, create_string_node($1));
               }
       ;

address_list
       :       address_list address
               {
                       $$ = $1;
                       APPEND_G_FIFO($$, $2);
               }
       |       address
               {
                       $$ = NULL;
                       APPEND_G_FIFO($$, $1);
               }
       ;

boolean
       :       T_Integer
               {
                       if ($1 != 0 && $1 != 1) {
                               yyerror("Integer value is not boolean (0 or 1). Assuming 1");
                               $$ = 1;
                       } else {
                               $$ = $1;
                       }
               }
       |       T_True  { $$ = 1; }
       |       T_False { $$ = 0; }
       ;

number
       :       T_Integer       { $$ = (double)$1; }
       |       T_Double
       ;

basedate
       :       T_Basedate T_String
                       { $$ = basedate_eval_string($2); YYFREE($2); }

/* Simulator Configuration Commands
* --------------------------------
*/

simulate_command
       :       sim_conf_start '{' sim_init_statement_list sim_server_list '}'
               {
                       sim_node *sn;

                       sn =  create_sim_node($3, $4);
                       APPEND_G_FIFO(cfgt.sim_details, sn);

                       /* Revert from ; to \n for end-of-command */
                       old_config_style = 1;
               }
       ;

/* The following is a terrible hack to get the configuration file to
* treat newlines as whitespace characters within the simulation.
* This is needed because newlines are significant in the rest of the
* configuration file.
*/
sim_conf_start
       :       T_Simulate { old_config_style = 0; }
       ;

sim_init_statement_list
       :       sim_init_statement_list sim_init_statement T_EOC
               {
                       $$ = $1;
                       APPEND_G_FIFO($$, $2);
               }
       |       sim_init_statement T_EOC
               {
                       $$ = NULL;
                       APPEND_G_FIFO($$, $1);
               }
       ;

sim_init_statement
       :       sim_init_keyword '=' number
                       { $$ = create_attr_dval($1, $3); }
       ;

sim_init_keyword
       :       T_Beep_Delay
       |       T_Sim_Duration
       ;

sim_server_list
       :       sim_server_list sim_server
               {
                       $$ = $1;
                       APPEND_G_FIFO($$, $2);
               }
       |       sim_server
               {
                       $$ = NULL;
                       APPEND_G_FIFO($$, $1);
               }
       ;

sim_server
       :       sim_server_name '{' sim_server_offset sim_act_list '}'
                       { $$ = ONLY_SIM(create_sim_server($1, $3, $4)); }
       ;

sim_server_offset
       :       T_Server_Offset '=' number T_EOC
                       { $$ = $3; }
       ;

sim_server_name
       :       T_Server '=' address
                       { $$ = $3; }
       ;

sim_act_list
       :       sim_act_list sim_act
               {
                       $$ = $1;
                       APPEND_G_FIFO($$, $2);
               }
       |       sim_act
               {
                       $$ = NULL;
                       APPEND_G_FIFO($$, $1);
               }
       ;

sim_act
       :       T_Duration '=' number '{' sim_act_stmt_list '}'
                       { $$ = ONLY_SIM(create_sim_script_info($3, $5)); }
       ;

sim_act_stmt_list
       :       sim_act_stmt_list sim_act_stmt T_EOC
               {
                       $$ = $1;
                       APPEND_G_FIFO($$, $2);
               }
       |       sim_act_stmt T_EOC
               {
                       $$ = NULL;
                       APPEND_G_FIFO($$, $1);
               }
       ;

sim_act_stmt
       :       sim_act_keyword '=' number
                       { $$ = create_attr_dval($1, $3); }
       ;

sim_act_keyword
       :       T_Freq_Offset
       |       T_Wander
       |       T_Jitter
       |       T_Prop_Delay
       |       T_Proc_Delay
       ;

%%

void
yyerror(
       const char *msg
       )
{
       int retval;
       struct FILE_INFO * ip_ctx;

       ip_ctx = lex_current();
       ip_ctx->errpos = ip_ctx->tokpos;

       msyslog(LOG_ERR, "line %d column %d %s",
               ip_ctx->errpos.nline, ip_ctx->errpos.ncol, msg);
       if (!lex_from_file()) {
               /* Save the error message in the correct buffer */
               retval = snprintf(remote_config.err_msg + remote_config.err_pos,
                                 sizeof remote_config.err_msg - remote_config.err_pos,
                                 "column %d %s",
                                 ip_ctx->errpos.ncol, msg);

               /* Increment the value of err_pos */
               if (retval > 0)
                       remote_config.err_pos += retval;

               /* Increment the number of errors */
               ++remote_config.no_errors;
       }
}


/*
* token_name - convert T_ token integers to text
*              example: token_name(T_Server) returns "T_Server"
*/
const char *
token_name(
       int token
       )
{
       return yytname[YYTRANSLATE(token)];
}


/* Initial Testing function -- ignore */
#if 0
int main(int argc, char *argv[])
{
       ip_file = FOPEN(argv[1], "r");
       if (!ip_file)
               fprintf(stderr, "ERROR!! Could not open file: %s\n", argv[1]);
       yyparse();
       return 0;
}
#endif