PageRenderTime 9ms CodeModel.GetById 5ms app.highlight 31ms RepoModel.GetById 1ms app.codeStats 2ms

/radiusd/rewrite.y

#
Happy | 6359 lines | 5568 code | 791 blank | 0 comment | 0 complexity | 746087d6a8925f92c839b6c7df700828 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

   1%{
   2/* This file is part of GNU Radius.
   3   Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
   4   2010, 2013 Free Software Foundation, Inc.
   5
   6   Written by Sergey Poznyakoff
   7  
   8   GNU Radius is free software; you can redistribute it and/or modify
   9   it under the terms of the GNU General Public License as published by
  10   the Free Software Foundation; either version 3 of the License, or
  11   (at your option) any later version.
  12  
  13   GNU Radius is distributed in the hope that it will be useful,
  14   but WITHOUT ANY WARRANTY; without even the implied warranty of
  15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  16   GNU General Public License for more details.
  17  
  18   You should have received a copy of the GNU General Public License
  19   along with GNU Radius.  If not, see <http://www.gnu.org/licenses/>. */
  20
  21#if defined(HAVE_CONFIG_H)
  22# include <config.h>
  23#endif
  24#include <sys/types.h>
  25#include <stdio.h>
  26#include <string.h>
  27#include <ctype.h>
  28#include <errno.h>
  29
  30#include <radiusd.h>
  31#include <setjmp.h>
  32#include <rewrite.h>
  33#ifdef USE_SERVER_GUILE 
  34# include <libguile.h>
  35# include <radius/radscm.h>	
  36#endif
  37        
  38typedef long RWSTYPE;
  39#define RW_MIN(a,b) ((a)<(b)) ? (a) : (b)
  40 
  41/*
  42 * Generalized list structure
  43 */
  44typedef struct rw_list RWLIST;
  45#define RWLIST(type) \
  46        type     *next;\
  47        type     *prev
  48
  49struct rw_list {
  50        RWLIST(RWLIST);
  51};
  52
  53/*
  54 * Generalized object 
  55 */
  56typedef struct object_t OBJECT ;
  57
  58#define OBJ(type) \
  59        RWLIST(type);\
  60        type    *alloc
  61
  62struct object_t {
  63        OBJ(OBJECT);
  64};
  65
  66typedef struct {
  67        size_t   size;        /* Size of an element */
  68        void     (*free)();   /* deallocator */ 
  69        OBJECT   *alloc_list; /* list of allocated elements */
  70} OBUCKET;
  71
  72        
  73
  74/* ************************************************************
  75 * Basic data types
  76 */
  77
  78typedef int stkoff_t;             /* Offset on stack */
  79typedef unsigned int pctr_t;      /* Program counter */
  80
  81#define RW_REG ('z'-'a'+1)
  82
  83typedef struct {
  84        RWSTYPE    reg[RW_REG];       /* Registers */
  85        #define rA reg[0]
  86        char       *sA;               /* String accumulator */
  87        pctr_t     pc;                /* Program counter */  
  88        
  89        RWSTYPE    *stack;            /* Stack+heap space */
  90        int        stacksize;         /* Size of stack */
  91        int        st;                /* Top of stack */
  92        int        sb;                /* Stack base */
  93        int        ht;                /* Top of heap */
  94        
  95        int        nmatch;
  96        regmatch_t *pmatch;
  97
  98        grad_request_t *req;
  99        
 100        jmp_buf    jmp;
 101} RWMACH;
 102
 103typedef void (*INSTR)();       /* program instruction */
 104 
 105/* Compiled regular expression
 106 */
 107typedef struct comp_regex COMP_REGEX;
 108struct comp_regex {
 109        OBJ(COMP_REGEX);
 110        regex_t      regex;    /* compiled regex itself */
 111        int          nmatch;   /* number of \( ... \) groups */
 112};
 113
 114/*
 115 * Binary Operations
 116 */
 117typedef enum {
 118        Eq,
 119        Ne,
 120        Lt,
 121        Le,
 122        Gt,
 123        Ge,
 124        BAnd,
 125        BXor,
 126        BOr,
 127        And,
 128        Or,
 129        Shl,
 130        Shr,
 131        Add,
 132        Sub,
 133        Mul,
 134        Div,
 135        Rem,
 136        Max_opcode
 137} Bopcode;
 138
 139/*
 140 * Unary operations
 141 */
 142typedef enum {
 143        Neg,
 144        Not,
 145        Max_unary
 146} Uopcode;
 147
 148/*
 149 * Matrix types
 150 */
 151typedef enum {
 152        Generic,
 153        Nop,
 154        Enter,
 155        Leave,
 156        Stop,
 157        Constant,
 158        Matchref,
 159        Variable,
 160        Unary,
 161        Binary,
 162        Cond,
 163        Asgn,
 164        Match,
 165        Coercion,
 166        Expression,
 167        Return,
 168        Jump,
 169        Branch,
 170        Target,
 171        Call,
 172        Builtin,
 173        Pop,
 174        Pusha,
 175        Popa,
 176        Attr,
 177        Attr_asgn,
 178        Attr_check,
 179	Attr_delete,
 180        Max_mtxtype
 181} Mtxtype;
 182
 183/*
 184 * Function parameter
 185 */
 186typedef struct parm_t PARAMETER;
 187struct parm_t {
 188        PARAMETER   *prev;     /* Previous parameter */
 189        PARAMETER   *next;     /* Next parameter */
 190        grad_data_type_t    datatype;  /* type */
 191        stkoff_t    offset;    /* Offset on stack */
 192};
 193
 194/*
 195 * Local variable
 196 */
 197typedef struct variable VAR;
 198struct variable {
 199        OBJ(VAR);
 200        VAR       *dcllink;  /* Link to the next variable vithin the
 201                              * same declaration
 202                              */
 203        char      *name;     /* name of the variable */
 204        int       level;     /* nesting level */
 205        int       offset;    /* offset on stack */
 206        grad_data_type_t  datatype;  /* type */
 207        int       constant;  /* true if assigned a constant value */
 208        grad_datum_t     datum;     /* constant value itself */
 209};
 210
 211/*
 212 * Function definition
 213 */
 214typedef struct function_def {
 215        struct function_def *next;
 216        char       *name;        /* Function name */
 217        grad_data_type_t   rettype;      /* Return type */
 218        pctr_t     entry;        /* Code entry */
 219        COMP_REGEX *rx_list;     /* List of compiled regexps */
 220        int        nparm;        /* Number of parameters */
 221        PARAMETER  *parm;        /* List of parameters */
 222        stkoff_t   stack_alloc;  /* required stack allocation */
 223        grad_locus_t      loc;   /* source location where the function
 224                                  * was declared
 225                                  */
 226} FUNCTION;
 227
 228#define STACK_BASE 2
 229
 230/*
 231 * Built-in function
 232 */
 233typedef struct  {
 234        INSTR    handler;        /* Function itself */
 235        char     *name;          /* Function name */
 236        grad_data_type_t rettype;        /* Return type */
 237        char     *parms;         /* coded parameter types */
 238} builtin_t;
 239
 240/*
 241 * Operation matrices
 242 */
 243typedef union mtx MTX;
 244/*
 245 * All matrices contain the following common fields:
 246 *    alloc- link to the previously allocated matrix.
 247 *           It is used at the end of code generation
 248 *           pass to free all allocated matrices.
 249 *    next - link to the next matrix in the subexpression
 250 *    prev - link to the previous matrix in the subexpression
 251 * Additionally, all expression matrices contain the field
 252 * `datatype' which contains the data type for this matrix.
 253 */
 254#if defined(MAINTAINER_MODE)
 255# define COMMON_MTX \
 256        OBJ(MTX);\
 257        int      id;\
 258        grad_locus_t    loc;\
 259        Mtxtype  type;
 260#else
 261# define COMMON_MTX \
 262        OBJ(MTX);\
 263        grad_locus_t    loc;\
 264        Mtxtype  type;
 265#endif
 266        
 267#define COMMON_EXPR_MTX \
 268        COMMON_MTX\
 269        grad_data_type_t datatype;\
 270        MTX      *uplink;\
 271        MTX      *arglink;
 272
 273/*
 274 * Generic matrix: nothing special
 275 * Type: Generic
 276 */
 277typedef struct {
 278        COMMON_EXPR_MTX
 279} GEN_MTX;
 280/*
 281 * Constant matrix
 282 * Type: Constant
 283 */
 284typedef struct {
 285        COMMON_EXPR_MTX
 286        grad_datum_t    datum;     /* Constant value */      
 287} CONST_MTX;
 288/*
 289 * Reference to a previous regexp: corresponds to a \N construct
 290 * Type: Matchref
 291 */
 292typedef struct {
 293        COMMON_EXPR_MTX
 294        int      num;       /* Number of \( ... \) to be referenced */
 295} MATCHREF_MTX;
 296/*
 297 * Reference to a variable
 298 * Type: Variable
 299 */
 300typedef struct {
 301        COMMON_EXPR_MTX
 302        VAR      *var;      /* Variable being referenced */ 
 303} VAR_MTX;
 304/*
 305 * Unary operation matrix
 306 * Type: Unary
 307 */
 308typedef struct {
 309        COMMON_EXPR_MTX
 310        Uopcode  opcode;    /* Operation code */
 311        MTX      *arg;      /* Argument */
 312} UN_MTX;
 313/*
 314 * Binary operation matrix
 315 * Type: Binary
 316 */
 317typedef struct {
 318        COMMON_EXPR_MTX
 319        Bopcode   opcode;   /* Operation code */ 
 320        MTX      *arg[2];   /* Arguments */ 
 321} BIN_MTX;
 322/*
 323 * Assignment matrix
 324 * Type: Asgn
 325 */
 326typedef struct {
 327        COMMON_EXPR_MTX
 328        VAR      *lval;     /* Lvalue */
 329        MTX      *arg;      /* Rvalue */
 330} ASGN_MTX;
 331/*
 332 * Conditional expression matrix
 333 * Type: Cond
 334 */
 335typedef struct {
 336        COMMON_MTX
 337        MTX      *expr;     /* Conditional expression */
 338        MTX      *if_true;  /* Branch if true */
 339        MTX      *if_false; /* Branch if false */ 
 340} COND_MTX;
 341/*
 342 * Regexp match
 343 * Type: Match
 344 */
 345typedef struct {
 346        COMMON_EXPR_MTX
 347        int        negated; /* Is the match negated ? */
 348        MTX        *arg;    /* Argument (lhs) */
 349        COMP_REGEX *rx;     /* Regexp (rhs) */
 350} MATCH_MTX;
 351/*
 352 * Type coercion
 353 * Type: Coerce
 354 */
 355typedef struct {
 356        COMMON_EXPR_MTX
 357        MTX      *arg;      /* Argument of the coercion */ 
 358} COERCE_MTX;
 359/*
 360 * Expression
 361 * Type: Expression
 362 */
 363typedef struct {
 364        COMMON_EXPR_MTX
 365        MTX      *expr;
 366} EXPR_MTX;
 367/*
 368 * Return from function
 369 * Type: Return
 370 */
 371typedef struct {
 372        COMMON_EXPR_MTX
 373        MTX      *expr;     /* Return value */
 374} RET_MTX;
 375/*
 376 * Unconditional branch (jump)
 377 * Type: Jump
 378 */
 379typedef struct {
 380        COMMON_MTX
 381        MTX *link;          /* Link to the next jump matrix
 382                             * (for break and continue matrices)
 383                             */
 384        MTX      *dest;     /* Jump destination (usually a NOP matrix) */
 385} JUMP_MTX;
 386/*
 387 * Conditional branch
 388 * Type: Branch
 389 */
 390typedef struct {
 391        COMMON_MTX
 392        int      cond;      /* Condition: 1 - equal, 0 - not equal */
 393        MTX      *dest;     /* Jump destination (usually a NOP matrix) */
 394} BRANCH_MTX;
 395/*
 396 * Stack frame matrix
 397 * Type: Enter, Leave
 398 */
 399typedef struct {
 400        COMMON_MTX
 401        stkoff_t  stacksize;/* Required stack size */
 402} FRAME_MTX;
 403/*
 404 * Jump target
 405 * Type: Target
 406 */
 407typedef struct {
 408        COMMON_MTX
 409        pctr_t  pc;         /* Target's program counter */
 410} TGT_MTX;
 411/*
 412 * No-op matrix. It is always inserted at the branch destination
 413 * points. Its purpose is to keep a singly-linked list of jump
 414 * locations for fixing up jump statements.
 415 * Type: Nop
 416 */
 417typedef struct {
 418        COMMON_MTX
 419        TGT_MTX   *tgt;     /* Target list */
 420        pctr_t     pc;      /* Program counter for backward
 421                               references */
 422} NOP_MTX;
 423/*
 424 * Function call
 425 * Type: Call
 426 */
 427typedef struct {
 428        COMMON_EXPR_MTX
 429        FUNCTION  *fun;     /* Called function */
 430        int       nargs;    /* Number of arguments */
 431        MTX       *args;    /* Arguments */
 432} CALL_MTX;
 433/*
 434 * Builtin function call
 435 * Type: Builtin
 436 */
 437typedef struct {
 438        COMMON_EXPR_MTX
 439        INSTR     fun;      /* Handler function */
 440        int       nargs;    /* Number of arguments */   
 441        MTX       *args;    /* Arguments */
 442} BTIN_MTX;
 443/*
 444 * Attribute matrix
 445 * Type: Attr, Attr_asgn, Attr_check
 446 */
 447typedef struct {
 448        COMMON_EXPR_MTX
 449        int       attrno;   /* Attribute number */
 450	MTX       *index;   /* Index expression */
 451        MTX       *rval;    /* Rvalue */
 452} ATTR_MTX;
 453
 454union mtx {
 455        GEN_MTX    gen;
 456        NOP_MTX    nop;
 457        FRAME_MTX  frame;
 458        CONST_MTX  cnst;
 459        MATCHREF_MTX    ref;
 460        VAR_MTX    var;
 461        UN_MTX     un;
 462        BIN_MTX    bin;
 463        COND_MTX   cond;
 464        ASGN_MTX   asgn;
 465        MATCH_MTX  match;
 466        COERCE_MTX coerce;
 467        RET_MTX    ret;
 468        JUMP_MTX   jump;
 469        BRANCH_MTX branch;
 470        TGT_MTX    tgt;
 471        CALL_MTX   call;
 472        BTIN_MTX   btin;
 473        ATTR_MTX   attr;
 474};
 475
 476/*
 477 * Stack frame
 478 */
 479typedef struct frame_t FRAME;
 480
 481struct frame_t {
 482        OBJ(FRAME);
 483        int       level;        /* nesting level */
 484        stkoff_t  stack_offset; /* offset in the stack */
 485};
 486
 487
 488/* *****************************************************************
 489 * Static data
 490 */
 491/*
 492 * Stack Frame list
 493 */
 494static OBUCKET frame_bkt = { sizeof(FRAME), NULL };
 495static FRAME *frame_first, *frame_last;
 496#define curframe frame_last
 497
 498static int errcnt;         /* Number of errors detected */ 
 499static FUNCTION *function; /* Function being compiled */
 500static grad_symtab_t *rewrite_tab;/* Function table */  
 501
 502static MTX *mtx_first, *mtx_last;  /* Matrix list */
 503static VAR *var_first, *var_last;  /* Variable list */ 
 504
 505/*
 506 * Loops
 507 */
 508typedef struct loop_t LOOP;
 509struct loop_t {
 510        OBJ(LOOP);
 511        JUMP_MTX *lp_break;
 512        JUMP_MTX *lp_cont;
 513};
 514static OBUCKET loop_bkt = { sizeof(LOOP), NULL };
 515static LOOP *loop_first, *loop_last;
 516
 517void loop_push(MTX *mtx);
 518void loop_pop();
 519void loop_fixup(JUMP_MTX *list, MTX *target);
 520void loop_init();
 521void loop_free_all();
 522void loop_unwind_all();
 523
 524/*
 525 * Lexical analyzer stuff
 526 */
 527static FILE *infile;               /* Input file */ 
 528static grad_locus_t locus;         /* Input location */
 529
 530static char *inbuf;                /* Input string */
 531static char *curp;                 /* Current pointer */
 532 
 533static int   yyeof;                /* rised when EOF is encountered */ 
 534static struct obstack input_stk;   /* Symbol stack */ 
 535
 536static grad_data_type_t return_type = Undefined;
 537                                   /* Data type of the topmost expression. */
 538
 539static int regcomp_flags = 0;      /* Flags to be used with regcomps */
 540
 541#define regex_init() regcomp_flags = 0
 542 
 543/* Runtime */
 544static size_t rewrite_stack_size = 4096;  /* Size of stack+heap */
 545static RWSTYPE *runtime_stack;
 546static RWMACH mach;
 547
 548/* Default domain for gettext functions. It is initialized to PACKAGE
 549   by default */
 550static char *default_gettext_domain;
 551 
 552
 553/* ***************************************************************
 554 * Function declarations
 555 */
 556
 557/*
 558 * Lexical analyzer
 559 */
 560static int yylex(); 
 561static void yysync();
 562static int yyerror(char *s);
 563 
 564/*
 565 * Frames
 566 */
 567static void frame_init();
 568static void frame_push();
 569static void frame_pop();
 570static void frame_unwind_all();
 571static void frame_free_all();
 572/*
 573 * Variables
 574 */
 575static void var_init();
 576static VAR * var_alloc(grad_data_type_t type, char *name, int grow);
 577static void var_unwind_level();
 578static void var_unwind_all();
 579static void var_type(grad_data_type_t type, VAR *var);
 580static void var_free_all();
 581static VAR *var_lookup(char *name);
 582/*
 583 * Matrices
 584 */
 585static void mtx_init();
 586static void mtx_free_all();
 587static void mtx_unwind_all();
 588static MTX * mtx_cur();
 589static MTX * mtx_nop();
 590static MTX * mtx_jump();
 591static MTX * mtx_frame(Mtxtype type, stkoff_t stksize);
 592static MTX * mtx_stop();
 593static MTX * mtx_pop();
 594static MTX * mtx_return();
 595static MTX * mtx_alloc(Mtxtype type);
 596static MTX * mtx_const(grad_value_t *val);
 597static MTX * mtx_ref(int num);
 598static MTX * mtx_var(VAR *var);
 599static MTX * mtx_asgn(VAR *var, MTX *arg);
 600static MTX * mtx_bin(Bopcode opcode, MTX *arg1, MTX *arg2);
 601static MTX * mtx_un(Uopcode opcode, MTX *arg);
 602static MTX * mtx_match(int negated, MTX *mtx, COMP_REGEX *);
 603static MTX * mtx_cond(MTX *cond, MTX *if_true, MTX *if_false);
 604static MTX * mtx_coerce(grad_data_type_t type, MTX *arg);
 605static MTX * mtx_call(FUNCTION *fun, MTX *args);
 606static MTX * mtx_builtin(builtin_t *bin, MTX *args);
 607static MTX * mtx_attr(grad_dict_attr_t *attr, MTX *index);
 608static MTX * mtx_attr_asgn(grad_dict_attr_t *attr, MTX *index, MTX *rval);
 609static MTX * mtx_attr_check(grad_dict_attr_t *attr, MTX *index);
 610static MTX * mtx_attr_delete(grad_dict_attr_t *attr, MTX *index);
 611
 612static MTX * coerce(MTX  *arg, grad_data_type_t type);
 613/*
 614 * Regular expressions
 615 */
 616static COMP_REGEX * rx_alloc(regex_t  *regex, int nmatch);
 617static void rx_free(COMP_REGEX *rx);
 618static COMP_REGEX * compile_regexp(char *str);
 619/*
 620 * Functions
 621 */
 622static FUNCTION * function_install(FUNCTION *fun);
 623static int  function_free(FUNCTION *fun);
 624static void function_delete();
 625static void function_cleanup();
 626/*
 627 * Built-in functions
 628 */
 629static builtin_t * builtin_lookup(char *name);
 630
 631/*
 632 * Code optimizer and generator
 633 */
 634static int optimize();
 635static pctr_t codegen();
 636static void code_init();
 637static void code_check();
 638
 639/*
 640 * Auxiliary and debugging functions
 641 */
 642static void debug_dump_code();
 643static const char * datatype_str_nom(grad_data_type_t type);
 644static const char * datatype_str_acc(grad_data_type_t type);
 645static const char * datatype_str_abl(grad_data_type_t type);
 646static grad_data_type_t attr_datatype(grad_dict_attr_t *);
 647
 648/*
 649 * Run-Time
 650 */
 651static void gc();
 652static void run(pctr_t pc);
 653static int run_init(pctr_t pc, grad_request_t *req);
 654static int rw_error(const char *msg);
 655static int rw_error_free(char *msg);
 656 
 657/* These used to lock/unlock access to rw_code array. Now this is
 658   not needed. However, I left the placeholders for a while... */
 659#define rw_code_lock() 
 660#define rw_code_unlock()
 661
 662#define AVPLIST(m) ((m)->req ? (m)->req->avlist : NULL)
 663
 664static FUNCTION fmain;
 665%}
 666
 667
 668%union {
 669        int   number;
 670        int   type;
 671        VAR   *var;
 672        MTX   *mtx;
 673        FUNCTION  *fun;
 674        builtin_t *btin;
 675        grad_dict_attr_t *attr;
 676        struct {
 677                MTX *arg_first;
 678                MTX *arg_last;
 679        } arg;
 680        struct {
 681                int nmatch;
 682                regex_t regex;
 683        } rx;
 684        char  *string;
 685};
 686
 687%token <type>   TYPE
 688%token IF ELSE RETURN WHILE FOR DO BREAK CONTINUE DELETE
 689%token <string> STRING IDENT
 690%token <number> NUMBER REFERENCE
 691%token <var> VARIABLE
 692%token <fun> FUN
 693%token <btin> BUILTIN
 694%token <attr> ATTR
 695%token BOGUS
 696
 697%type <arg> arglist 
 698%type <mtx> stmt expr list cond else while do arg args
 699%type <var> varlist parmlist parm dclparm
 700
 701
 702%right '='
 703%left OR
 704%left AND
 705%nonassoc MT NM
 706%left '|'
 707%left '^'
 708%left '&'
 709%left EQ NE 
 710%left LT LE GT GE
 711%left SHL SHR
 712%left '+' '-'
 713%left '*' '/' '%'
 714%left UMINUS NOT TYPECAST
 715
 716%%
 717
 718program : input
 719          {
 720                  var_free_all();
 721                  loop_free_all();
 722                  frame_free_all();
 723                  mtx_free_all();
 724          }
 725        ;
 726
 727input   : dcllist
 728          {
 729		  return_type = Undefined;
 730	  }
 731        | expr
 732          {
 733                  if (errcnt) {
 734                          YYERROR;
 735                  }
 736		  
 737		  mtx_return($1);
 738                  
 739		  memset(&fmain, 0, sizeof(fmain));
 740		  fmain.name = "main";
 741		  fmain.rettype = return_type = $1->gen.datatype;
 742		  function = &fmain;
 743
 744                  if (optimize() == 0) {
 745                          codegen();
 746                          if (errcnt) {
 747                                  YYERROR;
 748                          }
 749                  }
 750          }
 751        ;
 752
 753dcllist : decl
 754        | dcllist decl
 755        | dcllist error
 756          {
 757                  /* Roll back all changes done so far */
 758                  var_unwind_all();
 759                  loop_unwind_all();
 760                  frame_unwind_all();
 761                  mtx_unwind_all();
 762                  function_delete();
 763                  /* Synchronize input after error */
 764                  yysync();
 765                  /* Clear input and error condition */
 766                  yyclearin;
 767                  yyerrok;
 768                  errcnt = 0;
 769          }
 770        ;
 771
 772decl    : fundecl begin list end
 773          {
 774                  if (errcnt) {
 775                          function_delete();
 776                          YYERROR;
 777                  }
 778                  
 779                  if (optimize() == 0) {
 780                          codegen();
 781                          if (errcnt) {
 782                                  function_delete();
 783                                  YYERROR;
 784                          }
 785                  } else {
 786                          function_delete();
 787                  }
 788                  
 789                  /* clean up things */
 790                  var_unwind_all();
 791                  loop_unwind_all();
 792                  frame_unwind_all();
 793                  mtx_unwind_all();
 794                  function_cleanup();
 795          }
 796        ;
 797
 798fundecl : TYPE IDENT dclparm
 799          {
 800                  VAR *var;
 801                  PARAMETER *last, *parm;
 802                  FUNCTION f;
 803                  
 804                  if (errcnt)
 805                          YYERROR;
 806                  
 807                  memset(&f, 0, sizeof(f));
 808                  f.name    = $2;
 809                  f.rettype = $1;
 810                  f.entry   = 0;
 811                  f.loc     = locus;
 812                  
 813                  f.nparm   = 0;
 814                  f.parm    = NULL;
 815
 816                  /* Count number of parameters */
 817                  for (var = $3; var; var = var->next) 
 818                          f.nparm++;
 819
 820                  f.parm = last = NULL;
 821                  for (var = $3; var; var = var->next) {
 822                          parm = grad_emalloc(sizeof(*parm));
 823                          parm->datatype = var->datatype;
 824                          var->offset = -(STACK_BASE+
 825                                          f.nparm - var->offset);
 826                          parm->offset   = var->offset;
 827                          parm->prev     = last;
 828                          parm->next     = NULL;
 829                          if (f.parm == NULL)
 830                                  f.parm = parm;
 831                          else 
 832                                  last->next = parm;
 833                          last = parm;
 834                  }
 835                  function = function_install(&f);
 836          }
 837        | TYPE FUN dclparm
 838          {
 839		  grad_log_loc(GRAD_LOG_ERR, &locus,
 840			       _("redefinition of function `%s'"), $2->name);
 841		  grad_log_loc(GRAD_LOG_ERR, &$2->loc,
 842			       _("previously defined here"));
 843		  errcnt++;
 844		  YYERROR;
 845          }
 846        ;
 847
 848begin   : obrace
 849        | obrace autodcl
 850        ;
 851
 852end     : cbrace
 853        ;
 854                  
 855obrace  : '{'
 856          {
 857                  frame_push();
 858          }
 859        ;
 860
 861cbrace  : '}'
 862          {
 863                  var_unwind_level();
 864                  frame_pop();
 865          }
 866        ;
 867
 868/*
 869 * Automatic variables
 870 */
 871
 872autodcl : autovar
 873        | autodcl autovar
 874        ;
 875
 876autovar : TYPE varlist ';'
 877          {
 878                  var_type($1, $2);
 879          }
 880        ;
 881
 882varlist : IDENT
 883          {
 884                  $$ = var_alloc(Undefined, $1, +1);
 885                  $$->dcllink = NULL;
 886          }
 887        | varlist ',' IDENT
 888          {
 889                  VAR *var = var_alloc(Undefined, $3, +1);
 890                  var->dcllink = $1;
 891                  $$ = var;
 892          }
 893        ;
 894
 895/*
 896 * Function Parameters
 897 */
 898dclparm : '(' ')'
 899          {
 900                  $$ = NULL;
 901          }
 902        | '(' parmlist ')'
 903          {
 904                  $$ = $2;
 905          }
 906        ;
 907
 908parmlist: parm
 909          {
 910                  /*FIXME*/
 911                  /*$$->dcllink = NULL;*/
 912          }
 913        | parmlist ',' parm
 914          {
 915                  /*$1->dcllink = $3;*/
 916                  $$ = $1;
 917          }
 918        ;
 919
 920parm    : TYPE IDENT
 921          {
 922                  $$ = var_alloc($1, $2, +1);
 923          }
 924        ;
 925
 926/* Argument lists
 927 */
 928
 929args    : /* empty */
 930          {
 931                  $$ = NULL;
 932          }
 933        | arglist
 934          {
 935                  $$ = $1.arg_first;
 936          }
 937        ;
 938
 939arglist : arg
 940          {
 941                  $1->gen.arglink = NULL;
 942                  $$.arg_first = $$.arg_last = $1;
 943          }
 944        | arglist ',' arg
 945          {
 946                  $1.arg_last->gen.arglink = $3;
 947                  $1.arg_last = $3;
 948                  $$ = $1;
 949          }
 950        ;
 951
 952arg     : expr
 953        ;
 954
 955/*
 956 * Statement list and individual statements
 957 */
 958list    : stmt
 959        | list stmt
 960        ;
 961
 962stmt    : begin list end
 963          {
 964                  $$ = $2;
 965          }
 966        | expr ';'
 967          {
 968                  mtx_stop();
 969                  mtx_pop();
 970          }
 971        | IF cond stmt
 972          {
 973                  $2->cond.if_false = mtx_nop();
 974                  $$ = mtx_cur();
 975          }
 976        | IF cond stmt else stmt
 977          {
 978                  mtx_stop();
 979                  $2->cond.if_false = $4;
 980                  $4->nop.prev->jump.dest = mtx_nop();
 981                  $$ = mtx_cur();
 982          }
 983        | RETURN expr ';'
 984          {
 985                  /*mtx_stop();*/
 986                  $$ = mtx_return($2);
 987          }
 988        | while cond stmt
 989          {
 990                  MTX *mtx;
 991                  
 992                  mtx_stop();
 993                  mtx = mtx_jump();
 994                  mtx->jump.dest = $1;
 995                  $2->cond.if_false = mtx_nop();
 996                  $$ = mtx_cur();
 997                  
 998                  /* Fixup possible breaks */
 999                  loop_fixup(loop_last->lp_break, $$);
1000                  /* Fixup possible continues */
1001                  loop_fixup(loop_last->lp_cont, $1);
1002                  loop_pop();
1003          }       
1004        | do stmt { $<mtx>$ = mtx_nop(); } WHILE cond ';' 
1005          {
1006                  /* Default cond rule sets if_true to the next NOP matrix
1007                   * Invert this behaviour.
1008                   */
1009                  $5->cond.if_false = $5->cond.if_true;
1010                  $5->cond.if_true = $1;
1011                  $$ = mtx_cur();
1012
1013                  /* Fixup possible breaks */
1014                  loop_fixup(loop_last->lp_break, $$);
1015                  /* Fixup possible continues */
1016                  loop_fixup(loop_last->lp_cont, $<mtx>3);
1017                  loop_pop();
1018          }
1019/* ***********************
1020   For future use:
1021        | FOR '(' for_expr for_expr for_expr ')' stmt
1022   *********************** */
1023        | BREAK ';'
1024          {
1025                  if (!loop_last) {
1026                          grad_log_loc(GRAD_LOG_ERR, &locus,
1027				       "%s",
1028				       _("nothing to break from"));
1029                          errcnt++;
1030                          YYERROR;
1031                  }
1032
1033                  $$ = mtx_jump();
1034                  $$->jump.link = (MTX*)loop_last->lp_break;
1035                  loop_last->lp_break = (JUMP_MTX*)$$;
1036          }
1037        | CONTINUE ';'
1038          {
1039                  if (!loop_last) {
1040                          grad_log_loc(GRAD_LOG_ERR, &locus,
1041				       "%s",
1042				       _("nothing to continue"));
1043                          errcnt++;
1044                          YYERROR;
1045                  }
1046                  $$ = mtx_jump();
1047                  $$->jump.link = (MTX*)loop_last->lp_cont;
1048                  loop_last->lp_cont = (JUMP_MTX*)$$;
1049          }
1050        | DELETE ATTR ';'
1051          {
1052		  $$ = mtx_attr_delete($2, NULL);
1053	  }
1054	| DELETE ATTR '(' expr ')' ';'
1055          {
1056		  $$ = mtx_attr_delete($2, $4);
1057	  }
1058        ;
1059
1060while   : WHILE
1061          {
1062                  $$ = mtx_nop();
1063                  loop_push($$);
1064          }
1065        ;
1066
1067do      : DO
1068          {
1069                  $$ = mtx_nop();
1070                  loop_push($$);
1071          }
1072        ;
1073
1074else    : ELSE
1075          {
1076                  mtx_stop();
1077                  mtx_jump();
1078                  $$ = mtx_nop();
1079          }
1080        ;
1081
1082cond    : '(' expr ')'
1083          {
1084                  mtx_stop();
1085                  $$ = mtx_cond($2, NULL, NULL);
1086                  $$->cond.if_true = mtx_nop();
1087          }
1088        ;
1089
1090/*
1091 * Expressions
1092 */
1093expr    : NUMBER
1094          {
1095		  grad_value_t val;
1096		  val.type = Integer;
1097		  val.datum.ival = $1;
1098                  $$ = mtx_const(&val);
1099          }
1100        | STRING
1101          {
1102		  grad_value_t val;
1103		  val.type = String;
1104		  val.datum.sval.size = strlen($1);
1105		  val.datum.sval.data = $1;
1106                  $$ = mtx_const(&val);
1107          }
1108        | REFERENCE
1109          {
1110                  $$ = mtx_ref($1);
1111          }
1112        | VARIABLE
1113          {
1114                  $$ = mtx_var($1);
1115          }
1116        | IDENT
1117          {
1118                  grad_log_loc(GRAD_LOG_ERR, &locus, _("undefined variable: %s"), $1);
1119                  errcnt++;
1120                  YYERROR;
1121          }
1122        | VARIABLE '=' expr
1123          {
1124                  $$ = mtx_asgn($1, $3);
1125          }
1126        | ATTR
1127          {
1128                  $$ = mtx_attr($1, NULL);
1129          }
1130        | ATTR '(' expr ')'
1131          {
1132                  $$ = mtx_attr($1, $3);
1133          }
1134        | '*' ATTR
1135          {
1136                  $$ = mtx_attr_check($2, NULL);
1137          }
1138        | '*' ATTR '(' expr ')'
1139          {
1140		  $$ = mtx_attr_check($2, $4);
1141	  }
1142        | ATTR '=' expr
1143          {
1144                  $$ = mtx_attr_asgn($1, NULL, $3);
1145          }
1146        | ATTR '(' expr ')' '=' expr
1147          {
1148                  $$ = mtx_attr_asgn($1, $3, $6);
1149          }
1150        | FUN '(' args ')'
1151          {
1152                  $$ = mtx_call($1, $3);
1153          }
1154        | BUILTIN '(' args ')'
1155          {
1156                  $$ = mtx_builtin($1, $3);
1157          }
1158        | expr '+' expr
1159          {
1160                  $$ = mtx_bin(Add, $1, $3);
1161          }
1162        | expr '-' expr
1163          {
1164                  $$ = mtx_bin(Sub, $1, $3);
1165          }
1166        | expr '*' expr
1167          {
1168                  $$ = mtx_bin(Mul, $1, $3);
1169          }
1170        | expr '/' expr
1171          {
1172                  $$ = mtx_bin(Div, $1, $3);
1173          }
1174        | expr '%' expr
1175          {
1176                  $$ = mtx_bin(Rem, $1, $3);
1177          }
1178        | expr '|' expr
1179          {
1180                  $$ = mtx_bin(BOr, $1, $3);
1181          }
1182        | expr '&' expr
1183          {
1184                  $$ = mtx_bin(BAnd, $1, $3);
1185          }
1186        | expr '^' expr
1187          {
1188                  $$ = mtx_bin(BXor, $1, $3);
1189          }
1190        | expr SHL expr
1191          {
1192                  $$ = mtx_bin(Shl, $1, $3);
1193          }
1194        | expr SHR expr
1195          {
1196                  $$ = mtx_bin(Shr, $1, $3);
1197          }
1198        | expr AND expr
1199          {
1200                  $$ = mtx_bin(And, $1, $3);
1201          }
1202        | expr OR expr
1203          {
1204                  $$ = mtx_bin(Or, $1, $3);
1205          }
1206        | '-' expr %prec UMINUS
1207          {
1208                  $$ = mtx_un(Neg, $2);
1209          }
1210        | '+' expr %prec UMINUS
1211          {
1212                  $$ = $2;
1213          }
1214        | NOT expr
1215          {
1216                  $$ = mtx_un(Not, $2);
1217          }
1218        | '(' expr ')'
1219          {
1220                  $$ = $2;
1221          }
1222        | '(' TYPE ')' expr %prec TYPECAST
1223          {
1224                  $$ = mtx_coerce($2, $4);
1225          }
1226        | expr EQ expr
1227          {
1228                  $$ = mtx_bin(Eq, $1, $3);
1229          }
1230        | expr NE expr
1231          {
1232                  $$ = mtx_bin(Ne, $1, $3);
1233          }
1234        | expr LT expr
1235          {
1236                  $$ = mtx_bin(Lt, $1, $3);
1237          }
1238        | expr LE expr
1239          {
1240                  $$ = mtx_bin(Le, $1, $3);
1241          }
1242        | expr GT expr
1243          {
1244                  $$ = mtx_bin(Gt, $1, $3);
1245          }
1246        | expr GE expr
1247          {
1248                  $$ = mtx_bin(Ge, $1, $3);
1249          }
1250        | expr MT STRING
1251          {
1252                  COMP_REGEX *rx;
1253                  if ((rx = compile_regexp($3)) == NULL) {
1254                          errcnt++;
1255                          YYERROR;
1256                  }
1257                  $$ = mtx_match(0, $1, rx);
1258          }
1259        | expr NM STRING
1260          {
1261                  COMP_REGEX *rx;
1262                  if ((rx = compile_regexp($3)) == NULL) {
1263                          errcnt++;
1264                          YYERROR;
1265                  }
1266                  $$ = mtx_match(1, $1, rx);
1267          }
1268        ;
1269
1270%%
1271
1272int
1273yyerror(char *s)
1274{
1275        grad_log_loc(GRAD_LOG_ERR, &locus, "%s", s);
1276        errcnt++;
1277	return 0;
1278}
1279
1280
1281/* **************************************************************************
1282 * Interface functions
1283 */
1284int
1285parse_rewrite(char *path)
1286{
1287        locus.file = path;
1288        infile = fopen(locus.file, "r");
1289        if (!infile) {
1290                if (errno != ENOENT) {
1291                        grad_log(GRAD_LOG_ERR|GRAD_LOG_PERROR,
1292                                 _("can't open file `%s'"),
1293                                 locus.file);
1294			return -1;
1295                }
1296                return -2;
1297        }
1298
1299	GRAD_DEBUG1(1, "Loading file %s", locus.file);
1300        rw_code_lock();
1301        yyeof = 0;
1302        locus.line = 1;
1303	errcnt = 0;
1304        regex_init();
1305        obstack_init(&input_stk);
1306
1307        mtx_init();
1308        var_init();
1309        loop_init();
1310        frame_init();
1311        
1312        frame_push();
1313	
1314        yyparse();
1315
1316        var_free_all();
1317        frame_free_all();
1318        mtx_free_all();
1319                
1320        fclose(infile);
1321        obstack_free(&input_stk, NULL);
1322        rw_code_unlock();
1323        return errcnt;
1324}
1325
1326static int
1327parse_rewrite_string(char *str)
1328{
1329        rw_code_lock();
1330	code_check();
1331        yyeof = 0;
1332	locus.file = "<string>";
1333	locus.line = 1;
1334	errcnt = 0;
1335        regex_init();
1336        obstack_init(&input_stk);
1337
1338        mtx_init();
1339        var_init();
1340        loop_init();
1341        frame_init();
1342        
1343        frame_push();
1344        
1345        if (GRAD_DEBUG_LEVEL(50))
1346                yydebug++;
1347
1348	infile = 0;
1349	inbuf = curp = str;
1350	
1351        yyparse();
1352
1353#if defined(MAINTAINER_MODE)
1354        if (GRAD_DEBUG_LEVEL(100))
1355                debug_dump_code();
1356#endif
1357        
1358        var_free_all();
1359        frame_free_all();
1360        mtx_free_all();
1361                
1362        obstack_free(&input_stk, NULL);
1363        rw_code_unlock();
1364        return errcnt;
1365}
1366
1367
1368/* **************************************************************************
1369 * Lexical analyzer stuff: too simple to be written in lex.
1370 */
1371static int
1372unput(int c)
1373{
1374	if (!c)
1375		return 0;
1376	if (infile)
1377		ungetc(c, infile);
1378	else if (curp > inbuf)
1379		*--curp = c;
1380	return c;
1381}
1382
1383static int 
1384input()
1385{
1386        if (yyeof)
1387                yychar = 0;
1388	else if (infile) {
1389		if ((yychar = getc(infile)) <= 0) {
1390			yyeof++;
1391			yychar = 0;
1392		}
1393	} else if (curp) {
1394		yychar = *curp++;
1395		if (!yychar)
1396			yyeof++;
1397	}
1398        return yychar;
1399}
1400
1401static int  rw_backslash();
1402static int  c2d(int c);
1403static int  read_number();
1404static int  read_num(int n, int base);
1405static char *read_string();
1406static char *read_ident(int c);
1407static char *read_to_delim(int c);
1408static int  skip_to_nl();
1409static int c_comment();
1410
1411/*
1412 * Convert a character to digit. Only octal, decimal and hex digits are
1413 * allowed. If any other character is input, c2d() returns 100, which is
1414 * greater than any number base allowed.
1415 */
1416int
1417c2d(int c)
1418{
1419        switch (c) {
1420        case '0':
1421        case '1':
1422        case '2':
1423        case '3':
1424        case '4':
1425        case '5':
1426        case '6':
1427        case '7':
1428        case '8':
1429        case '9':
1430                return c - '0';
1431        case 'A':
1432        case 'B':
1433        case 'C':
1434        case 'D':
1435        case 'E':
1436        case 'F':
1437                return c - 'A' + 16;
1438        case 'a':
1439        case 'b':
1440        case 'c':
1441        case 'd':
1442        case 'e':
1443        case 'f':
1444                return c - 'a' + 10;
1445        }
1446        return 100;
1447}
1448
1449/*
1450 * Read a number. Usual C conventions apply. 
1451 */
1452int
1453read_number()
1454{
1455        int c;
1456        int base;
1457	int res;
1458	
1459        c = yychar;
1460        if (c == '0') {
1461                if (input() == 'x' || yychar == 'X') {
1462                        base = 16;
1463                } else {
1464                        base = 8;
1465                        unput(yychar);
1466                }
1467        } else
1468                base = 10;
1469
1470	res = read_num(c2d(c), base);
1471	if (base == 10 && yychar == '.') {
1472		int n;
1473
1474		for (n = 0; n < 3 && yychar == '.'; n++) {
1475			int val;
1476			
1477			input();
1478			val = read_num(0, base);
1479			res = (res << 8) + val;
1480		}
1481		if (n != 3)
1482			res <<= 8 * (3-n);
1483	}
1484	return res;
1485}
1486
1487int
1488read_num(int n, int base)
1489{
1490        int d;
1491
1492        while (input() && (d = c2d(yychar)) < 16) 
1493                n = n*base + d;
1494        unput(yychar);
1495        return n;
1496}
1497
1498int
1499rw_backslash()
1500{
1501        switch (input()) {
1502        case '\\':
1503                return '\\';
1504        case 'a':
1505                return '\a';
1506        case 'b':
1507                return '\b';
1508        case 'f':
1509                return '\f';
1510        case 'n':
1511                return '\n';
1512        case 'r':
1513                return '\r';
1514        case 't':
1515                return '\t';
1516        case 'e':
1517                return '\033';
1518        case '0':
1519                return read_number();
1520        case 'x':
1521        case 'X':
1522                return read_num(0, 16);
1523        case '(':
1524        case ')':
1525                /* Preserve regular expressions */
1526                unput(yychar);
1527                yychar = '\\';
1528        }
1529        return yychar;
1530}
1531
1532/*
1533 * Read a string up to the closing doublequote
1534 */
1535char *
1536read_string()
1537{
1538        while (input() && yychar != '"') {
1539                if (yychar == '\\')
1540                        yychar = rw_backslash();
1541                obstack_1grow(&input_stk, yychar);
1542        }
1543        obstack_1grow(&input_stk, 0);
1544        return obstack_finish(&input_stk);
1545}
1546
1547/*
1548 * Read everything up to the given delimiter
1549 */
1550char *
1551read_to_delim(int c)
1552{
1553        while (input() && yychar != c)
1554                obstack_1grow(&input_stk, yychar);
1555        obstack_1grow(&input_stk, 0);
1556        return obstack_finish(&input_stk);
1557}
1558
1559/*
1560 * Is `c' a part of the word?
1561 */
1562#define isword(c) (isalnum(c) || c == '_' || c == '$')
1563
1564/*
1565 * Is `c' a whitespace character?
1566 */
1567#define isws(c) ((c) == ' ' || (c) == '\t')
1568
1569/*
1570 * Read identifier
1571 */
1572char *
1573read_ident(int c)
1574{
1575        obstack_1grow(&input_stk, c);
1576        while (input() && isword(yychar))
1577                obstack_1grow(&input_stk, yychar);
1578        obstack_1grow(&input_stk, 0);
1579        unput(yychar);
1580        return obstack_finish(&input_stk);
1581}
1582
1583/*
1584 * Skip input up to the next newline
1585 */
1586int
1587skip_to_nl()
1588{
1589        while (input() && yychar != '\n')
1590                ;
1591        return unput(yychar);
1592}
1593
1594/*
1595 * Skip a C-style comment
1596 */
1597int
1598c_comment()
1599{
1600        if (yychar != '/')
1601                return 0;
1602        if (input() == '*') {
1603                size_t keep_line = locus.line;
1604
1605                do {
1606                        while (input() != '*') {
1607                                if (yychar == 0) {
1608                                        grad_log_loc(GRAD_LOG_ERR, &locus,
1609		       _("unexpected EOF in comment started at line %lu"),
1610						     (unsigned long) keep_line);
1611                                        return 0;
1612                                } else if (yychar == '\n')
1613                                        locus.line++;
1614                        }
1615                } while (input() != '/');
1616                return 1;
1617        }
1618        unput(yychar);
1619        yychar = '/';
1620        return 0;
1621}
1622
1623
1624/* Pragmatic comments */
1625enum pragma_handler_phase {
1626	pragma_begin,
1627	pragma_cont,
1628	pragma_error,
1629	pragma_end
1630};
1631
1632typedef int (*pragma_handler_fp) (enum pragma_handler_phase);
1633
1634static int
1635regex_pragma (enum pragma_handler_phase phase)
1636{
1637	int disable = 0;
1638	int bit;
1639	char *s;
1640	static int regexp_accum;
1641	
1642	switch (phase) {
1643	case pragma_begin:
1644		regexp_accum = 0;
1645		return 0;
1646		
1647	case pragma_end:
1648		regcomp_flags = regexp_accum;
1649		return 0;
1650
1651	case pragma_error:
1652		return 0;
1653		
1654	case pragma_cont:
1655		break;
1656	}
1657
1658	switch (yychar) {
1659	case '+':
1660		disable = 0;
1661		input();
1662		break;
1663
1664	case '-':
1665		disable = 1;
1666		input();
1667		break;
1668	}
1669	if (!isword(yychar)) {
1670		grad_log_loc(GRAD_LOG_ERR, &locus, _("Malformed pragma"));
1671		return 1;
1672	}
1673	
1674	s = read_ident(yychar);
1675
1676	if (strcmp (s, "extended") == 0)
1677		bit = REG_EXTENDED;
1678	else if (strcmp (s, "icase") == 0)
1679		bit = REG_ICASE;
1680	else if (strcmp (s, "newline") == 0)
1681		bit = REG_NEWLINE;
1682	else {
1683		grad_log_loc(GRAD_LOG_ERR, &locus,
1684			     _("Unknown regexp flag: %s"), s);
1685		return 1;
1686	}
1687
1688	if (disable)
1689		regexp_accum &= ~bit;
1690	else
1691		regexp_accum |= bit;
1692	return 0;
1693}
1694
1695static pragma_handler_fp
1696find_pragma_handler(char *s)
1697{
1698	if (strcmp(s, "regex") == 0)
1699		return regex_pragma;
1700	return NULL;
1701}
1702
1703static void
1704handle_pragma()
1705{
1706	int rc;
1707	pragma_handler_fp pragma_handler;
1708	
1709	while (input() && isws(yychar))
1710		;
1711	if (yychar == 0)
1712		return;
1713			
1714	pragma_handler = find_pragma_handler (read_ident(yychar));
1715		
1716	if (pragma_handler) {
1717		pragma_handler(pragma_begin);
1718
1719		do {
1720			while (input() && isws(yychar))
1721				;
1722			if (yychar == 0 || yychar == '\n')
1723				break;
1724			rc = pragma_handler(pragma_cont);
1725		} while (rc == 0 && yychar != '\n' && yychar != 0);
1726		
1727		pragma_handler(rc ? pragma_error : pragma_end);
1728	}
1729}
1730
1731
1732
1733
1734/* Parse a 'sharp' (single-line) comment */
1735void
1736sharp_comment()
1737{
1738	while (input() && isws(yychar))
1739		;
1740	if (yychar == 0)
1741		return;
1742	else if (yychar == '\n') {
1743		locus.line++;
1744		return;
1745	} else if (isword(yychar)) {
1746		if (strcmp(read_ident(yychar), "pragma") == 0)
1747			handle_pragma();
1748	}
1749		
1750	skip_to_nl();
1751}
1752
1753
1754#if defined(MAINTAINER_MODE)
1755# define DEBUG_LEX1(s) if (GRAD_DEBUG_LEVEL(60)) printf("yylex: " s "\n")
1756# define DEBUG_LEX2(s,v) if (GRAD_DEBUG_LEVEL(60)) printf("yylex: " s "\n", v)
1757#else
1758# define DEBUG_LEX1(s)
1759# define DEBUG_LEX2(s,v)
1760#endif
1761
1762static grad_keyword_t rw_kw[] = {
1763        { "if",       IF },
1764        { "else",     ELSE },
1765        { "return",   RETURN },
1766        { "for",      FOR },
1767        { "do",       DO },
1768        { "while",    WHILE },
1769        { "break",    BREAK },
1770        { "continue", CONTINUE },
1771	{ "delete",   DELETE },
1772        { NULL }
1773};
1774
1775int
1776yylex()
1777{
1778        int nl;
1779        int c;
1780        VAR *var;
1781        FUNCTION *fun;
1782        builtin_t *btin;
1783        
1784        /* Skip whitespace and comment lines */
1785        do {
1786                nl = 0;
1787                while (input() && isspace(yychar))
1788                        if (yychar == '\n')
1789                                locus.line++;
1790        
1791                if (!yychar)
1792                        return 0;
1793
1794                if (yychar == '#') {
1795                        sharp_comment();
1796                        nl = 1;
1797                }
1798        } while (nl || c_comment());
1799
1800        /*
1801         * A regexp reference
1802         */
1803        if (yychar == '\\') {
1804                input();
1805                yylval.number = read_number();
1806                DEBUG_LEX2("REFERENCE %d", yylval.number);
1807                return REFERENCE;
1808        }
1809
1810        /*
1811         * A character
1812         */
1813        if (yychar == '\'') {
1814                if (input() == '\\')
1815                        c = rw_backslash();
1816                else
1817                        c = yychar;
1818                if (input() != '\'') {
1819                        grad_log_loc(GRAD_LOG_ERR, &locus,
1820				     "%s",
1821				     _("unterminated character constant"));
1822                        errcnt++;
1823                }
1824                yylval.number = c;
1825                DEBUG_LEX2("CHAR %d", c);
1826                return NUMBER;
1827        }
1828        
1829        /*
1830         * A number
1831         */
1832        if (isdigit(yychar)) {
1833                yylval.number = read_number();
1834                DEBUG_LEX2("NUMBER %d", yylval.number);
1835                return NUMBER;
1836        }
1837
1838        /*
1839         * Quoted string
1840         */
1841        if (yychar == '"') {
1842                yylval.string = read_string();
1843                DEBUG_LEX2("STRING %s", yylval.string);
1844                return STRING;
1845        }
1846
1847        /* A/V  pair reference.
1848           We do not allow %<number> sequences, since it would result
1849           in conflict with binary '%' operator.
1850           Thanks to Clement Gerouville for noticing.  */
1851        if (yychar == '%') {
1852                grad_dict_attr_t *attr = 0;
1853                char *attr_name;
1854                
1855                input();
1856                if (yychar == '[' || yychar == '{') {
1857                        attr_name = read_to_delim(yychar == '[' ? ']' : '}');
1858                        attr = grad_attr_name_to_dict(attr_name);
1859                } else {
1860                        unput(yychar);
1861                        return '%';
1862                }
1863                if (!attr) {
1864                        grad_log_loc(GRAD_LOG_ERR, &locus,
1865				     _("unknown attribute `%s'"),
1866				     attr_name);
1867                        errcnt++;
1868                        return BOGUS;
1869                }
1870                yylval.attr = attr;
1871                DEBUG_LEX2("ATTR: %s", attr->name);
1872                return ATTR;
1873        }
1874                               
1875                
1876        /*
1877         * Data type or identifier
1878         */
1879        if (isword(yychar)) {
1880                yylval.string = read_ident(yychar);
1881
1882                if (strcmp(yylval.string, "integer") == 0) {
1883                        DEBUG_LEX1("TYPE(Integer)");
1884                        yylval.type = Integer;
1885                        return TYPE;
1886                } else if (strcmp(yylval.string, "string") == 0) {
1887                        DEBUG_LEX1("TYPE(String)");
1888                        yylval.type = String;
1889                        return TYPE;
1890		}
1891		
1892                if ((c = grad_xlat_keyword(rw_kw, yylval.string, 0)) != 0) {
1893                        DEBUG_LEX2("KW: %s", yylval.string);
1894                        return c;
1895                }
1896
1897                if (var = var_lookup(yylval.string)) {
1898                        DEBUG_LEX2("VARIABLE: %s", yylval.string);
1899                        yylval.var = var;
1900                        return VARIABLE;
1901                }
1902                
1903                if (fun = (FUNCTION*) grad_sym_lookup(rewrite_tab, yylval.string)) {
1904                        DEBUG_LEX2("FUN %s", yylval.string);
1905                        yylval.fun = fun;
1906                        return FUN;
1907                }
1908
1909                if (btin = builtin_lookup(yylval.string)) {
1910                        DEBUG_LEX2("BUILTIN %s", yylval.string);
1911                        yylval.btin = btin;
1912                        return BUILTIN;
1913                }
1914                DEBUG_LEX2("IDENT: %s", yylval.string);
1915                return IDENT;
1916        }
1917
1918        /*
1919         * Boolean expressions
1920         */
1921        if (yychar == '&' || yychar == '|') {
1922                int c = yychar;
1923
1924                if (input() == c) { 
1925                        DEBUG_LEX2("%s", yychar == '&' ? "AND" : "OR"); 
1926                        return yychar == '&' ? AND : OR;
1927                }
1928                unput(yychar);
1929                
1930                DEBUG_LEX2("%c", c); 
1931                return c;
1932        }
1933        
1934        /*
1935         * Comparison operator
1936         */
1937        if (strchr("<>=!", yychar)) {
1938                int c = yychar;
1939                if (input() == '=') {
1940                        switch (c) {
1941                        case '<':
1942                                DEBUG_LEX1("LE");
1943                                return LE;
1944                        case '>':
1945                                DEBUG_LEX1("GE");
1946                                return GE;
1947                        case '=':
1948                                DEBUG_LEX1("EQ");
1949                                return EQ;
1950                        case '!':
1951                                DEBUG_LEX1("NE");
1952                                return NE;
1953                        }
1954                } else if (c == yychar) {
1955                        if (c == '<') {
1956                                DEBUG_LEX1("SHL");
1957                                return SHL;
1958                        }
1959                        if (c == '>') {
1960                                DEBUG_LEX1("SHR");
1961                                return SHR;
1962                        }
1963                        unput(yychar);
1964                        DEBUG_LEX2("%c", yychar);
1965                        return yychar;
1966                } else if (yychar == '~') {
1967                        if (c == '=') {
1968                                DEBUG_LEX1("MT");
1969                                return MT;
1970                        }
1971                        if (c == '!') {
1972                                DEBUG_LEX1("NM");
1973                                return NM;
1974                        }
1975                }
1976                unput(yychar);
1977                switch (c) {
1978                case '<':
1979                        DEBUG_LEX1("LT");
1980                        return LT;
1981                case '>':
1982                        DEBUG_LEX1("GT");
1983                        return GT;
1984                case '!':
1985                        DEBUG_LEX1("NOT");
1986                        return NOT;
1987                default:
1988                        return c;
1989                }
1990        }
1991
1992        DEBUG_LEX2("%c", yychar);
1993        return yychar;
1994}
1995
1996void
1997yysync()
1998{
1999        while (skip_to_nl() == '\n' && !isalpha(input()))
2000                locus.line++;
2001        unput(yychar);
2002}
2003
2004
2005/* ****************************************************************************
2006 * Generalized list functions
2007 */
2008static RWLIST *_list_insert(RWLIST **first, RWLIST **last, RWLIST *prev,
2009			    RWLIST *obj, int before);
2010static RWLIST *_list_remove(RWLIST **first, RWLIST **last, RWLIST *obj);
2011static RWLIST *_list_append(RWLIST **first, RWLIST **last, RWLIST *obj);
2012
2013#define rw_list_insert(first, last, prev, obj, before) \
2014 _list_insert((RWLIST**)first,(RWLIST**)last,(RWLIST*)prev,(RWLIST*)obj, before)
2015#define rw_list_remove(first, last, obj) \
2016 _list_remove((RWLIST**)first,(RWLIST**)last,(RWLIST *)obj)
2017#define rw_list_append(first, last, obj) \
2018 _list_append((RWLIST**)first, (RWLIST**)last, (RWLIST*)obj)
2019        
2020RWLIST *
2021_list_append(RWLIST **first, RWLIST **last, RWLIST *obj)
2022{
2023        return rw_list_insert(first, last, *last, obj, 0);
2024}
2025
2026RWLIST *
2027_list_insert(RWLIST **first, RWLIST **last, RWLIST *prev, RWLIST *obj,
2028	     int before)
2029{
2030        RWLIST   *next;
2031
2032        /*
2033         * No first element: initialize whole list
2034         */
2035        if (!*first) {
2036                *first = obj;
2037                if (last)
2038                        *last = obj;
2039                obj->prev = obj->next = NULL;
2040                return obj;
2041        }
2042
2043        /*
2044         * Insert before `prev'
2045         */
2046        if (before) {
2047                _list_insert(first, last, prev, obj, 0);
2048                _list_remove(first, last, prev);
2049                _list_insert(first, last, obj, prev, 0);
2050                return obj;
2051        }
2052
2053        /*
2054         * Default: insert after prev
2055         */
2056        obj->prev = prev;
2057        obj->next = prev->next;
2058        
2059        if (next = prev->next)
2060                next->prev = obj;
2061
2062        prev->next = obj;
2063        if (last && prev == *last)
2064                *last = obj;
2065
2066                
2067        return obj;
2068}
2069
2070RWLIST *
2071_list_remove(RWLIST **first, RWLIST **last, RWLIST *obj)
2072{
2073        RWLIST *temp;
2074
2075        if (temp = obj->prev) 
2076                temp->next = obj->next;
2077        else
2078                *first = obj->next;
2079
2080        if (temp = obj->next)
2081                temp->prev = ob…

Large files files are truncated, but you can click here to view the full file