diff options
author | Arnold D. Robbins <arnold@skeeve.com> | 2010-11-18 23:00:31 +0200 |
---|---|---|
committer | Arnold D. Robbins <arnold@skeeve.com> | 2010-11-18 23:00:31 +0200 |
commit | 6f3612539c425da2bc1d34db621696e6a273b01c (patch) | |
tree | 9623b3ac2c54a93e5eed3be2b1dda7f4e4bf0e47 /awkgram.c | |
parent | 4e3701015635401df2fc4da58abaab7645f4ebd3 (diff) | |
download | egawk-6f3612539c425da2bc1d34db621696e6a273b01c.tar.gz egawk-6f3612539c425da2bc1d34db621696e6a273b01c.tar.bz2 egawk-6f3612539c425da2bc1d34db621696e6a273b01c.zip |
Bring latest byte code gawk into git. Hurray!
Diffstat (limited to 'awkgram.c')
-rw-r--r-- | awkgram.c | 7107 |
1 files changed, 4651 insertions, 2456 deletions
@@ -80,64 +80,103 @@ #define signed /**/ #endif -#define CAN_FREE TRUE -#define DONT_FREE FALSE - -#ifdef CAN_USE_STDARG_H static void yyerror(const char *m, ...) ATTRIBUTE_PRINTF_1; -#else -static void yyerror(); /* va_alist */ -#endif -static char *get_src_buf P((void)); -static int yylex P((void)); -static NODE *node_common P((NODETYPE op)); -static NODE *snode P((NODE *subn, NODETYPE op, int sindex)); -static NODE *make_for_loop P((NODE *init, NODE *cond, NODE *incr)); -static NODE *append_right P((NODE *list, NODE *new)); -static inline NODE *append_pattern P((NODE **list, NODE *patt)); -static void func_install P((NODE *params, NODE *def)); -static void pop_var P((NODE *np, int freeit)); -static void pop_params P((NODE *params)); -static NODE *make_param P((char *name)); -static NODE *mk_rexp P((NODE *exp)); -static int dup_parms P((NODE *func)); -static void param_sanity P((NODE *arglist)); -static int parms_shadow P((const char *fname, NODE *func)); -static int isnoeffect P((NODETYPE t)); -static int isassignable P((NODE *n)); -static void dumpintlstr P((const char *str, size_t len)); -static void dumpintlstr2 P((const char *str1, size_t len1, const char *str2, size_t len2)); -static void count_args P((NODE *n)); -static int isarray P((NODE *n)); +static char *get_src_buf(void); +static int yylex(void); +int yyparse(void); +static INSTRUCTION *snode(INSTRUCTION *subn, INSTRUCTION *op); +static int func_install(INSTRUCTION *fp, INSTRUCTION *def); +static void pop_params(NODE *params); +static NODE *make_param(char *pname); +static NODE *mk_rexp(INSTRUCTION *exp); +static void append_param(char *pname); +static int dup_parms(NODE *func); +static void param_sanity(INSTRUCTION *arglist); +static int parms_shadow(INSTRUCTION *pc, int *shadow); +static int isnoeffect(OPCODE type); +static INSTRUCTION *make_assignable(INSTRUCTION *ip); +static void dumpintlstr(const char *str, size_t len); +static void dumpintlstr2(const char *str1, size_t len1, const char *str2, size_t len2); +static int isarray(NODE *n); +static int include_source(char *src); +static void next_sourcefile(void); +static char *tokexpand(void); + +#define instruction(t) bcalloc(t, 1, 0) + +static INSTRUCTION *mk_program(void); +static INSTRUCTION *append_rule(INSTRUCTION *pattern, INSTRUCTION *action); +static INSTRUCTION *mk_condition(INSTRUCTION *cond, INSTRUCTION *ifp, INSTRUCTION *true_branch, + INSTRUCTION *elsep, INSTRUCTION *false_branch); +static INSTRUCTION *mk_expression_list(INSTRUCTION *list, INSTRUCTION *s1); +static INSTRUCTION *mk_for_loop(INSTRUCTION *forp, INSTRUCTION *init, INSTRUCTION *cond, + INSTRUCTION *incr, INSTRUCTION *body); +static void fix_break_continue(INSTRUCTION *start, INSTRUCTION *end, int check_continue); +static INSTRUCTION *mk_binary(INSTRUCTION *s1, INSTRUCTION *s2, INSTRUCTION *op); +static INSTRUCTION *mk_boolean(INSTRUCTION *left, INSTRUCTION *right, INSTRUCTION *op); +static INSTRUCTION *mk_assignment(INSTRUCTION *lhs, INSTRUCTION *rhs, INSTRUCTION *op); +static INSTRUCTION *mk_getline(INSTRUCTION *op, INSTRUCTION *opt_var, INSTRUCTION *redir, OPCODE redirtype); +static NODE *make_regnode(int type, NODE *exp); +static int count_expressions(INSTRUCTION **list, int isarg); +static INSTRUCTION *optimize_assignment(INSTRUCTION *exp); +static void add_lint(INSTRUCTION *list, LINTTYPE linttype); enum defref { FUNC_DEFINE, FUNC_USE }; -static void func_use P((const char *name, enum defref how)); -static void check_funcs P((void)); +static void func_use(const char *name, enum defref how); +static void check_funcs(void); +static void free_bcpool(INSTRUCTION *pl); -static ssize_t read_one_line P((int fd, void *buffer, size_t count)); -static int one_line_close P((int fd)); +static ssize_t read_one_line(int fd, void *buffer, size_t count); +static int one_line_close(int fd); -static NODE *constant_fold P((NODE *left, NODETYPE op, NODE *right)); -static NODE *optimize_concat P((NODE *left, NODETYPE op, NODE *right)); +static void (*install_func)(char *) = NULL; +static int want_source = FALSE; static int want_regexp; /* lexical scanning kludge */ static int can_return; /* parsing kludge */ -static int begin_or_end_rule = FALSE; /* parsing kludge */ -static int parsing_end_rule = FALSE; /* for warnings */ -static int beginfile_or_endfile_rule = FALSE; /* parsing kludge */ -static int parsing_endfile_rule = FALSE; /* for warnings */ +static int rule = 0; + +const char *const ruletab[] = { + "?", + "BEGIN", + "Rule", + "END", + "BEGINFILE", + "ENDFILE", +}; + static int in_print = FALSE; /* lexical scanning kludge for print */ static int in_parens = 0; /* lexical scanning kludge for print */ -static char *lexptr; /* pointer to next char during parsing */ +static int sub_counter = 0; /* array dimension counter for use in delete */ +static char *lexptr = NULL; /* pointer to next char during parsing */ static char *lexend; static char *lexptr_begin; /* keep track of where we were for error msgs */ static char *lexeme; /* beginning of lexeme for debugging */ +static int lexeof; /* seen EOF for current source? */ static char *thisline = NULL; +static int in_braces = 0; /* count braces for firstline, lastline in an 'action' */ +static int lastline = 0; +static int firstline = 0; +static SRCFILE *sourcefile = NULL; /* current program source */ +static int lasttok = 0; +static int eof_warned = FALSE; /* GLOBAL: want warning for each file */ +static int break_allowed; /* kludge for break */ +static int continue_allowed; /* kludge for continue */ + + +#define END_FILE -1000 +#define END_SRC -2000 + #define YYDEBUG_LEXER_TEXT (lexeme) static int param_counter; +static NODE *func_params; /* list of parameters for the current function */ static char *tokstart = NULL; static char *tok = NULL; static char *tokend; +static int errcount = 0; + +static NODE *symbol_list; +extern void destroy_symbol(char *name); static long func_count; /* total number of functions */ @@ -147,14 +186,25 @@ static int var_count; /* total number of global variables */ extern char *source; extern int sourceline; -extern struct src *srcfiles; -extern long numfiles; -extern int errcount; -extern NODE *begin_block; -extern NODE *end_block; -extern NODE *beginfile_block; -extern NODE *endfile_block; +extern SRCFILE *srcfiles; +extern INSTRUCTION *rule_list; +extern int max_args; + +static INSTRUCTION *rule_block[sizeof(ruletab)]; +static INSTRUCTION *ip_rec; +static INSTRUCTION *ip_newfile; +static INSTRUCTION *ip_atexit = NULL; +static INSTRUCTION *ip_end; +static INSTRUCTION *ip_endfile; +static INSTRUCTION *ip_beginfile; + +static inline INSTRUCTION *list_create(INSTRUCTION *x); +static inline INSTRUCTION *list_append(INSTRUCTION *l, INSTRUCTION *x); +static inline INSTRUCTION *list_prepend(INSTRUCTION *l, INSTRUCTION *x); +static inline INSTRUCTION *list_merge(INSTRUCTION *l1, INSTRUCTION *l2); + +extern double fmod(double x, double y); /* * This string cannot occur as a real awk identifier. * Use it as a special token to make function parsing @@ -166,9 +216,11 @@ extern NODE *endfile_block; */ static char builtin_func[] = "@builtin"; +#define YYSTYPE INSTRUCTION * + /* Line 189 of yacc.c */ -#line 172 "awkgram.c" +#line 224 "awkgram.c" /* Enabling traces. */ #ifndef YYDEBUG @@ -198,7 +250,7 @@ static char builtin_func[] = "@builtin"; FUNC_CALL = 258, NAME = 259, REGEXP = 260, - ERROR = 261, + FILENAME = 261, YNUMBER = 262, YSTRING = 263, RELOP = 264, @@ -208,46 +260,50 @@ static char builtin_func[] = "@builtin"; ASSIGN = 268, MATCHOP = 269, CONCAT_OP = 270, - LEX_BEGIN = 271, - LEX_END = 272, - LEX_IF = 273, - LEX_ELSE = 274, - LEX_RETURN = 275, - LEX_DELETE = 276, - LEX_BEGINFILE = 277, - LEX_ENDFILE = 278, - LEX_SWITCH = 279, - LEX_CASE = 280, - LEX_DEFAULT = 281, - LEX_WHILE = 282, - LEX_DO = 283, - LEX_FOR = 284, - LEX_BREAK = 285, - LEX_CONTINUE = 286, - LEX_PRINT = 287, - LEX_PRINTF = 288, - LEX_NEXT = 289, - LEX_EXIT = 290, - LEX_FUNCTION = 291, - LEX_GETLINE = 292, - LEX_NEXTFILE = 293, - LEX_IN = 294, - LEX_AND = 295, - LEX_OR = 296, - INCREMENT = 297, - DECREMENT = 298, - LEX_BUILTIN = 299, - LEX_LENGTH = 300, - NEWLINE = 301, - SLASH_BEFORE_EQUAL = 302, - UNARY = 303 + SUBSCRIPT = 271, + LEX_BEGIN = 272, + LEX_END = 273, + LEX_IF = 274, + LEX_ELSE = 275, + LEX_RETURN = 276, + LEX_DELETE = 277, + LEX_SWITCH = 278, + LEX_CASE = 279, + LEX_DEFAULT = 280, + LEX_WHILE = 281, + LEX_DO = 282, + LEX_FOR = 283, + LEX_BREAK = 284, + LEX_CONTINUE = 285, + LEX_PRINT = 286, + LEX_PRINTF = 287, + LEX_NEXT = 288, + LEX_EXIT = 289, + LEX_FUNCTION = 290, + LEX_BEGINFILE = 291, + LEX_ENDFILE = 292, + LEX_GETLINE = 293, + LEX_NEXTFILE = 294, + LEX_IN = 295, + LEX_AND = 296, + LEX_OR = 297, + INCREMENT = 298, + DECREMENT = 299, + LEX_BUILTIN = 300, + LEX_LENGTH = 301, + LEX_EOF = 302, + LEX_INCLUDE = 303, + LEX_EVAL = 304, + NEWLINE = 305, + SLASH_BEFORE_EQUAL = 306, + UNARY = 307 }; #endif /* Tokens. */ #define FUNC_CALL 258 #define NAME 259 #define REGEXP 260 -#define ERROR 261 +#define FILENAME 261 #define YNUMBER 262 #define YSTRING 263 #define RELOP 264 @@ -257,62 +313,49 @@ static char builtin_func[] = "@builtin"; #define ASSIGN 268 #define MATCHOP 269 #define CONCAT_OP 270 -#define LEX_BEGIN 271 -#define LEX_END 272 -#define LEX_IF 273 -#define LEX_ELSE 274 -#define LEX_RETURN 275 -#define LEX_DELETE 276 -#define LEX_BEGINFILE 277 -#define LEX_ENDFILE 278 -#define LEX_SWITCH 279 -#define LEX_CASE 280 -#define LEX_DEFAULT 281 -#define LEX_WHILE 282 -#define LEX_DO 283 -#define LEX_FOR 284 -#define LEX_BREAK 285 -#define LEX_CONTINUE 286 -#define LEX_PRINT 287 -#define LEX_PRINTF 288 -#define LEX_NEXT 289 -#define LEX_EXIT 290 -#define LEX_FUNCTION 291 -#define LEX_GETLINE 292 -#define LEX_NEXTFILE 293 -#define LEX_IN 294 -#define LEX_AND 295 -#define LEX_OR 296 -#define INCREMENT 297 -#define DECREMENT 298 -#define LEX_BUILTIN 299 -#define LEX_LENGTH 300 -#define NEWLINE 301 -#define SLASH_BEFORE_EQUAL 302 -#define UNARY 303 +#define SUBSCRIPT 271 +#define LEX_BEGIN 272 +#define LEX_END 273 +#define LEX_IF 274 +#define LEX_ELSE 275 +#define LEX_RETURN 276 +#define LEX_DELETE 277 +#define LEX_SWITCH 278 +#define LEX_CASE 279 +#define LEX_DEFAULT 280 +#define LEX_WHILE 281 +#define LEX_DO 282 +#define LEX_FOR 283 +#define LEX_BREAK 284 +#define LEX_CONTINUE 285 +#define LEX_PRINT 286 +#define LEX_PRINTF 287 +#define LEX_NEXT 288 +#define LEX_EXIT 289 +#define LEX_FUNCTION 290 +#define LEX_BEGINFILE 291 +#define LEX_ENDFILE 292 +#define LEX_GETLINE 293 +#define LEX_NEXTFILE 294 +#define LEX_IN 295 +#define LEX_AND 296 +#define LEX_OR 297 +#define INCREMENT 298 +#define DECREMENT 299 +#define LEX_BUILTIN 300 +#define LEX_LENGTH 301 +#define LEX_EOF 302 +#define LEX_INCLUDE 303 +#define LEX_EVAL 304 +#define NEWLINE 305 +#define SLASH_BEFORE_EQUAL 306 +#define UNARY 307 #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED -typedef union YYSTYPE -{ - -/* Line 214 of yacc.c */ -#line 124 "awkgram.y" - - long lval; - AWKNUM fval; - NODE *nodeval; - NODETYPE nodetypeval; - char *sval; - NODE *(*ptrval) P((void)); - - - -/* Line 214 of yacc.c */ -#line 315 "awkgram.c" -} YYSTYPE; +typedef int YYSTYPE; # define YYSTYPE_IS_TRIVIAL 1 # define yystype YYSTYPE /* obsolescent; will be withdrawn */ # define YYSTYPE_IS_DECLARED 1 @@ -323,7 +366,7 @@ typedef union YYSTYPE /* Line 264 of yacc.c */ -#line 327 "awkgram.c" +#line 370 "awkgram.c" #ifdef short # undef short @@ -395,8 +438,7 @@ typedef short int yytype_int16; #ifndef lint # define YYID(n) (n) #else -#if (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) +#if (defined __STDC__ || defined __C99__FUNC__ || defined __cplusplus || defined _MSC_VER) static int YYID (int yyi) #else @@ -479,9 +521,7 @@ void free (void *); /* INFRINGES ON USER NAME SPACE */ #endif /* ! defined yyoverflow || YYERROR_VERBOSE */ -#if (! defined yyoverflow \ - && (! defined __cplusplus \ - || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL))) +#if (! defined yyoverflow && (! defined __cplusplus || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL))) /* A type that is properly aligned for any stack member. */ union yyalloc @@ -536,22 +576,22 @@ union yyalloc #endif /* YYFINAL -- State number of the termination state. */ -#define YYFINAL 5 +#define YYFINAL 2 /* YYLAST -- Last index in YYTABLE. */ -#define YYLAST 1105 +#define YYLAST 1142 /* YYNTOKENS -- Number of terminals. */ -#define YYNTOKENS 70 +#define YYNTOKENS 74 /* YYNNTS -- Number of nonterminals. */ -#define YYNNTS 58 +#define YYNNTS 66 /* YYNRULES -- Number of rules. */ -#define YYNRULES 170 +#define YYNRULES 186 /* YYNRULES -- Number of states. */ -#define YYNSTATES 314 +#define YYNSTATES 330 /* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */ #define YYUNDEFTOK 2 -#define YYMAXUTOK 303 +#define YYMAXUTOK 307 #define YYTRANSLATE(YYX) \ ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK) @@ -562,16 +602,16 @@ static const yytype_uint8 yytranslate[] = 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 58, 2, 2, 61, 57, 2, 2, - 62, 63, 55, 53, 50, 54, 2, 56, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 49, 69, - 51, 2, 52, 48, 66, 2, 2, 2, 2, 2, + 2, 2, 2, 62, 2, 2, 65, 61, 2, 2, + 66, 67, 59, 57, 54, 58, 2, 60, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 53, 73, + 55, 2, 56, 52, 68, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 64, 2, 65, 60, 2, 2, 2, 2, 2, + 2, 69, 2, 70, 64, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 67, 2, 68, 2, 2, 2, 2, + 2, 2, 2, 71, 2, 72, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, @@ -589,7 +629,7 @@ static const yytype_uint8 yytranslate[] = 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, - 45, 46, 47, 59 + 45, 46, 47, 48, 49, 50, 51, 63 }; #if YYDEBUG @@ -597,106 +637,112 @@ static const yytype_uint8 yytranslate[] = YYRHS. */ static const yytype_uint16 yyprhs[] = { - 0, 0, 3, 7, 8, 11, 14, 17, 20, 23, - 24, 26, 30, 32, 34, 36, 38, 44, 46, 48, - 50, 52, 54, 55, 63, 64, 68, 70, 72, 73, - 76, 79, 81, 84, 87, 91, 93, 103, 110, 119, - 128, 141, 153, 156, 159, 162, 165, 169, 170, 175, - 178, 179, 184, 190, 193, 198, 200, 201, 203, 205, - 206, 209, 212, 218, 223, 225, 228, 231, 233, 235, - 237, 239, 241, 247, 248, 249, 253, 260, 270, 272, - 275, 276, 278, 279, 282, 283, 285, 287, 291, 293, - 296, 300, 301, 303, 304, 306, 308, 312, 314, 317, - 321, 325, 329, 333, 337, 341, 345, 349, 355, 357, - 359, 361, 364, 366, 368, 370, 372, 374, 376, 379, - 381, 385, 389, 393, 397, 401, 405, 409, 412, 415, - 421, 426, 430, 434, 438, 442, 446, 450, 452, 455, - 459, 464, 469, 471, 473, 475, 478, 481, 483, 485, - 488, 491, 493, 496, 501, 502, 504, 506, 511, 513, - 517, 519, 521, 522, 525, 528, 530, 531, 533, 535, - 537 + 0, 0, 3, 4, 7, 10, 13, 16, 19, 22, + 25, 30, 32, 35, 37, 38, 40, 44, 46, 48, + 50, 52, 58, 60, 62, 64, 67, 69, 71, 72, + 80, 81, 85, 87, 89, 90, 93, 96, 98, 101, + 104, 108, 110, 120, 127, 136, 145, 158, 170, 172, + 175, 178, 181, 184, 188, 189, 194, 197, 198, 203, + 204, 209, 214, 216, 217, 219, 221, 222, 225, 228, + 234, 239, 241, 244, 247, 249, 251, 253, 255, 257, + 261, 262, 263, 267, 274, 284, 286, 289, 290, 292, + 293, 296, 297, 299, 301, 305, 307, 310, 314, 315, + 317, 318, 320, 322, 326, 328, 331, 335, 339, 343, + 347, 351, 355, 359, 363, 369, 371, 373, 375, 378, + 380, 382, 384, 386, 388, 390, 393, 395, 399, 403, + 407, 411, 415, 419, 423, 426, 429, 435, 440, 444, + 448, 452, 456, 460, 464, 466, 469, 473, 478, 483, + 485, 487, 489, 492, 495, 497, 499, 502, 505, 507, + 510, 515, 516, 518, 519, 522, 524, 527, 529, 533, + 535, 538, 541, 543, 546, 548, 552, 554, 556, 557, + 560, 563, 565, 566, 568, 570, 572 }; /* YYRHS -- A `-1'-separated list of the rules' RHS. */ -static const yytype_int8 yyrhs[] = +static const yytype_int16 yyrhs[] = { - 71, 0, -1, 100, 72, 100, -1, -1, 72, 73, - -1, 72, 1, -1, 74, 75, -1, 74, 84, -1, - 78, 75, -1, -1, 107, -1, 107, 50, 107, -1, - 16, -1, 17, -1, 22, -1, 23, -1, 121, 83, - 122, 124, 100, -1, 4, -1, 3, -1, 77, -1, - 44, -1, 45, -1, -1, 36, 79, 76, 62, 102, - 123, 100, -1, -1, 82, 81, 5, -1, 56, -1, - 47, -1, -1, 83, 85, -1, 83, 1, -1, 99, - -1, 125, 100, -1, 125, 100, -1, 121, 83, 122, - -1, 98, -1, 24, 62, 107, 123, 100, 121, 90, - 100, 122, -1, 27, 62, 107, 123, 100, 85, -1, - 28, 100, 85, 27, 62, 107, 123, 100, -1, 29, - 62, 4, 39, 4, 123, 100, 85, -1, 29, 62, - 89, 125, 100, 107, 125, 100, 89, 123, 100, 85, - -1, 29, 62, 89, 125, 100, 125, 100, 89, 123, - 100, 85, -1, 30, 84, -1, 31, 84, -1, 34, - 84, -1, 38, 84, -1, 35, 104, 84, -1, -1, - 20, 86, 104, 84, -1, 87, 84, -1, -1, 94, - 88, 95, 96, -1, 21, 4, 64, 106, 65, -1, - 21, 4, -1, 21, 62, 4, 63, -1, 107, -1, - -1, 87, -1, 91, -1, -1, 91, 92, -1, 91, - 1, -1, 25, 93, 126, 100, 83, -1, 26, 126, - 100, 83, -1, 7, -1, 54, 7, -1, 53, 7, - -1, 8, -1, 80, -1, 32, -1, 33, -1, 105, - -1, 62, 107, 127, 106, 123, -1, -1, -1, 10, - 97, 111, -1, 18, 62, 107, 123, 100, 85, -1, - 18, 62, 107, 123, 100, 85, 19, 100, 85, -1, - 46, -1, 99, 46, -1, -1, 99, -1, -1, 51, - 112, -1, -1, 103, -1, 4, -1, 103, 127, 4, - -1, 1, -1, 103, 1, -1, 103, 127, 1, -1, - -1, 107, -1, -1, 106, -1, 107, -1, 106, 127, - 107, -1, 1, -1, 106, 1, -1, 106, 1, 107, - -1, 106, 127, 1, -1, 118, 108, 107, -1, 107, - 40, 107, -1, 107, 41, 107, -1, 107, 14, 107, - -1, 107, 39, 4, -1, 107, 110, 107, -1, 107, - 48, 107, 49, 107, -1, 111, -1, 13, -1, 12, - -1, 47, 13, -1, 9, -1, 51, -1, 109, -1, - 52, -1, 112, -1, 113, -1, 111, 112, -1, 114, - -1, 112, 60, 112, -1, 112, 55, 112, -1, 112, - 56, 112, -1, 112, 57, 112, -1, 112, 53, 112, - -1, 112, 54, 112, -1, 37, 117, 101, -1, 118, - 42, -1, 118, 43, -1, 62, 106, 123, 39, 4, - -1, 111, 11, 37, 117, -1, 113, 60, 112, -1, - 113, 55, 112, -1, 113, 56, 112, -1, 113, 57, - 112, -1, 113, 53, 112, -1, 113, 54, 112, -1, - 80, -1, 58, 112, -1, 62, 107, 123, -1, 44, - 62, 105, 123, -1, 45, 62, 105, 123, -1, 45, - -1, 115, -1, 118, -1, 42, 118, -1, 43, 118, - -1, 7, -1, 8, -1, 54, 112, -1, 53, 112, - -1, 116, -1, 66, 116, -1, 3, 62, 105, 123, - -1, -1, 118, -1, 4, -1, 4, 64, 106, 65, - -1, 119, -1, 61, 114, 120, -1, 42, -1, 43, - -1, -1, 67, 100, -1, 68, 100, -1, 63, -1, - -1, 125, -1, 69, -1, 49, -1, 50, 100, -1 + 75, 0, -1, -1, 75, 76, -1, 75, 105, -1, + 75, 47, -1, 75, 1, -1, 78, 79, -1, 78, + 88, -1, 82, 79, -1, 68, 48, 77, 88, -1, + 6, -1, 6, 1, -1, 1, -1, -1, 113, -1, + 113, 54, 113, -1, 17, -1, 18, -1, 36, -1, + 37, -1, 133, 87, 134, 136, 106, -1, 4, -1, + 3, -1, 81, -1, 68, 49, -1, 45, -1, 46, + -1, -1, 35, 83, 80, 66, 108, 135, 106, -1, + -1, 86, 85, 5, -1, 60, -1, 51, -1, -1, + 87, 89, -1, 87, 1, -1, 105, -1, 137, 106, + -1, 137, 106, -1, 133, 87, 134, -1, 104, -1, + 23, 66, 113, 135, 106, 133, 96, 106, 134, -1, + 26, 66, 113, 135, 106, 89, -1, 27, 106, 89, + 26, 66, 113, 135, 106, -1, 28, 66, 4, 40, + 130, 135, 106, 89, -1, 28, 66, 95, 137, 106, + 113, 137, 106, 95, 135, 106, 89, -1, 28, 66, + 95, 137, 106, 137, 106, 95, 135, 106, 89, -1, + 90, -1, 29, 88, -1, 30, 88, -1, 33, 88, + -1, 39, 88, -1, 34, 110, 88, -1, -1, 21, + 91, 110, 88, -1, 92, 88, -1, -1, 100, 93, + 101, 102, -1, -1, 22, 4, 94, 124, -1, 22, + 66, 4, 67, -1, 113, -1, -1, 92, -1, 97, + -1, -1, 97, 98, -1, 97, 1, -1, 24, 99, + 138, 106, 87, -1, 25, 138, 106, 87, -1, 7, + -1, 58, 7, -1, 57, 7, -1, 8, -1, 84, + -1, 31, -1, 32, -1, 111, -1, 66, 112, 135, + -1, -1, -1, 10, 103, 117, -1, 19, 66, 113, + 135, 106, 89, -1, 19, 66, 113, 135, 106, 89, + 20, 106, 89, -1, 50, -1, 105, 50, -1, -1, + 105, -1, -1, 55, 118, -1, -1, 109, -1, 4, + -1, 109, 139, 4, -1, 1, -1, 109, 1, -1, + 109, 139, 1, -1, -1, 113, -1, -1, 112, -1, + 113, -1, 112, 139, 113, -1, 1, -1, 112, 1, + -1, 112, 1, 113, -1, 112, 139, 1, -1, 131, + 114, 113, -1, 113, 41, 113, -1, 113, 42, 113, + -1, 113, 14, 113, -1, 113, 40, 130, -1, 113, + 116, 113, -1, 113, 52, 113, 53, 113, -1, 117, + -1, 13, -1, 12, -1, 51, 13, -1, 9, -1, + 55, -1, 115, -1, 56, -1, 118, -1, 119, -1, + 117, 118, -1, 120, -1, 118, 64, 118, -1, 118, + 59, 118, -1, 118, 60, 118, -1, 118, 61, 118, + -1, 118, 57, 118, -1, 118, 58, 118, -1, 38, + 123, 107, -1, 131, 43, -1, 131, 44, -1, 66, + 112, 135, 40, 130, -1, 117, 11, 38, 123, -1, + 119, 64, 118, -1, 119, 59, 118, -1, 119, 60, + 118, -1, 119, 61, 118, -1, 119, 57, 118, -1, + 119, 58, 118, -1, 84, -1, 62, 118, -1, 66, + 113, 135, -1, 45, 66, 111, 135, -1, 46, 66, + 111, 135, -1, 46, -1, 121, -1, 131, -1, 43, + 131, -1, 44, 131, -1, 7, -1, 8, -1, 58, + 118, -1, 57, 118, -1, 122, -1, 68, 122, -1, + 3, 66, 111, 135, -1, -1, 131, -1, -1, 125, + 16, -1, 126, -1, 125, 126, -1, 127, -1, 69, + 112, 70, -1, 127, -1, 128, 127, -1, 128, 16, + -1, 4, -1, 4, 129, -1, 130, -1, 65, 120, + 132, -1, 43, -1, 44, -1, -1, 71, 106, -1, + 72, 106, -1, 67, -1, -1, 137, -1, 73, -1, + 53, -1, 54, 106, -1 }; /* YYRLINE[YYN] -- source line where rule number YYN was defined. */ static const yytype_uint16 yyrline[] = { - 0, 187, 187, 193, 195, 200, 212, 216, 234, 245, - 248, 252, 262, 271, 280, 285, 293, 298, 300, 302, - 313, 314, 319, 318, 342, 341, 367, 368, 373, 374, - 392, 397, 398, 402, 404, 406, 408, 410, 412, 414, - 458, 462, 467, 470, 473, 485, 523, 526, 525, 535, - 547, 547, 578, 580, 598, 620, 626, 627, 632, 685, - 686, 703, 708, 710, 715, 717, 722, 724, 726, 731, - 732, 740, 741, 747, 752, 752, 764, 769, 776, 777, - 780, 782, 787, 788, 794, 795, 800, 802, 804, 806, - 808, 815, 816, 822, 823, 828, 830, 836, 838, 840, - 842, 847, 853, 855, 857, 863, 869, 875, 877, 882, - 884, 886, 891, 893, 897, 898, 903, 905, 907, 912, - 914, 916, 918, 920, 922, 924, 926, 947, 949, 951, - 964, 969, 971, 973, 975, 977, 979, 984, 986, 988, - 990, 993, 995, 1009, 1010, 1011, 1013, 1015, 1017, 1020, - 1028, 1039, 1044, 1060, 1071, 1072, 1077, 1079, 1094, 1104, - 1119, 1120, 1121, 1125, 1129, 1133, 1136, 1138, 1142, 1146, - 1149 + 0, 215, 215, 217, 222, 223, 227, 239, 243, 254, + 262, 270, 279, 281, 287, 288, 290, 316, 326, 336, + 342, 351, 361, 363, 365, 376, 381, 382, 387, 386, + 416, 415, 446, 448, 453, 454, 467, 472, 473, 477, + 479, 481, 488, 509, 555, 598, 708, 715, 722, 732, + 741, 750, 757, 782, 797, 796, 808, 820, 820, 916, + 916, 944, 970, 976, 977, 982, 1035, 1036, 1048, 1053, + 1072, 1090, 1095, 1102, 1108, 1113, 1121, 1123, 1132, 1133, + 1141, 1146, 1146, 1157, 1161, 1169, 1170, 1173, 1175, 1180, + 1181, 1188, 1190, 1194, 1200, 1207, 1209, 1211, 1218, 1219, + 1225, 1226, 1231, 1233, 1238, 1240, 1242, 1244, 1250, 1256, + 1258, 1260, 1275, 1284, 1290, 1292, 1297, 1299, 1301, 1309, + 1311, 1316, 1318, 1323, 1325, 1327, 1375, 1377, 1379, 1381, + 1383, 1385, 1387, 1389, 1410, 1415, 1420, 1443, 1449, 1451, + 1453, 1455, 1457, 1459, 1464, 1468, 1508, 1510, 1516, 1522, + 1534, 1535, 1536, 1541, 1546, 1550, 1554, 1566, 1579, 1584, + 1620, 1638, 1639, 1645, 1646, 1651, 1653, 1660, 1677, 1694, + 1696, 1703, 1708, 1716, 1730, 1742, 1751, 1755, 1759, 1763, + 1767, 1771, 1774, 1776, 1780, 1784, 1788 }; #endif @@ -705,29 +751,31 @@ static const yytype_uint16 yyrline[] = First, the terminals, then, starting at YYNTOKENS, nonterminals. */ static const char *const yytname[] = { - "$end", "error", "$undefined", "FUNC_CALL", "NAME", "REGEXP", "ERROR", - "YNUMBER", "YSTRING", "RELOP", "IO_OUT", "IO_IN", "ASSIGNOP", "ASSIGN", - "MATCHOP", "CONCAT_OP", "LEX_BEGIN", "LEX_END", "LEX_IF", "LEX_ELSE", - "LEX_RETURN", "LEX_DELETE", "LEX_BEGINFILE", "LEX_ENDFILE", "LEX_SWITCH", + "$end", "error", "$undefined", "FUNC_CALL", "NAME", "REGEXP", + "FILENAME", "YNUMBER", "YSTRING", "RELOP", "IO_OUT", "IO_IN", "ASSIGNOP", + "ASSIGN", "MATCHOP", "CONCAT_OP", "SUBSCRIPT", "LEX_BEGIN", "LEX_END", + "LEX_IF", "LEX_ELSE", "LEX_RETURN", "LEX_DELETE", "LEX_SWITCH", "LEX_CASE", "LEX_DEFAULT", "LEX_WHILE", "LEX_DO", "LEX_FOR", "LEX_BREAK", "LEX_CONTINUE", "LEX_PRINT", "LEX_PRINTF", "LEX_NEXT", "LEX_EXIT", - "LEX_FUNCTION", "LEX_GETLINE", "LEX_NEXTFILE", "LEX_IN", "LEX_AND", - "LEX_OR", "INCREMENT", "DECREMENT", "LEX_BUILTIN", "LEX_LENGTH", + "LEX_FUNCTION", "LEX_BEGINFILE", "LEX_ENDFILE", "LEX_GETLINE", + "LEX_NEXTFILE", "LEX_IN", "LEX_AND", "LEX_OR", "INCREMENT", "DECREMENT", + "LEX_BUILTIN", "LEX_LENGTH", "LEX_EOF", "LEX_INCLUDE", "LEX_EVAL", "NEWLINE", "SLASH_BEFORE_EQUAL", "'?'", "':'", "','", "'<'", "'>'", "'+'", "'-'", "'*'", "'/'", "'%'", "'!'", "UNARY", "'^'", "'$'", "'('", - "')'", "'['", "']'", "'@'", "'{'", "'}'", "';'", "$accept", "start", - "program", "rule", "pattern", "action", "func_name", "lex_builtin", + "')'", "'@'", "'['", "']'", "'{'", "'}'", "';'", "$accept", "program", + "rule", "source", "pattern", "action", "func_name", "lex_builtin", "function_prologue", "$@1", "regexp", "$@2", "a_slash", "statements", - "statement_term", "statement", "$@3", "simple_stmt", "$@4", - "opt_simple_stmt", "switch_body", "case_statements", "case_statement", - "case_value", "print", "print_expression_list", "output_redir", "$@5", - "if_statement", "nls", "opt_nls", "input_redir", "opt_param_list", - "param_list", "opt_exp", "opt_expression_list", "expression_list", "exp", - "assign_operator", "relop_or_less", "a_relop", "common_exp", "simp_exp", - "simp_exp_nc", "non_post_simp_exp", "function_call", - "direct_function_call", "opt_variable", "variable", "field_spec", - "opt_incdec", "l_brace", "r_brace", "r_paren", "opt_semi", "semi", - "colon", "comma", 0 + "statement_term", "statement", "non_compound_stmt", "$@3", "simple_stmt", + "$@4", "$@5", "opt_simple_stmt", "switch_body", "case_statements", + "case_statement", "case_value", "print", "print_expression_list", + "output_redir", "$@6", "if_statement", "nls", "opt_nls", "input_redir", + "opt_param_list", "param_list", "opt_exp", "opt_expression_list", + "expression_list", "exp", "assign_operator", "relop_or_less", "a_relop", + "common_exp", "simp_exp", "simp_exp_nc", "non_post_simp_exp", + "func_call", "direct_func_call", "opt_variable", "delete_subscript_list", + "delete_subscript", "delete_exp_list", "bracketed_exp_list", "subscript", + "subscript_list", "simple_variable", "variable", "opt_incdec", "l_brace", + "r_brace", "r_paren", "opt_semi", "semi", "colon", "comma", 0 }; #endif @@ -740,56 +788,59 @@ static const yytype_uint16 yytoknum[] = 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, - 295, 296, 297, 298, 299, 300, 301, 302, 63, 58, - 44, 60, 62, 43, 45, 42, 47, 37, 33, 303, - 94, 36, 40, 41, 91, 93, 64, 123, 125, 59 + 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, + 305, 306, 63, 58, 44, 60, 62, 43, 45, 42, + 47, 37, 33, 307, 94, 36, 40, 41, 64, 91, + 93, 123, 125, 59 }; # endif /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ static const yytype_uint8 yyr1[] = { - 0, 70, 71, 72, 72, 72, 73, 73, 73, 74, - 74, 74, 74, 74, 74, 74, 75, 76, 76, 76, - 77, 77, 79, 78, 81, 80, 82, 82, 83, 83, - 83, 84, 84, 85, 85, 85, 85, 85, 85, 85, - 85, 85, 85, 85, 85, 85, 85, 86, 85, 85, - 88, 87, 87, 87, 87, 87, 89, 89, 90, 91, - 91, 91, 92, 92, 93, 93, 93, 93, 93, 94, - 94, 95, 95, 96, 97, 96, 98, 98, 99, 99, - 100, 100, 101, 101, 102, 102, 103, 103, 103, 103, - 103, 104, 104, 105, 105, 106, 106, 106, 106, 106, - 106, 107, 107, 107, 107, 107, 107, 107, 107, 108, - 108, 108, 109, 109, 110, 110, 111, 111, 111, 112, - 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, - 113, 113, 113, 113, 113, 113, 113, 114, 114, 114, - 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, - 114, 115, 115, 116, 117, 117, 118, 118, 118, 119, - 120, 120, 120, 121, 122, 123, 124, 124, 125, 126, - 127 + 0, 74, 75, 75, 75, 75, 75, 76, 76, 76, + 76, 77, 77, 77, 78, 78, 78, 78, 78, 78, + 78, 79, 80, 80, 80, 80, 81, 81, 83, 82, + 85, 84, 86, 86, 87, 87, 87, 88, 88, 89, + 89, 89, 89, 89, 89, 89, 89, 89, 89, 90, + 90, 90, 90, 90, 91, 90, 90, 93, 92, 94, + 92, 92, 92, 95, 95, 96, 97, 97, 97, 98, + 98, 99, 99, 99, 99, 99, 100, 100, 101, 101, + 102, 103, 102, 104, 104, 105, 105, 106, 106, 107, + 107, 108, 108, 109, 109, 109, 109, 109, 110, 110, + 111, 111, 112, 112, 112, 112, 112, 112, 113, 113, + 113, 113, 113, 113, 113, 113, 114, 114, 114, 115, + 115, 116, 116, 117, 117, 117, 118, 118, 118, 118, + 118, 118, 118, 118, 118, 118, 118, 119, 119, 119, + 119, 119, 119, 119, 120, 120, 120, 120, 120, 120, + 120, 120, 120, 120, 120, 120, 120, 120, 121, 121, + 122, 123, 123, 124, 124, 125, 125, 126, 127, 128, + 128, 129, 130, 130, 131, 131, 132, 132, 132, 133, + 134, 135, 136, 136, 137, 138, 139 }; /* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */ static const yytype_uint8 yyr2[] = { - 0, 2, 3, 0, 2, 2, 2, 2, 2, 0, - 1, 3, 1, 1, 1, 1, 5, 1, 1, 1, - 1, 1, 0, 7, 0, 3, 1, 1, 0, 2, - 2, 1, 2, 2, 3, 1, 9, 6, 8, 8, - 12, 11, 2, 2, 2, 2, 3, 0, 4, 2, - 0, 4, 5, 2, 4, 1, 0, 1, 1, 0, - 2, 2, 5, 4, 1, 2, 2, 1, 1, 1, - 1, 1, 5, 0, 0, 3, 6, 9, 1, 2, - 0, 1, 0, 2, 0, 1, 1, 3, 1, 2, - 3, 0, 1, 0, 1, 1, 3, 1, 2, 3, - 3, 3, 3, 3, 3, 3, 3, 5, 1, 1, - 1, 2, 1, 1, 1, 1, 1, 1, 2, 1, - 3, 3, 3, 3, 3, 3, 3, 2, 2, 5, - 4, 3, 3, 3, 3, 3, 3, 1, 2, 3, - 4, 4, 1, 1, 1, 2, 2, 1, 1, 2, - 2, 1, 2, 4, 0, 1, 1, 4, 1, 3, - 1, 1, 0, 2, 2, 1, 0, 1, 1, 1, - 2 + 0, 2, 0, 2, 2, 2, 2, 2, 2, 2, + 4, 1, 2, 1, 0, 1, 3, 1, 1, 1, + 1, 5, 1, 1, 1, 2, 1, 1, 0, 7, + 0, 3, 1, 1, 0, 2, 2, 1, 2, 2, + 3, 1, 9, 6, 8, 8, 12, 11, 1, 2, + 2, 2, 2, 3, 0, 4, 2, 0, 4, 0, + 4, 4, 1, 0, 1, 1, 0, 2, 2, 5, + 4, 1, 2, 2, 1, 1, 1, 1, 1, 3, + 0, 0, 3, 6, 9, 1, 2, 0, 1, 0, + 2, 0, 1, 1, 3, 1, 2, 3, 0, 1, + 0, 1, 1, 3, 1, 2, 3, 3, 3, 3, + 3, 3, 3, 3, 5, 1, 1, 1, 2, 1, + 1, 1, 1, 1, 1, 2, 1, 3, 3, 3, + 3, 3, 3, 3, 2, 2, 5, 4, 3, 3, + 3, 3, 3, 3, 1, 2, 3, 4, 4, 1, + 1, 1, 2, 2, 1, 1, 2, 2, 1, 2, + 4, 0, 1, 0, 2, 1, 2, 1, 3, 1, + 2, 2, 1, 2, 1, 3, 1, 1, 0, 2, + 2, 1, 0, 1, 1, 1, 2 }; /* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state @@ -797,372 +848,385 @@ static const yytype_uint8 yyr2[] = means the default is an error. */ static const yytype_uint8 yydefact[] = { - 80, 78, 0, 81, 3, 1, 79, 0, 5, 0, - 156, 147, 148, 12, 13, 14, 15, 22, 154, 0, - 0, 0, 142, 27, 0, 0, 26, 0, 0, 0, - 0, 4, 0, 0, 137, 24, 2, 10, 108, 116, - 117, 119, 143, 151, 144, 158, 0, 0, 0, 82, - 155, 145, 146, 0, 0, 150, 144, 149, 138, 0, - 162, 144, 97, 0, 95, 152, 80, 168, 6, 7, - 31, 28, 80, 8, 0, 112, 0, 0, 0, 0, - 0, 0, 113, 115, 114, 0, 0, 118, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 110, 109, 127, 128, 0, 0, 0, 0, 95, 0, - 18, 17, 20, 21, 0, 19, 0, 126, 0, 0, - 0, 160, 161, 159, 98, 80, 165, 0, 0, 139, - 163, 0, 32, 25, 104, 105, 102, 103, 0, 11, - 106, 154, 124, 125, 121, 122, 123, 120, 135, 136, - 132, 133, 134, 131, 111, 101, 153, 157, 0, 83, - 140, 141, 99, 170, 0, 100, 96, 30, 0, 47, - 0, 0, 0, 80, 0, 0, 0, 69, 70, 0, - 91, 0, 80, 29, 0, 50, 35, 55, 28, 166, - 80, 0, 130, 88, 86, 0, 0, 129, 0, 91, - 53, 0, 0, 0, 0, 56, 42, 43, 44, 0, - 92, 45, 164, 49, 0, 0, 80, 167, 33, 107, - 80, 89, 0, 0, 0, 0, 0, 0, 0, 0, - 156, 57, 0, 46, 0, 73, 71, 34, 16, 23, - 90, 87, 80, 48, 0, 54, 80, 80, 0, 0, - 80, 95, 74, 51, 0, 52, 0, 0, 0, 0, - 0, 0, 0, 76, 59, 37, 0, 80, 0, 80, - 0, 75, 80, 80, 0, 80, 0, 80, 56, 72, - 0, 0, 61, 0, 0, 60, 38, 39, 56, 0, - 77, 36, 64, 67, 0, 0, 68, 0, 169, 80, - 0, 80, 66, 65, 80, 28, 80, 0, 28, 0, - 0, 41, 0, 40 + 2, 0, 1, 6, 0, 172, 154, 155, 17, 18, + 28, 19, 20, 161, 0, 0, 0, 149, 5, 85, + 33, 0, 0, 32, 0, 0, 0, 0, 3, 0, + 0, 144, 30, 4, 15, 115, 123, 124, 126, 150, + 158, 174, 151, 0, 0, 169, 0, 173, 0, 89, + 162, 152, 153, 0, 0, 0, 157, 151, 156, 145, + 0, 178, 151, 104, 0, 102, 0, 159, 87, 184, + 7, 8, 37, 34, 87, 9, 0, 86, 119, 0, + 0, 0, 0, 0, 0, 120, 122, 121, 0, 0, + 125, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 117, 116, 134, 135, 0, 0, 0, + 0, 102, 0, 171, 170, 23, 22, 26, 27, 0, + 0, 24, 0, 133, 0, 0, 0, 176, 177, 175, + 105, 87, 181, 0, 0, 146, 13, 0, 0, 88, + 179, 0, 38, 31, 111, 112, 109, 110, 0, 16, + 113, 161, 131, 132, 128, 129, 130, 127, 142, 143, + 139, 140, 141, 138, 118, 108, 160, 168, 25, 0, + 90, 147, 148, 106, 186, 0, 107, 103, 12, 10, + 36, 0, 54, 0, 0, 0, 87, 0, 0, 0, + 76, 77, 0, 98, 0, 87, 35, 48, 0, 57, + 41, 62, 34, 182, 87, 0, 137, 95, 93, 0, + 0, 136, 0, 98, 59, 0, 0, 0, 0, 63, + 49, 50, 51, 0, 99, 52, 180, 56, 0, 0, + 87, 183, 39, 114, 87, 96, 0, 0, 0, 163, + 0, 0, 0, 0, 172, 64, 0, 53, 0, 80, + 78, 40, 21, 29, 97, 94, 87, 55, 60, 0, + 165, 167, 61, 87, 87, 0, 0, 87, 0, 81, + 58, 0, 164, 166, 0, 0, 0, 0, 0, 79, + 0, 83, 66, 43, 0, 87, 0, 87, 82, 87, + 87, 0, 87, 0, 87, 63, 0, 0, 68, 0, + 0, 67, 44, 45, 63, 0, 84, 42, 71, 74, + 0, 0, 75, 0, 185, 87, 0, 87, 73, 72, + 87, 34, 87, 0, 34, 0, 0, 47, 0, 46 }; /* YYDEFGOTO[NTERM-NUM]. */ static const yytype_int16 yydefgoto[] = { - -1, 2, 7, 31, 32, 68, 114, 115, 33, 48, - 34, 74, 35, 131, 69, 183, 199, 184, 214, 232, - 273, 274, 285, 297, 185, 235, 253, 262, 186, 3, - 4, 117, 195, 196, 209, 106, 107, 187, 105, 84, - 85, 38, 39, 40, 41, 42, 43, 49, 44, 45, - 123, 188, 189, 129, 216, 190, 299, 128 + -1, 1, 28, 138, 29, 70, 120, 121, 30, 48, + 31, 76, 32, 141, 71, 196, 197, 213, 198, 228, + 239, 246, 290, 291, 301, 313, 199, 249, 270, 280, + 200, 139, 140, 123, 209, 210, 223, 109, 110, 201, + 108, 87, 88, 35, 36, 37, 38, 39, 40, 49, + 258, 259, 260, 45, 46, 47, 41, 42, 129, 202, + 203, 135, 230, 204, 315, 134 }; /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing STATE-NUM. */ -#define YYPACT_NINF -263 +#define YYPACT_NINF -267 static const yytype_int16 yypact[] = { - -27, -263, 29, -23, -263, -263, -263, 365, -263, -21, - -18, -263, -263, -263, -263, -263, -263, -263, 9, 9, - 9, -15, -10, -263, 1014, 1014, -263, 1014, 1039, 792, - 48, -263, -31, -14, -263, -263, -263, 712, 958, 195, - 274, -263, -263, -263, 176, -263, 764, 792, 126, 3, - -263, -263, -263, 764, 764, 2, -11, 2, 2, 1014, - -8, -263, -263, 44, 389, -263, -27, -263, -263, -263, - -23, -263, -27, -263, 58, -263, 1014, 65, 1014, 1014, - 1014, 1014, -263, -263, -263, 1014, 31, 195, 1014, 1014, - 1014, 1014, 1014, 1014, 1014, 1014, 1014, 1014, 1014, 1014, - -263, -263, -263, -263, 83, 1014, 42, 10, 907, 21, - -263, -263, -263, -263, 50, -263, 1014, -263, 42, 42, - 389, -263, -263, -263, 1014, -27, -263, 75, 848, -263, - -263, 547, -263, -263, 117, -263, 194, 97, 824, 907, - 52, 9, 181, 181, 2, 2, 2, 2, 181, 181, - 2, 2, 2, 2, -263, 907, -263, -263, 17, 195, - -263, -263, 907, -263, 111, -263, 907, -263, 54, -263, - 4, 55, 59, -27, 61, -29, -29, -263, -263, -29, - 1014, -29, -27, -263, -29, -263, -263, 907, -263, 56, - -27, 1014, -263, -263, -263, 42, 47, -263, 1014, 1014, - 63, 124, 1014, 1014, 680, 875, -263, -263, -263, -29, - 907, -263, -263, -263, 616, 547, -27, -263, -263, 907, - -27, -263, 23, 389, -29, 792, 69, 389, 389, 106, - -25, -263, 56, -263, 792, 125, -263, -263, -263, -263, - -263, -263, -27, -263, 43, -263, -27, -27, 72, 135, - -27, 588, -263, -263, 680, -263, -14, 680, 1014, 42, - 736, 792, 1014, 123, -263, -263, 389, -27, 306, -27, - 44, 958, -27, -27, 32, -27, 680, -27, 931, -263, - 680, 82, -263, 91, 102, -263, -263, -263, 931, 42, - -263, -263, -263, -263, 139, 158, -263, 102, -263, -27, - 42, -27, -263, -263, -27, -263, -27, 680, -263, 435, - 680, -263, 491, -263 + -267, 330, -267, -267, -36, -37, -267, -267, -267, -267, + -267, -267, -267, 20, 20, 20, -30, -20, -267, -267, + -267, 973, 973, -267, 973, 1018, 799, 6, -267, -15, + -21, -267, -267, 10, 1057, 947, 300, 325, -267, -267, + -267, -267, 299, 731, 799, -267, 53, -267, 112, 66, + -267, -267, -267, 731, 731, 122, 70, -3, 70, 70, + 973, 88, -267, -267, 50, 1051, 25, -267, 97, -267, + -267, -267, 10, -267, 97, -267, 143, -267, -267, 973, + 146, 973, 973, 973, 973, -267, -267, -267, 973, 113, + 300, 973, 973, 973, 973, 973, 973, 973, 973, 973, + 973, 973, 973, -267, -267, -267, -267, 139, 973, 87, + 118, 1086, 7, -267, -267, -267, -267, -267, -267, 121, + 96, -267, 973, -267, 87, 87, 1051, -267, -267, -267, + 973, 97, -267, 137, 825, -267, -267, 36, -16, 10, + -267, 547, -267, -267, 19, -267, 260, 251, 1080, 1086, + 105, 20, 115, 115, 70, 70, 70, 70, 115, 115, + 70, 70, 70, 70, -267, 1086, -267, -267, -267, 63, + 300, -267, -267, 1086, -267, 146, -267, 1086, -267, -267, + -267, 116, -267, 45, 120, 124, 97, 129, -16, -16, + -267, -267, -16, 973, -16, 97, -267, -267, -16, -267, + -267, 1086, -267, 123, 97, 973, -267, -267, -267, 87, + 117, -267, 973, 973, -267, 193, 973, 973, 660, 870, + -267, -267, -267, -16, 1086, -267, -267, -267, 593, 547, + 97, -267, -267, 1086, 97, -267, 72, 1051, -16, -37, + 133, 1051, 1051, 175, -22, -267, 123, -267, 799, 192, + -267, -267, -267, -267, -267, -267, 97, -267, -267, 90, + -267, -267, -267, 97, 97, 141, 146, 97, 50, -267, + -267, 660, -267, -267, -21, 660, 973, 87, 705, 137, + 973, 183, -267, -267, 1051, 97, 262, 97, 947, 97, + 97, 38, 97, 660, 97, 902, 660, 136, -267, 198, + 156, -267, -267, -267, 902, 87, -267, -267, -267, -267, + 203, 210, -267, 156, -267, 97, 87, 97, -267, -267, + 97, -267, 97, 660, -267, 401, 660, -267, 474, -267 }; /* YYPGOTO[NTERM-NUM]. */ static const yytype_int16 yypgoto[] = { - -263, -263, -263, -263, -263, 145, -263, -263, -263, -263, - -111, -263, -263, -186, 114, -167, -263, -193, -263, -262, - -263, -263, -263, -263, -263, -263, -263, -263, -263, -2, - -7, -263, -263, -263, -13, -47, -19, -4, -263, -263, - -263, -81, 187, -263, 157, -263, 160, 51, 64, -263, - -263, -28, -214, 78, -263, 132, -106, -187 + -267, -267, -267, -267, -267, 188, -267, -267, -267, -267, + -77, -267, -267, -197, 56, -170, -267, -267, -192, -267, + -267, -266, -267, -267, -267, -267, -267, -267, -267, -267, + -267, 43, 34, -267, -267, -267, 11, -39, -23, -1, + -267, -267, -267, -52, 44, -267, 201, -267, -10, 82, + -267, -267, -19, -40, -267, -267, -73, -2, -267, -28, + -213, -54, -267, -25, -79, 26 }; /* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If positive, shift that token. If negative, reduce the rule which number is the opposite. If zero, do what YYDEFACT says. If YYTABLE_NINF, syntax error. */ -#define YYTABLE_NINF -95 +#define YYTABLE_NINF -102 static const yytype_int16 yytable[] = { - 36, 237, 215, 37, 71, 71, 118, 119, 200, 222, - 63, 124, 231, 10, 249, 1, 289, 1, 193, 1, - -94, 194, 124, 6, 240, 64, 300, 241, 109, 5, - 70, 102, 103, 282, 121, 122, 66, 229, 67, 47, - 67, 46, 108, 108, 124, 124, 47, 53, 221, 108, - 108, 9, 54, 66, 116, 120, -94, 283, 284, 130, - 125, -95, 93, 133, 261, 132, 201, 291, 141, 135, - 28, 125, 134, -94, 136, 137, 138, 139, -58, -94, - -84, 140, 50, 51, 52, 231, 157, 263, 56, 56, - 265, 56, 61, 125, 125, 231, 154, 125, 292, 293, - -58, 155, 56, -95, -95, 126, 75, 126, 255, 287, - -85, 76, 158, 290, 164, 197, 198, 202, 163, 309, - 162, 203, 312, 205, 166, 67, 75, 225, 226, 110, - 111, -95, 245, 248, 258, 252, 77, 78, 23, 259, - 311, 127, 272, 313, 294, 295, 302, 26, 82, 83, - 182, 298, 56, 56, 56, 56, 56, 56, 56, 56, - 56, 56, 56, 56, 72, 303, 204, 236, 82, 83, - 112, 113, 296, 70, 70, 212, 210, 70, 73, 70, - 56, 271, 70, 218, 156, 60, 224, 219, 100, 101, - 65, 304, 192, 0, 223, 210, 160, 161, 227, 228, - 0, 0, 0, 75, 0, 50, 244, 70, 76, 238, - 108, 55, 57, 239, 58, 63, 0, 0, 102, 103, - 0, 108, 70, 104, 0, 87, 0, 0, 264, 0, - 251, 0, 0, 77, 0, 254, 90, 91, 92, 256, - 257, 93, 270, 260, 0, 82, 83, 0, 88, 89, - 90, 91, 92, 0, 266, 93, 268, 108, 0, 0, - 276, 0, 278, 0, 0, 280, 281, 0, 286, 0, - 288, 0, 0, 220, 0, 142, 143, 144, 145, 146, - 147, 148, 149, 150, 151, 152, 153, 0, 0, 206, - 207, 0, 305, 208, 307, 211, 0, 308, 213, 310, - 0, 242, 0, 159, 0, 246, 247, 72, 72, 0, - 0, 72, 0, 72, 0, 75, 72, 0, 0, 0, - 76, 217, 0, 233, 0, 0, 56, 94, 95, 96, - 97, 98, 0, 0, 99, 56, 0, 267, 243, 0, - 0, 72, 0, 0, 275, 77, 78, 79, 279, 0, - 0, 0, 0, 0, 80, 0, 72, 82, 83, 0, - 0, 0, 0, 0, 250, -80, 8, 301, 9, 10, - 0, 0, 11, 12, 0, 67, 0, 0, 306, 0, - 0, 13, 14, 0, 0, 0, 0, 15, 16, 0, - 0, 0, 269, 0, 0, 0, 0, 0, 75, 0, - 277, 17, 18, 76, 0, 0, 0, 19, 20, 21, - 22, 1, 23, 0, 0, 0, 0, 0, 24, 25, - 0, 26, 0, 27, 0, 0, 28, 29, 77, 78, - 79, 30, -9, 0, -9, 0, 167, 80, 9, 10, - 82, 83, 11, 12, 0, 0, 0, 0, 0, 0, - 0, 0, 126, 168, 0, 169, 170, 0, 87, 171, - -63, -63, 172, 173, 174, 175, 176, 177, 178, 179, - 180, 0, 18, 181, 0, 0, 0, 19, 20, 21, - 22, -63, 23, 0, 0, 0, 0, 0, 24, 25, - 0, 26, 167, 27, 9, 10, 28, 29, 11, 12, - 0, 30, 66, -63, 67, 0, 0, 0, 0, 168, - 0, 169, 170, 0, 0, 171, -62, -62, 172, 173, - 174, 175, 176, 177, 178, 179, 180, 0, 18, 181, - 0, 0, 0, 19, 20, 21, 22, -62, 23, 0, - 0, 0, 0, 0, 24, 25, 0, 26, 167, 27, - 9, 10, 28, 29, 11, 12, 0, 30, 66, -62, - 67, 0, 0, 0, 0, 168, 0, 169, 170, 0, - 0, 171, 0, 0, 172, 173, 174, 175, 176, 177, - 178, 179, 180, 0, 18, 181, 0, 0, 0, 19, - 20, 21, 22, 0, 23, 0, 0, 75, 0, 0, - 24, 25, 76, 26, 0, 27, 0, 0, 28, 29, - 0, 0, 0, 30, 66, 182, 67, 62, 0, 9, - 10, 0, 0, 11, 12, 0, -93, 77, 78, 79, - 0, 0, 0, 0, 0, 0, 80, 0, 125, 82, - 83, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 126, 0, 18, 0, 0, 0, 0, 19, 20, - 21, 22, -93, 23, 0, 0, 0, 0, 0, 24, - 25, 0, 26, 0, 27, 0, 0, 28, 234, -93, - 0, 0, 30, 9, 10, -93, 0, 11, 12, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 168, 0, - 169, 170, 0, 0, 171, 0, 0, 172, 173, 174, - 175, 176, 177, 178, 179, 180, 0, 18, 181, 0, - 0, 75, 19, 20, 21, 22, 76, 23, 0, 0, - 0, 0, 0, 24, 25, 0, 26, 0, 27, 9, - 10, 28, 29, 11, 12, 0, 30, 66, 0, 67, - 0, 77, 78, 79, 0, 0, 0, 0, 0, 0, - 80, 0, 81, 82, 83, 62, 0, 9, 10, 0, - 0, 11, 12, 18, 0, 0, 0, 0, 19, 20, - 21, 22, 0, 23, 0, 0, 0, 0, 0, 24, - 25, 0, 26, 62, 27, 9, 10, 28, 29, 11, - 12, 18, 30, 0, 0, 67, 19, 20, 21, 22, - 0, 23, 0, 0, 0, 0, 0, 24, 25, 0, - 26, 0, 27, 0, 0, 28, 29, -93, 0, 18, - 30, 0, 0, 75, 19, 20, 21, 22, 76, 23, - 0, 0, 0, 0, 0, 24, 25, 0, 26, 165, - 27, 9, 10, 28, 29, 11, 12, 0, 30, 0, - 0, 0, 0, 77, 78, 79, 0, 0, 0, 0, - 0, 0, 80, 191, 0, 82, 83, 0, 9, 230, - 0, 0, 11, 12, 0, 18, 0, 0, 0, 0, - 19, 20, 21, 22, 0, 23, 170, 0, 0, 0, - 0, 24, 25, 0, 26, 0, 27, 177, 178, 28, - 29, 0, 18, 0, 30, 0, 75, 19, 20, 21, - 22, 76, 23, 0, 0, 0, 0, 0, 24, 25, - 0, 26, 0, 27, 9, 10, 28, 29, 11, 12, - 0, 30, 0, 0, 0, 0, 77, 78, 79, 0, - 0, 0, 170, 0, 0, 80, 0, 0, 82, 83, - 0, 9, 10, 177, 178, 11, 12, 0, 18, 86, - 0, 0, 0, 19, 20, 21, 22, 0, 23, 0, - 0, 0, 0, 0, 24, 25, 0, 26, 0, 27, - 0, 0, 28, 29, 0, 18, 0, 30, 0, 0, - 19, 20, 21, 22, 0, 23, 0, 0, 0, 0, - 0, 24, 25, 0, 26, 0, 27, 9, 10, 28, - 29, 11, 12, 0, 30, 0, 0, 0, 0, 0, + 34, 73, 73, 64, 74, 229, 114, 145, 130, 4, + 133, 50, 51, 52, 124, 125, 251, 67, 266, 57, + 57, 112, 57, 62, 5, 65, 136, 245, 78, 305, + 43, 137, 44, 57, 19, 19, 53, 178, 316, 298, + 105, 106, 111, 111, 33, 67, 54, 44, 243, 214, + 68, 130, 111, 111, 66, 166, 68, 69, 69, 126, + 77, 131, 299, 300, 207, 56, 58, 208, 59, 113, + 171, 172, 72, 254, 85, 86, 255, 167, 144, 90, + 146, 147, 148, 149, 307, 25, -11, 150, -65, 57, + 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, + 57, 281, 211, 245, 131, 283, 272, 165, 142, -11, + -65, 215, 245, 74, -102, 115, 116, 132, 235, 130, + 57, 122, 44, 303, 325, 4, 306, 328, -101, 173, + -91, 127, 128, 177, 96, 152, 153, 154, 155, 156, + 157, 158, 159, 160, 161, 162, 163, 19, 143, 50, + 5, 151, 164, 327, 132, 234, 329, 117, 118, 44, + -102, -102, 169, 74, 74, 174, 170, 74, -101, 74, + 168, 131, 131, 74, 93, 94, 95, 175, 231, 96, + 119, 72, 212, 256, -92, -101, 216, 263, 264, 250, + 217, -101, 224, 277, 179, 219, 69, 240, 74, 261, + 262, 265, 269, 289, 233, 308, 309, 276, 195, 314, + 318, 237, 224, 74, 279, 241, 242, 319, 75, 261, + 218, 267, 312, 285, 238, 268, 61, 111, 288, 226, + 292, 72, 72, 206, 320, 72, 236, 72, 232, 0, + 273, 72, 0, 0, 220, 221, 282, 65, 222, 20, + 225, 317, 0, 287, 227, 310, 311, 0, 23, 0, + 78, 294, 322, 0, 252, 79, 72, 0, 253, 78, + 0, 78, 0, 0, 79, 284, 79, 286, 57, 247, + 0, 72, 0, 0, 0, 0, 57, 0, 0, 0, + 271, 80, 81, 0, 257, 0, 0, 274, 275, 0, + 80, 278, 80, 81, 82, 0, 85, 86, 0, 0, + 0, 103, 104, 0, 83, 85, 86, 85, 86, 293, + 0, 295, 0, 296, 297, 0, 302, 0, 304, 0, + 2, 3, 90, 4, 5, 69, 0, 6, 7, 0, + 0, 0, 105, 106, 0, 0, 0, 8, 9, 321, + 107, 323, 0, 0, 324, 0, 326, 91, 92, 93, + 94, 95, 0, 0, 96, 10, 11, 12, 13, 0, + 0, 0, 0, 14, 15, 16, 17, 18, 0, 0, + 19, 20, 97, 98, 99, 100, 101, 21, 22, 102, + 23, 0, 24, 0, 0, 25, 26, 0, 27, 0, + 0, -14, 180, -14, 4, 5, 0, 0, 6, 7, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 181, 0, 182, 183, 184, -70, -70, 185, 186, 187, + 188, 189, 190, 191, 192, 193, 0, 0, 0, 13, + 194, 0, 0, 0, 14, 15, 16, 17, 0, 0, + 0, -70, 20, 0, 0, 0, 0, 0, 21, 22, + 0, 23, 0, 24, 0, 0, 25, 26, 0, 55, + 0, 0, 68, -70, 69, 180, 0, 4, 5, 0, + 0, 6, 7, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 181, 0, 182, 183, 184, -69, -69, + 185, 186, 187, 188, 189, 190, 191, 192, 193, 0, + 0, 0, 13, 194, 0, 0, 0, 14, 15, 16, + 17, 0, 0, 0, -69, 20, 0, 0, 0, 0, + 0, 21, 22, 0, 23, 0, 24, 0, 0, 25, + 26, 0, 55, 0, 0, 68, -69, 69, 180, 0, + 4, 5, 0, 0, 6, 7, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 181, 0, 182, 183, + 184, 0, 0, 185, 186, 187, 188, 189, 190, 191, + 192, 193, 0, 0, 0, 13, 194, 0, 0, 0, + 14, 15, 16, 17, 63, 0, 4, 5, 20, 0, + 6, 7, 0, -100, 21, 22, 0, 23, 0, 24, + 0, 0, 25, 26, 0, 55, 0, 0, 68, 195, + 69, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 13, 0, 0, 0, 0, 14, 15, 16, 17, + 0, 0, 0, -100, 20, 0, 0, 0, 0, 0, + 21, 22, 0, 23, 0, 24, 0, 0, 25, 248, + -100, 55, 0, 4, 5, 0, -100, 6, 7, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 181, + 0, 182, 183, 184, 0, 0, 185, 186, 187, 188, + 189, 190, 191, 192, 193, 0, 0, 0, 13, 194, + 0, 0, 0, 14, 15, 16, 17, 0, 4, 5, + 0, 20, 6, 7, 0, 0, 0, 21, 22, 0, + 23, 0, 24, 0, 0, 25, 26, 0, 55, 0, + 0, 68, 63, 69, 4, 5, 0, 0, 6, 7, + 0, 0, 0, 13, 0, 0, 0, 0, 14, 15, + 16, 17, 0, 0, 0, 0, 20, 0, 0, 0, + 0, 0, 21, 22, 0, 23, 0, 24, 0, 13, + 25, 26, 0, 55, 14, 15, 16, 17, 69, 0, + 0, 0, 20, 0, 0, 0, 0, 0, 21, 22, + 0, 23, 0, 24, 0, 0, 25, 26, -100, 55, + 63, 0, 4, 5, 0, 0, 6, 7, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 176, 0, 4, 5, + 0, 0, 6, 7, 0, 0, 0, 13, 0, 0, + 0, 0, 14, 15, 16, 17, 0, 0, 0, 0, + 20, 0, 0, 0, 0, 0, 21, 22, 0, 23, + 0, 24, 0, 13, 25, 26, 0, 55, 14, 15, + 16, 17, 0, 4, 244, 0, 20, 6, 7, 0, + 0, 0, 21, 22, 0, 23, 0, 24, 0, 0, + 25, 26, 183, 55, 0, 0, 0, 0, 0, 0, + 0, 190, 191, 0, 0, 4, 5, 0, 13, 6, + 7, 0, 0, 14, 15, 16, 17, 0, 0, 0, + 0, 20, 0, 0, 183, 0, 0, 21, 22, 0, + 23, 0, 24, 190, 191, 25, 26, 0, 55, 0, + 13, 0, 0, 0, 0, 14, 15, 16, 17, 0, + 4, 5, 0, 20, 6, 7, 0, 0, 89, 21, + 22, 0, 23, 0, 24, 0, 0, 25, 26, 0, + 55, 0, 0, 0, 0, 0, 4, 5, 0, 0, + 6, 7, 0, 0, 0, 13, 0, 0, 0, 0, + 14, 15, 16, 17, 0, 0, 0, 0, 20, 0, + 0, 0, 0, 0, 21, 22, 0, 23, 0, 24, + 0, 13, 25, 26, 0, 55, 14, 15, 16, 17, + 0, 4, 5, 0, 20, 6, 7, 0, 0, 0, + 21, 22, 0, 23, 0, 24, 0, 0, 25, 26, + 0, 55, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 9, 10, 0, 0, 11, 12, 0, 0, - 0, 18, 0, 0, 0, 0, 19, 20, 21, 22, - 0, 23, 0, 0, 0, 0, 0, 24, 25, 0, - 26, 0, 27, 0, 0, 28, 29, 0, 0, 0, - 30, 19, 20, 21, 22, 0, 23, 0, 0, 0, - 0, 0, 24, 25, 0, 26, 0, 27, 0, 0, - 28, 59, 0, 0, 0, 30 + 78, 14, 15, 16, 17, 79, 78, 0, 0, 20, + 0, 79, 0, 0, 0, 21, 22, 0, 23, 0, + 24, 0, 0, 25, 60, 0, 55, 0, 0, 78, + 0, 80, 81, 82, 79, 78, 0, 80, 81, 82, + 79, 0, 0, 83, 0, 0, 85, 86, 0, 83, + 0, 84, 85, 86, 0, 0, 0, 0, 132, 0, + 80, 81, 82, 0, 0, 0, 80, 81, 82, 0, + 0, 0, 83, 205, 0, 85, 86, 0, 83, 0, + 0, 85, 86 }; static const yytype_int16 yycheck[] = { - 7, 215, 188, 7, 32, 33, 53, 54, 4, 196, - 29, 1, 205, 4, 39, 46, 278, 46, 1, 46, - 10, 4, 1, 46, 1, 29, 288, 4, 47, 0, - 32, 42, 43, 1, 42, 43, 67, 204, 69, 64, - 69, 62, 46, 47, 1, 1, 64, 62, 1, 53, - 54, 3, 62, 67, 51, 59, 46, 25, 26, 66, - 50, 9, 60, 5, 251, 72, 62, 281, 37, 4, - 61, 50, 76, 63, 78, 79, 80, 81, 46, 69, - 63, 85, 18, 19, 20, 278, 65, 254, 24, 25, - 257, 27, 28, 50, 50, 288, 13, 50, 7, 8, - 68, 105, 38, 51, 52, 63, 9, 63, 65, 276, - 63, 14, 62, 280, 39, 4, 62, 62, 125, 305, - 124, 62, 308, 62, 128, 69, 9, 64, 4, 3, - 4, 14, 63, 27, 62, 10, 39, 40, 47, 4, - 307, 63, 19, 310, 53, 54, 7, 56, 51, 52, - 68, 49, 88, 89, 90, 91, 92, 93, 94, 95, - 96, 97, 98, 99, 32, 7, 173, 214, 51, 52, - 44, 45, 283, 175, 176, 182, 180, 179, 33, 181, - 116, 262, 184, 190, 106, 28, 199, 191, 12, 13, - 30, 297, 141, -1, 198, 199, 118, 119, 202, 203, - -1, -1, -1, 9, -1, 141, 225, 209, 14, 216, - 214, 24, 25, 220, 27, 234, -1, -1, 42, 43, - -1, 225, 224, 47, -1, 38, -1, -1, 256, -1, - 234, -1, -1, 39, -1, 242, 55, 56, 57, 246, - 247, 60, 261, 250, -1, 51, 52, -1, 53, 54, - 55, 56, 57, -1, 258, 60, 260, 261, -1, -1, - 267, -1, 269, -1, -1, 272, 273, -1, 275, -1, - 277, -1, -1, 195, -1, 88, 89, 90, 91, 92, - 93, 94, 95, 96, 97, 98, 99, -1, -1, 175, - 176, -1, 299, 179, 301, 181, -1, 304, 184, 306, - -1, 223, -1, 116, -1, 227, 228, 175, 176, -1, - -1, 179, -1, 181, -1, 9, 184, -1, -1, -1, - 14, 189, -1, 209, -1, -1, 262, 53, 54, 55, - 56, 57, -1, -1, 60, 271, -1, 259, 224, -1, - -1, 209, -1, -1, 266, 39, 40, 41, 270, -1, - -1, -1, -1, -1, 48, -1, 224, 51, 52, -1, - -1, -1, -1, -1, 232, 0, 1, 289, 3, 4, - -1, -1, 7, 8, -1, 69, -1, -1, 300, -1, - -1, 16, 17, -1, -1, -1, -1, 22, 23, -1, - -1, -1, 260, -1, -1, -1, -1, -1, 9, -1, - 268, 36, 37, 14, -1, -1, -1, 42, 43, 44, - 45, 46, 47, -1, -1, -1, -1, -1, 53, 54, - -1, 56, -1, 58, -1, -1, 61, 62, 39, 40, - 41, 66, 67, -1, 69, -1, 1, 48, 3, 4, - 51, 52, 7, 8, -1, -1, -1, -1, -1, -1, - -1, -1, 63, 18, -1, 20, 21, -1, 271, 24, - 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, - 35, -1, 37, 38, -1, -1, -1, 42, 43, 44, - 45, 46, 47, -1, -1, -1, -1, -1, 53, 54, - -1, 56, 1, 58, 3, 4, 61, 62, 7, 8, - -1, 66, 67, 68, 69, -1, -1, -1, -1, 18, - -1, 20, 21, -1, -1, 24, 25, 26, 27, 28, - 29, 30, 31, 32, 33, 34, 35, -1, 37, 38, - -1, -1, -1, 42, 43, 44, 45, 46, 47, -1, - -1, -1, -1, -1, 53, 54, -1, 56, 1, 58, - 3, 4, 61, 62, 7, 8, -1, 66, 67, 68, - 69, -1, -1, -1, -1, 18, -1, 20, 21, -1, - -1, 24, -1, -1, 27, 28, 29, 30, 31, 32, - 33, 34, 35, -1, 37, 38, -1, -1, -1, 42, - 43, 44, 45, -1, 47, -1, -1, 9, -1, -1, - 53, 54, 14, 56, -1, 58, -1, -1, 61, 62, - -1, -1, -1, 66, 67, 68, 69, 1, -1, 3, - 4, -1, -1, 7, 8, -1, 10, 39, 40, 41, - -1, -1, -1, -1, -1, -1, 48, -1, 50, 51, - 52, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 63, -1, 37, -1, -1, -1, -1, 42, 43, - 44, 45, 46, 47, -1, -1, -1, -1, -1, 53, - 54, -1, 56, -1, 58, -1, -1, 61, 62, 63, - -1, -1, 66, 3, 4, 69, -1, 7, 8, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 18, -1, - 20, 21, -1, -1, 24, -1, -1, 27, 28, 29, - 30, 31, 32, 33, 34, 35, -1, 37, 38, -1, - -1, 9, 42, 43, 44, 45, 14, 47, -1, -1, - -1, -1, -1, 53, 54, -1, 56, -1, 58, 3, - 4, 61, 62, 7, 8, -1, 66, 67, -1, 69, - -1, 39, 40, 41, -1, -1, -1, -1, -1, -1, - 48, -1, 50, 51, 52, 1, -1, 3, 4, -1, - -1, 7, 8, 37, -1, -1, -1, -1, 42, 43, - 44, 45, -1, 47, -1, -1, -1, -1, -1, 53, - 54, -1, 56, 1, 58, 3, 4, 61, 62, 7, - 8, 37, 66, -1, -1, 69, 42, 43, 44, 45, - -1, 47, -1, -1, -1, -1, -1, 53, 54, -1, - 56, -1, 58, -1, -1, 61, 62, 63, -1, 37, - 66, -1, -1, 9, 42, 43, 44, 45, 14, 47, - -1, -1, -1, -1, -1, 53, 54, -1, 56, 1, - 58, 3, 4, 61, 62, 7, 8, -1, 66, -1, - -1, -1, -1, 39, 40, 41, -1, -1, -1, -1, - -1, -1, 48, 49, -1, 51, 52, -1, 3, 4, - -1, -1, 7, 8, -1, 37, -1, -1, -1, -1, - 42, 43, 44, 45, -1, 47, 21, -1, -1, -1, - -1, 53, 54, -1, 56, -1, 58, 32, 33, 61, - 62, -1, 37, -1, 66, -1, 9, 42, 43, 44, - 45, 14, 47, -1, -1, -1, -1, -1, 53, 54, - -1, 56, -1, 58, 3, 4, 61, 62, 7, 8, - -1, 66, -1, -1, -1, -1, 39, 40, 41, -1, - -1, -1, 21, -1, -1, 48, -1, -1, 51, 52, - -1, 3, 4, 32, 33, 7, 8, -1, 37, 11, - -1, -1, -1, 42, 43, 44, 45, -1, 47, -1, - -1, -1, -1, -1, 53, 54, -1, 56, -1, 58, - -1, -1, 61, 62, -1, 37, -1, 66, -1, -1, - 42, 43, 44, 45, -1, 47, -1, -1, -1, -1, - -1, 53, 54, -1, 56, -1, 58, 3, 4, 61, - 62, 7, 8, -1, 66, -1, -1, -1, -1, -1, + 1, 29, 30, 26, 29, 202, 46, 80, 1, 3, + 64, 13, 14, 15, 53, 54, 229, 27, 40, 21, + 22, 44, 24, 25, 4, 26, 1, 219, 9, 295, + 66, 6, 69, 35, 50, 50, 66, 1, 304, 1, + 43, 44, 43, 44, 1, 55, 66, 69, 218, 4, + 71, 1, 53, 54, 48, 109, 71, 73, 73, 60, + 50, 54, 24, 25, 1, 21, 22, 4, 24, 16, + 124, 125, 29, 1, 55, 56, 4, 70, 79, 35, + 81, 82, 83, 84, 297, 65, 50, 88, 50, 91, + 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, + 102, 271, 175, 295, 54, 275, 16, 108, 74, 73, + 72, 66, 304, 138, 9, 3, 4, 67, 1, 1, + 122, 55, 69, 293, 321, 3, 296, 324, 10, 130, + 67, 43, 44, 134, 64, 91, 92, 93, 94, 95, + 96, 97, 98, 99, 100, 101, 102, 50, 5, 151, + 4, 38, 13, 323, 67, 209, 326, 45, 46, 69, + 55, 56, 66, 188, 189, 131, 122, 192, 50, 194, + 49, 54, 54, 198, 59, 60, 61, 40, 203, 64, + 68, 138, 66, 237, 67, 67, 66, 241, 242, 228, + 66, 73, 193, 266, 138, 66, 73, 4, 223, 239, + 67, 26, 10, 20, 205, 7, 8, 66, 72, 53, + 7, 212, 213, 238, 268, 216, 217, 7, 30, 259, + 186, 246, 299, 277, 213, 248, 25, 228, 280, 195, + 284, 188, 189, 151, 313, 192, 210, 194, 204, -1, + 259, 198, -1, -1, 188, 189, 274, 248, 192, 51, + 194, 305, -1, 278, 198, 57, 58, -1, 60, -1, + 9, 286, 316, -1, 230, 14, 223, -1, 234, 9, + -1, 9, -1, -1, 14, 276, 14, 278, 280, 223, + -1, 238, -1, -1, -1, -1, 288, -1, -1, -1, + 256, 40, 41, -1, 238, -1, -1, 263, 264, -1, + 40, 267, 40, 41, 42, -1, 55, 56, -1, -1, + -1, 12, 13, -1, 52, 55, 56, 55, 56, 285, + -1, 287, -1, 289, 290, -1, 292, -1, 294, -1, + 0, 1, 288, 3, 4, 73, -1, 7, 8, -1, + -1, -1, 43, 44, -1, -1, -1, 17, 18, 315, + 51, 317, -1, -1, 320, -1, 322, 57, 58, 59, + 60, 61, -1, -1, 64, 35, 36, 37, 38, -1, + -1, -1, -1, 43, 44, 45, 46, 47, -1, -1, + 50, 51, 57, 58, 59, 60, 61, 57, 58, 64, + 60, -1, 62, -1, -1, 65, 66, -1, 68, -1, + -1, 71, 1, 73, 3, 4, -1, -1, 7, 8, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 19, -1, 21, 22, 23, 24, 25, 26, 27, 28, + 29, 30, 31, 32, 33, 34, -1, -1, -1, 38, + 39, -1, -1, -1, 43, 44, 45, 46, -1, -1, + -1, 50, 51, -1, -1, -1, -1, -1, 57, 58, + -1, 60, -1, 62, -1, -1, 65, 66, -1, 68, + -1, -1, 71, 72, 73, 1, -1, 3, 4, -1, + -1, 7, 8, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 19, -1, 21, 22, 23, 24, 25, + 26, 27, 28, 29, 30, 31, 32, 33, 34, -1, + -1, -1, 38, 39, -1, -1, -1, 43, 44, 45, + 46, -1, -1, -1, 50, 51, -1, -1, -1, -1, + -1, 57, 58, -1, 60, -1, 62, -1, -1, 65, + 66, -1, 68, -1, -1, 71, 72, 73, 1, -1, + 3, 4, -1, -1, 7, 8, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 19, -1, 21, 22, + 23, -1, -1, 26, 27, 28, 29, 30, 31, 32, + 33, 34, -1, -1, -1, 38, 39, -1, -1, -1, + 43, 44, 45, 46, 1, -1, 3, 4, 51, -1, + 7, 8, -1, 10, 57, 58, -1, 60, -1, 62, + -1, -1, 65, 66, -1, 68, -1, -1, 71, 72, + 73, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 38, -1, -1, -1, -1, 43, 44, 45, 46, + -1, -1, -1, 50, 51, -1, -1, -1, -1, -1, + 57, 58, -1, 60, -1, 62, -1, -1, 65, 66, + 67, 68, -1, 3, 4, -1, 73, 7, 8, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 19, + -1, 21, 22, 23, -1, -1, 26, 27, 28, 29, + 30, 31, 32, 33, 34, -1, -1, -1, 38, 39, + -1, -1, -1, 43, 44, 45, 46, -1, 3, 4, + -1, 51, 7, 8, -1, -1, -1, 57, 58, -1, + 60, -1, 62, -1, -1, 65, 66, -1, 68, -1, + -1, 71, 1, 73, 3, 4, -1, -1, 7, 8, + -1, -1, -1, 38, -1, -1, -1, -1, 43, 44, + 45, 46, -1, -1, -1, -1, 51, -1, -1, -1, + -1, -1, 57, 58, -1, 60, -1, 62, -1, 38, + 65, 66, -1, 68, 43, 44, 45, 46, 73, -1, + -1, -1, 51, -1, -1, -1, -1, -1, 57, 58, + -1, 60, -1, 62, -1, -1, 65, 66, 67, 68, + 1, -1, 3, 4, -1, -1, 7, 8, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 1, -1, 3, 4, + -1, -1, 7, 8, -1, -1, -1, 38, -1, -1, + -1, -1, 43, 44, 45, 46, -1, -1, -1, -1, + 51, -1, -1, -1, -1, -1, 57, 58, -1, 60, + -1, 62, -1, 38, 65, 66, -1, 68, 43, 44, + 45, 46, -1, 3, 4, -1, 51, 7, 8, -1, + -1, -1, 57, 58, -1, 60, -1, 62, -1, -1, + 65, 66, 22, 68, -1, -1, -1, -1, -1, -1, + -1, 31, 32, -1, -1, 3, 4, -1, 38, 7, + 8, -1, -1, 43, 44, 45, 46, -1, -1, -1, + -1, 51, -1, -1, 22, -1, -1, 57, 58, -1, + 60, -1, 62, 31, 32, 65, 66, -1, 68, -1, + 38, -1, -1, -1, -1, 43, 44, 45, 46, -1, + 3, 4, -1, 51, 7, 8, -1, -1, 11, 57, + 58, -1, 60, -1, 62, -1, -1, 65, 66, -1, + 68, -1, -1, -1, -1, -1, 3, 4, -1, -1, + 7, 8, -1, -1, -1, 38, -1, -1, -1, -1, + 43, 44, 45, 46, -1, -1, -1, -1, 51, -1, + -1, -1, -1, -1, 57, 58, -1, 60, -1, 62, + -1, 38, 65, 66, -1, 68, 43, 44, 45, 46, + -1, 3, 4, -1, 51, 7, 8, -1, -1, -1, + 57, 58, -1, 60, -1, 62, -1, -1, 65, 66, + -1, 68, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 3, 4, -1, -1, 7, 8, -1, -1, - -1, 37, -1, -1, -1, -1, 42, 43, 44, 45, - -1, 47, -1, -1, -1, -1, -1, 53, 54, -1, - 56, -1, 58, -1, -1, 61, 62, -1, -1, -1, - 66, 42, 43, 44, 45, -1, 47, -1, -1, -1, - -1, -1, 53, 54, -1, 56, -1, 58, -1, -1, - 61, 62, -1, -1, -1, 66 + 9, 43, 44, 45, 46, 14, 9, -1, -1, 51, + -1, 14, -1, -1, -1, 57, 58, -1, 60, -1, + 62, -1, -1, 65, 66, -1, 68, -1, -1, 9, + -1, 40, 41, 42, 14, 9, -1, 40, 41, 42, + 14, -1, -1, 52, -1, -1, 55, 56, -1, 52, + -1, 54, 55, 56, -1, -1, -1, -1, 67, -1, + 40, 41, 42, -1, -1, -1, 40, 41, 42, -1, + -1, -1, 52, 53, -1, 55, 56, -1, 52, -1, + -1, 55, 56 }; /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing symbol of state STATE-NUM. */ static const yytype_uint8 yystos[] = { - 0, 46, 71, 99, 100, 0, 46, 72, 1, 3, - 4, 7, 8, 16, 17, 22, 23, 36, 37, 42, - 43, 44, 45, 47, 53, 54, 56, 58, 61, 62, - 66, 73, 74, 78, 80, 82, 100, 107, 111, 112, - 113, 114, 115, 116, 118, 119, 62, 64, 79, 117, - 118, 118, 118, 62, 62, 112, 118, 112, 112, 62, - 114, 118, 1, 106, 107, 116, 67, 69, 75, 84, - 99, 121, 125, 75, 81, 9, 14, 39, 40, 41, - 48, 50, 51, 52, 109, 110, 11, 112, 53, 54, - 55, 56, 57, 60, 53, 54, 55, 56, 57, 60, - 12, 13, 42, 43, 47, 108, 105, 106, 107, 106, - 3, 4, 44, 45, 76, 77, 51, 101, 105, 105, - 107, 42, 43, 120, 1, 50, 63, 123, 127, 123, - 100, 83, 100, 5, 107, 4, 107, 107, 107, 107, - 107, 37, 112, 112, 112, 112, 112, 112, 112, 112, - 112, 112, 112, 112, 13, 107, 123, 65, 62, 112, - 123, 123, 107, 100, 39, 1, 107, 1, 18, 20, - 21, 24, 27, 28, 29, 30, 31, 32, 33, 34, - 35, 38, 68, 85, 87, 94, 98, 107, 121, 122, - 125, 49, 117, 1, 4, 102, 103, 4, 62, 86, - 4, 62, 62, 62, 100, 62, 84, 84, 84, 104, - 107, 84, 100, 84, 88, 83, 124, 125, 100, 107, - 123, 1, 127, 107, 104, 64, 4, 107, 107, 85, - 4, 87, 89, 84, 62, 95, 105, 122, 100, 100, - 1, 4, 123, 84, 106, 63, 123, 123, 27, 39, - 125, 107, 10, 96, 100, 65, 100, 100, 62, 4, - 100, 127, 97, 85, 121, 85, 107, 123, 107, 125, - 106, 111, 19, 90, 91, 123, 100, 125, 100, 123, - 100, 100, 1, 25, 26, 92, 100, 85, 100, 89, - 85, 122, 7, 8, 53, 54, 80, 93, 49, 126, - 89, 123, 7, 7, 126, 100, 123, 100, 100, 83, - 100, 85, 83, 85 + 0, 75, 0, 1, 3, 4, 7, 8, 17, 18, + 35, 36, 37, 38, 43, 44, 45, 46, 47, 50, + 51, 57, 58, 60, 62, 65, 66, 68, 76, 78, + 82, 84, 86, 105, 113, 117, 118, 119, 120, 121, + 122, 130, 131, 66, 69, 127, 128, 129, 83, 123, + 131, 131, 131, 66, 66, 68, 118, 131, 118, 118, + 66, 120, 131, 1, 112, 113, 48, 122, 71, 73, + 79, 88, 105, 133, 137, 79, 85, 50, 9, 14, + 40, 41, 42, 52, 54, 55, 56, 115, 116, 11, + 118, 57, 58, 59, 60, 61, 64, 57, 58, 59, + 60, 61, 64, 12, 13, 43, 44, 51, 114, 111, + 112, 113, 112, 16, 127, 3, 4, 45, 46, 68, + 80, 81, 55, 107, 111, 111, 113, 43, 44, 132, + 1, 54, 67, 135, 139, 135, 1, 6, 77, 105, + 106, 87, 106, 5, 113, 130, 113, 113, 113, 113, + 113, 38, 118, 118, 118, 118, 118, 118, 118, 118, + 118, 118, 118, 118, 13, 113, 135, 70, 49, 66, + 118, 135, 135, 113, 106, 40, 1, 113, 1, 88, + 1, 19, 21, 22, 23, 26, 27, 28, 29, 30, + 31, 32, 33, 34, 39, 72, 89, 90, 92, 100, + 104, 113, 133, 134, 137, 53, 123, 1, 4, 108, + 109, 130, 66, 91, 4, 66, 66, 66, 106, 66, + 88, 88, 88, 110, 113, 88, 106, 88, 93, 87, + 136, 137, 106, 113, 135, 1, 139, 113, 110, 94, + 4, 113, 113, 89, 4, 92, 95, 88, 66, 101, + 111, 134, 106, 106, 1, 4, 135, 88, 124, 125, + 126, 127, 67, 135, 135, 26, 40, 137, 112, 10, + 102, 106, 16, 126, 106, 106, 66, 130, 106, 135, + 103, 89, 133, 89, 113, 135, 113, 137, 117, 20, + 96, 97, 135, 106, 137, 106, 106, 106, 1, 24, + 25, 98, 106, 89, 106, 95, 89, 134, 7, 8, + 57, 58, 84, 99, 53, 138, 95, 135, 7, 7, + 138, 106, 135, 106, 106, 87, 106, 89, 87, 89 }; #define yyerrok (yyerrstatus = 0) @@ -1286,8 +1350,7 @@ do { \ `--------------------------------*/ /*ARGSUSED*/ -#if (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) +#if (defined __STDC__ || defined __C99__FUNC__ || defined __cplusplus || defined _MSC_VER) static void yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep) #else @@ -1318,8 +1381,7 @@ yy_symbol_value_print (yyoutput, yytype, yyvaluep) | Print this symbol on YYOUTPUT. | `--------------------------------*/ -#if (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) +#if (defined __STDC__ || defined __C99__FUNC__ || defined __cplusplus || defined _MSC_VER) static void yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep) #else @@ -1344,8 +1406,7 @@ yy_symbol_print (yyoutput, yytype, yyvaluep) | TOP (included). | `------------------------------------------------------------------*/ -#if (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) +#if (defined __STDC__ || defined __C99__FUNC__ || defined __cplusplus || defined _MSC_VER) static void yy_stack_print (yytype_int16 *yybottom, yytype_int16 *yytop) #else @@ -1375,8 +1436,7 @@ do { \ | Report that the YYRULE is going to be reduced. | `------------------------------------------------*/ -#if (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) +#if (defined __STDC__ || defined __C99__FUNC__ || defined __cplusplus || defined _MSC_VER) static void yy_reduce_print (YYSTYPE *yyvsp, int yyrule) #else @@ -1444,8 +1504,7 @@ int yydebug; # define yystrlen strlen # else /* Return the length of YYSTR. */ -#if (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) +#if (defined __STDC__ || defined __C99__FUNC__ || defined __cplusplus || defined _MSC_VER) static YYSIZE_T yystrlen (const char *yystr) #else @@ -1468,8 +1527,7 @@ yystrlen (yystr) # else /* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in YYDEST. */ -#if (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) +#if (defined __STDC__ || defined __C99__FUNC__ || defined __cplusplus || defined _MSC_VER) static char * yystpcpy (char *yydest, const char *yysrc) #else @@ -1653,8 +1711,7 @@ yysyntax_error (char *yyresult, int yystate, int yychar) `-----------------------------------------------*/ /*ARGSUSED*/ -#if (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) +#if (defined __STDC__ || defined __C99__FUNC__ || defined __cplusplus || defined _MSC_VER) static void yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep) #else @@ -1711,8 +1768,7 @@ int yynerrs; `-------------------------*/ #ifdef YYPARSE_PARAM -#if (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) +#if (defined __STDC__ || defined __C99__FUNC__ || defined __cplusplus || defined _MSC_VER) int yyparse (void *YYPARSE_PARAM) #else @@ -1721,8 +1777,7 @@ yyparse (YYPARSE_PARAM) void *YYPARSE_PARAM; #endif #else /* ! YYPARSE_PARAM */ -#if (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) +#if (defined __STDC__ || defined __C99__FUNC__ || defined __cplusplus || defined _MSC_VER) int yyparse (void) #else @@ -1973,343 +2028,538 @@ yyreduce: YY_REDUCE_PRINT (yyn); switch (yyn) { - case 2: + case 3: /* Line 1455 of yacc.c */ -#line 188 "awkgram.y" +#line 218 "awkgram.y" { - check_funcs(); - } + rule = 0; + yyerrok; + } break; - case 4: + case 5: /* Line 1455 of yacc.c */ -#line 196 "awkgram.y" +#line 224 "awkgram.y" { - beginfile_or_endfile_rule = begin_or_end_rule = parsing_end_rule = FALSE; - yyerrok; + next_sourcefile(); } break; - case 5: + case 6: /* Line 1455 of yacc.c */ -#line 201 "awkgram.y" +#line 228 "awkgram.y" { - beginfile_or_endfile_rule = begin_or_end_rule = parsing_end_rule = FALSE; + rule = 0; /* * If errors, give up, don't produce an infinite * stream of syntax error messages. */ /* yyerrok; */ - } + } break; - case 6: + case 7: /* Line 1455 of yacc.c */ -#line 213 "awkgram.y" +#line 240 "awkgram.y" { - (yyvsp[(1) - (2)].nodeval)->rnode = (yyvsp[(2) - (2)].nodeval); + (void) append_rule((yyvsp[(1) - (2)]), (yyvsp[(2) - (2)])); } break; - case 7: + case 8: /* Line 1455 of yacc.c */ -#line 217 "awkgram.y" +#line 244 "awkgram.y" { - if ((yyvsp[(1) - (2)].nodeval)->lnode != NULL) { - /* pattern rule with non-empty pattern */ - (yyvsp[(1) - (2)].nodeval)->rnode = node(NULL, Node_K_print_rec, NULL); - } else { - /* an error */ - if (begin_or_end_rule) - msg(_("%s blocks must have an action part"), - (parsing_end_rule ? "END" : "BEGIN")); - else if (beginfile_or_endfile_rule) - msg(_("%s blocks must have an action part"), - (parsing_endfile_rule ? "ENDFILE" : "BEGINFILE")); - else - msg(_("each rule must have a pattern or an action part")); + if (rule != Rule) { + msg(_("%s blocks must have an action part"), ruletab[rule]); errcount++; - } + } else if ((yyvsp[(1) - (2)]) == NULL) { + msg(_("each rule must have a pattern or an action part")); + errcount++; + } else /* pattern rule with non-empty pattern */ + (void) append_rule((yyvsp[(1) - (2)]), NULL); } break; - case 8: + case 9: /* Line 1455 of yacc.c */ -#line 235 "awkgram.y" +#line 255 "awkgram.y" { can_return = FALSE; - if ((yyvsp[(1) - (2)].nodeval)) - func_install((yyvsp[(1) - (2)].nodeval), (yyvsp[(2) - (2)].nodeval)); + if ((yyvsp[(1) - (2)]) && func_install((yyvsp[(1) - (2)]), (yyvsp[(2) - (2)])) < 0) + YYABORT; + func_params = NULL; yyerrok; } break; - case 9: + case 10: /* Line 1455 of yacc.c */ -#line 245 "awkgram.y" +#line 263 "awkgram.y" { - (yyval.nodeval) = append_pattern(&expression_value, (NODE *) NULL); + want_source = FALSE; + yyerrok; } break; - case 10: + case 11: /* Line 1455 of yacc.c */ -#line 249 "awkgram.y" +#line 271 "awkgram.y" { - (yyval.nodeval) = append_pattern(&expression_value, (yyvsp[(1) - (1)].nodeval)); + char *src = (yyvsp[(1) - (1)])->lextok; + if (include_source(src) < 0) + YYABORT; + efree(src); + bcfree((yyvsp[(1) - (1)])); + (yyval) = NULL; } break; - case 11: + case 12: /* Line 1455 of yacc.c */ -#line 253 "awkgram.y" - { - NODE *r; +#line 280 "awkgram.y" + { (yyval) = NULL; } + break; + + case 13: + +/* Line 1455 of yacc.c */ +#line 282 "awkgram.y" + { (yyval) = NULL; } + break; + + case 14: + +/* Line 1455 of yacc.c */ +#line 287 "awkgram.y" + { (yyval) = NULL; rule = Rule; } + break; + + case 15: + +/* Line 1455 of yacc.c */ +#line 289 "awkgram.y" + { (yyval) = (yyvsp[(1) - (1)]); rule = Rule; } + break; - getnode(r); - r->type = Node_line_range; - r->condpair = node((yyvsp[(1) - (3)].nodeval), Node_cond_pair, (yyvsp[(3) - (3)].nodeval)); - r->triggered = FALSE; - (yyval.nodeval) = append_pattern(&expression_value, r); + case 16: + +/* Line 1455 of yacc.c */ +#line 291 "awkgram.y" + { + INSTRUCTION *tp; + + add_lint((yyvsp[(1) - (3)]), LINT_assign_in_cond); + add_lint((yyvsp[(3) - (3)]), LINT_assign_in_cond); + + tp = instruction(Op_no_op); + list_prepend((yyvsp[(1) - (3)]), bcalloc(Op_line_range, !!do_profiling + 1, 0)); + (yyvsp[(1) - (3)])->nexti->triggered = FALSE; + (yyvsp[(1) - (3)])->nexti->target_jmp = (yyvsp[(3) - (3)])->nexti; + + list_append((yyvsp[(1) - (3)]), instruction(Op_cond_pair)); + (yyvsp[(1) - (3)])->lasti->line_range = (yyvsp[(1) - (3)])->nexti; + (yyvsp[(1) - (3)])->lasti->target_jmp = tp; + + list_append((yyvsp[(3) - (3)]), instruction(Op_cond_pair)); + (yyvsp[(3) - (3)])->lasti->line_range = (yyvsp[(1) - (3)])->nexti; + (yyvsp[(3) - (3)])->lasti->target_jmp = tp; + if (do_profiling) { + ((yyvsp[(1) - (3)])->nexti + 1)->condpair_left = (yyvsp[(1) - (3)])->lasti; + ((yyvsp[(1) - (3)])->nexti + 1)->condpair_right = (yyvsp[(3) - (3)])->lasti; + } + (yyval) = list_append(list_merge((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)])), tp); + rule = Rule; } break; - case 12: + case 17: /* Line 1455 of yacc.c */ -#line 263 "awkgram.y" +#line 317 "awkgram.y" { static int begin_seen = 0; if (do_lint_old && ++begin_seen == 2) warning(_("old awk does not support multiple `BEGIN' or `END' rules")); - begin_or_end_rule = TRUE; - (yyval.nodeval) = append_pattern(&begin_block, (NODE *) NULL); + (yyvsp[(1) - (1)])->in_rule = rule = BEGIN; + (yyvsp[(1) - (1)])->source_file = source; + (yyval) = (yyvsp[(1) - (1)]); } break; - case 13: + case 18: /* Line 1455 of yacc.c */ -#line 272 "awkgram.y" +#line 327 "awkgram.y" { static int end_seen = 0; if (do_lint_old && ++end_seen == 2) warning(_("old awk does not support multiple `BEGIN' or `END' rules")); - begin_or_end_rule = parsing_end_rule = TRUE; - (yyval.nodeval) = append_pattern(&end_block, (NODE *) NULL); + (yyvsp[(1) - (1)])->in_rule = rule = END; + (yyvsp[(1) - (1)])->source_file = source; + (yyval) = (yyvsp[(1) - (1)]); } break; - case 14: + case 19: /* Line 1455 of yacc.c */ -#line 281 "awkgram.y" +#line 337 "awkgram.y" { - beginfile_or_endfile_rule = TRUE; - (yyval.nodeval) = append_pattern(&beginfile_block, (NODE *) NULL); + (yyvsp[(1) - (1)])->in_rule = rule = BEGINFILE; + (yyvsp[(1) - (1)])->source_file = source; + (yyval) = (yyvsp[(1) - (1)]); } break; - case 15: + case 20: /* Line 1455 of yacc.c */ -#line 286 "awkgram.y" +#line 343 "awkgram.y" { - beginfile_or_endfile_rule = parsing_endfile_rule = TRUE; - (yyval.nodeval) = append_pattern(&endfile_block, (NODE *) NULL); + (yyvsp[(1) - (1)])->in_rule = rule = ENDFILE; + (yyvsp[(1) - (1)])->source_file = source; + (yyval) = (yyvsp[(1) - (1)]); } break; - case 16: + case 21: /* Line 1455 of yacc.c */ -#line 294 "awkgram.y" - { (yyval.nodeval) = (yyvsp[(2) - (5)].nodeval); } +#line 352 "awkgram.y" + { + if ((yyvsp[(2) - (5)]) == NULL) + (yyval) = list_create(instruction(Op_no_op)); + else + (yyval) = (yyvsp[(2) - (5)]); + } break; - case 17: + case 22: /* Line 1455 of yacc.c */ -#line 299 "awkgram.y" - { (yyval.sval) = (yyvsp[(1) - (1)].sval); } +#line 362 "awkgram.y" + { (yyval) = (yyvsp[(1) - (1)]); } break; - case 18: + case 23: /* Line 1455 of yacc.c */ -#line 301 "awkgram.y" - { (yyval.sval) = (yyvsp[(1) - (1)].sval); } +#line 364 "awkgram.y" + { (yyval) = (yyvsp[(1) - (1)]); } break; - case 19: + case 24: /* Line 1455 of yacc.c */ -#line 303 "awkgram.y" +#line 366 "awkgram.y" { yyerror(_("`%s' is a built-in function, it cannot be redefined"), tokstart); - errcount++; - (yyval.sval) = builtin_func; + (yyvsp[(1) - (1)])->opcode = Op_symbol; /* Op_symbol instead of Op_token so that + * free_bc_internal does not try to free it + */ + (yyvsp[(1) - (1)])->lextok = builtin_func; + (yyval) = (yyvsp[(1) - (1)]); /* yyerrok; */ } break; - case 22: + case 25: /* Line 1455 of yacc.c */ -#line 319 "awkgram.y" +#line 377 "awkgram.y" + { (yyval) = (yyvsp[(2) - (2)]); } + break; + + case 28: + +/* Line 1455 of yacc.c */ +#line 387 "awkgram.y" { - param_counter = 0; - } + param_counter = 0; + func_params = NULL; + } break; - case 23: + case 29: /* Line 1455 of yacc.c */ -#line 323 "awkgram.y" +#line 392 "awkgram.y" { NODE *t; - t = make_param((yyvsp[(3) - (7)].sval)); + (yyvsp[(1) - (7)])->source_file = source; + t = make_param((yyvsp[(3) - (7)])->lextok); + (yyvsp[(3) - (7)])->lextok = NULL; + bcfree((yyvsp[(3) - (7)])); t->flags |= FUNC; - (yyval.nodeval) = append_right(t, (yyvsp[(5) - (7)].nodeval)); + t->rnode = func_params; + func_params = t; + (yyval) = (yyvsp[(1) - (7)]); can_return = TRUE; /* check for duplicate parameter names */ - if (dup_parms((yyval.nodeval))) + if (dup_parms(t)) errcount++; } break; - case 24: + case 30: /* Line 1455 of yacc.c */ -#line 342 "awkgram.y" +#line 416 "awkgram.y" { ++want_regexp; } break; - case 25: + case 31: /* Line 1455 of yacc.c */ -#line 344 "awkgram.y" +#line 418 "awkgram.y" { - NODE *n; - size_t len = strlen((yyvsp[(3) - (3)].sval)); + NODE *n, *exp; + char *re; + size_t len; + re = (yyvsp[(3) - (3)])->lextok; + len = strlen(re); if (do_lint) { if (len == 0) lintwarn(_("regexp constant `//' looks like a C++ comment, but is not")); - else if (((yyvsp[(3) - (3)].sval))[0] == '*' && ((yyvsp[(3) - (3)].sval))[len-1] == '*') + else if ((re)[0] == '*' && (re)[len-1] == '*') /* possible C comment */ lintwarn(_("regexp constant `/%s/' looks like a C comment, but is not"), tokstart); } - getnode(n); - n->type = Node_regex; - n->re_exp = make_string((yyvsp[(3) - (3)].sval), len); - n->re_reg = make_regexp((yyvsp[(3) - (3)].sval), len, FALSE, TRUE); - n->re_text = NULL; - n->re_flags = CONSTANT; - n->re_cnt = 1; - (yyval.nodeval) = n; + + exp = make_str_node(re, len, ALREADY_MALLOCED); + n = make_regnode(Node_regex, exp); + if (n == NULL) { + unref(exp); + YYABORT; + } + (yyval) = (yyvsp[(3) - (3)]); + (yyval)->opcode = Op_match_rec; + (yyval)->memory = n; } break; - case 28: + case 32: /* Line 1455 of yacc.c */ -#line 373 "awkgram.y" - { (yyval.nodeval) = NULL; } +#line 447 "awkgram.y" + { bcfree((yyvsp[(1) - (1)])); } break; - case 29: + case 34: /* Line 1455 of yacc.c */ -#line 375 "awkgram.y" +#line 453 "awkgram.y" + { (yyval) = NULL; } + break; + + case 35: + +/* Line 1455 of yacc.c */ +#line 455 "awkgram.y" { - if ((yyvsp[(2) - (2)].nodeval) == NULL) - (yyval.nodeval) = (yyvsp[(1) - (2)].nodeval); + if ((yyvsp[(2) - (2)]) == NULL) + (yyval) = (yyvsp[(1) - (2)]); else { - if (do_lint && isnoeffect((yyvsp[(2) - (2)].nodeval)->type)) - lintwarn(_("statement may have no effect")); - if ((yyvsp[(1) - (2)].nodeval) == NULL) - (yyval.nodeval) = (yyvsp[(2) - (2)].nodeval); + add_lint((yyvsp[(2) - (2)]), LINT_no_effect); + if ((yyvsp[(1) - (2)]) == NULL) + (yyval) = (yyvsp[(2) - (2)]); else - (yyval.nodeval) = append_right( - ((yyvsp[(1) - (2)].nodeval)->type == Node_statement_list ? (yyvsp[(1) - (2)].nodeval) - : node((yyvsp[(1) - (2)].nodeval), Node_statement_list, (NODE *) NULL)), - ((yyvsp[(2) - (2)].nodeval)->type == Node_statement_list ? (yyvsp[(2) - (2)].nodeval) - : node((yyvsp[(2) - (2)].nodeval), Node_statement_list, (NODE *) NULL))); + (yyval) = list_merge((yyvsp[(1) - (2)]), (yyvsp[(2) - (2)])); } - yyerrok; + yyerrok; } break; - case 30: + case 36: /* Line 1455 of yacc.c */ -#line 393 "awkgram.y" - { (yyval.nodeval) = NULL; } +#line 468 "awkgram.y" + { (yyval) = NULL; } break; - case 33: + case 39: /* Line 1455 of yacc.c */ -#line 403 "awkgram.y" - { (yyval.nodeval) = NULL; } +#line 478 "awkgram.y" + { (yyval) = NULL; } break; - case 34: + case 40: /* Line 1455 of yacc.c */ -#line 405 "awkgram.y" - { (yyval.nodeval) = (yyvsp[(2) - (3)].nodeval); } +#line 480 "awkgram.y" + { (yyval) = (yyvsp[(2) - (3)]); } break; - case 35: + case 41: /* Line 1455 of yacc.c */ -#line 407 "awkgram.y" - { (yyval.nodeval) = (yyvsp[(1) - (1)].nodeval); } +#line 482 "awkgram.y" + { + if (do_profiling) + (yyval) = list_prepend((yyvsp[(1) - (1)]), instruction(Op_exec_count)); + else + (yyval) = (yyvsp[(1) - (1)]); + } break; - case 36: + case 42: /* Line 1455 of yacc.c */ -#line 409 "awkgram.y" - { (yyval.nodeval) = node((yyvsp[(3) - (9)].nodeval), Node_K_switch, (yyvsp[(7) - (9)].nodeval)); } +#line 489 "awkgram.y" + { + INSTRUCTION *ip; + + (yyvsp[(1) - (9)])->opcode = Op_push_loop; + (yyvsp[(1) - (9)])->target_continue = NULL; + ip = list_prepend((yyvsp[(3) - (9)]), (yyvsp[(1) - (9)])); + if ((yyvsp[(7) - (9)])->nexti->switch_dflt == NULL) + (yyvsp[(7) - (9)])->nexti->switch_dflt = (yyvsp[(1) - (9)]); /* implicit break */ + if (do_profiling) { + (void) list_prepend(ip, instruction(Op_exec_count)); + ((yyvsp[(1) - (9)]) + 1)->opcode = Op_K_switch; + ((yyvsp[(1) - (9)]) + 1)->switch_body = (yyvsp[(7) - (9)])->nexti; + } + (void) list_merge(ip, (yyvsp[(7) - (9)])); + (yyval) = list_append(ip, instruction(Op_pop_loop)); + (yyvsp[(1) - (9)])->target_break = (yyval)->lasti; + + break_allowed--; + fix_break_continue((yyvsp[(1) - (9)]), (yyval)->lasti, FALSE); + } break; - case 37: + case 43: /* Line 1455 of yacc.c */ -#line 411 "awkgram.y" - { (yyval.nodeval) = node((yyvsp[(3) - (6)].nodeval), Node_K_while, (yyvsp[(6) - (6)].nodeval)); } +#line 510 "awkgram.y" + { + /* + * [Op_push_loop| z| y] + * ----------------- + * z: + * cond + * ----------------- + * [Op_jmp_false y ] + * ----------------- + * body + * ----------------- + * [Op_jmp z ] + * y: [Op_pop_loop ] + */ + + INSTRUCTION *ip, *tp; + + tp = instruction(Op_pop_loop); + + add_lint((yyvsp[(3) - (6)]), LINT_assign_in_cond); + (yyvsp[(1) - (6)])->opcode = Op_push_loop; + (yyvsp[(1) - (6)])->target_continue = (yyvsp[(3) - (6)])->nexti; + (yyvsp[(1) - (6)])->target_break = tp; + ip = list_create((yyvsp[(1) - (6)])); + + (void) list_merge(ip, (yyvsp[(3) - (6)])); + (void) list_append(ip, instruction(Op_jmp_false)); + ip->lasti->target_jmp = tp; + + if (do_profiling) { + (void) list_append(ip, instruction(Op_exec_count)); + ((yyvsp[(1) - (6)]) + 1)->opcode = Op_K_while; + ((yyvsp[(1) - (6)]) + 1)->while_body = ip->lasti; + } + + if ((yyvsp[(6) - (6)]) != NULL) + (void) list_merge(ip, (yyvsp[(6) - (6)])); + (void) list_append(ip, instruction(Op_jmp)); + ip->lasti->target_jmp = (yyvsp[(1) - (6)])->target_continue; + (yyval) = list_append(ip, tp); + + break_allowed--; + continue_allowed--; + fix_break_continue((yyvsp[(1) - (6)]), tp, TRUE); + } break; - case 38: + case 44: /* Line 1455 of yacc.c */ -#line 413 "awkgram.y" - { (yyval.nodeval) = node((yyvsp[(6) - (8)].nodeval), Node_K_do, (yyvsp[(3) - (8)].nodeval)); } +#line 556 "awkgram.y" + { + /* + * [Op_push_loop | x | y] + * ----------------- + * z: + * body + * ----------------- + * x: + * cond + * ----------------- + * [Op_jmp_true | z ] + * y: [Op_pop_loop ] + */ + + INSTRUCTION *ip; + + (yyvsp[(4) - (8)])->opcode = Op_pop_loop; + (yyvsp[(1) - (8)])->opcode = Op_push_loop; + (yyvsp[(1) - (8)])->target_continue = (yyvsp[(6) - (8)])->nexti; + (yyvsp[(1) - (8)])->target_break = (yyvsp[(4) - (8)]); + + add_lint((yyvsp[(6) - (8)]), LINT_assign_in_cond); + if ((yyvsp[(3) - (8)]) != NULL) + ip = list_merge((yyvsp[(3) - (8)]), (yyvsp[(6) - (8)])); + else + ip = list_prepend((yyvsp[(6) - (8)]), instruction(Op_no_op)); + + if (do_profiling) { + (void) list_prepend(ip, instruction(Op_exec_count)); + ((yyvsp[(1) - (8)]) + 1)->opcode = Op_K_do; + ((yyvsp[(1) - (8)]) + 1)->doloop_cond = (yyvsp[(1) - (8)])->target_continue; + } + + (void) list_append(ip, instruction(Op_jmp_true)); + ip->lasti->target_jmp = ip->nexti; + (yyval) = list_prepend(ip, (yyvsp[(1) - (8)])); + (void) list_append(ip, (yyvsp[(4) - (8)])); + + break_allowed--; + continue_allowed--; + fix_break_continue((yyvsp[(1) - (8)]), (yyvsp[(4) - (8)]), TRUE); + } break; - case 39: + case 45: /* Line 1455 of yacc.c */ -#line 415 "awkgram.y" +#line 599 "awkgram.y" { - /* - * Efficiency hack. Recognize the special case of + + char *var_name = (yyvsp[(3) - (8)])->lextok; + + if ((yyvsp[(8) - (8)]) != NULL + && (yyvsp[(8) - (8)])->lasti->opcode == Op_K_delete + && (yyvsp[(8) - (8)])->lasti->expr_count == 1 + && (yyvsp[(8) - (8)])->nexti->opcode == Op_push + && ((yyvsp[(8) - (8)])->nexti->memory->type != Node_var || !((yyvsp[(8) - (8)])->nexti->memory->var_update)) + && strcmp((yyvsp[(8) - (8)])->nexti->memory->vname, var_name) == 0 + ) { + + /* Efficiency hack. Recognize the special case of * * for (iggy in foo) * delete foo[iggy] @@ -2320,1170 +2570,1652 @@ yyreduce: * * Check that the body is a `delete a[i]' statement, * and that both the loop var and array names match. - */ - if ((yyvsp[(8) - (8)].nodeval) != NULL && (yyvsp[(8) - (8)].nodeval)->type == Node_K_delete && (yyvsp[(8) - (8)].nodeval)->rnode != NULL) { - NODE *arr, *sub; - - assert((yyvsp[(8) - (8)].nodeval)->rnode->type == Node_expression_list); - arr = (yyvsp[(8) - (8)].nodeval)->lnode; /* array var */ - sub = (yyvsp[(8) - (8)].nodeval)->rnode->lnode; /* index var */ - - if ( (arr->type == Node_var_new - || arr->type == Node_var_array - || arr->type == Node_param_list) - && (sub->type == Node_var_new - || sub->type == Node_var - || sub->type == Node_param_list) - && strcmp((yyvsp[(3) - (8)].sval), sub->vname) == 0 - && strcmp((yyvsp[(5) - (8)].sval), arr->vname) == 0) { - (yyvsp[(8) - (8)].nodeval)->type = Node_K_delete_loop; - (yyval.nodeval) = (yyvsp[(8) - (8)].nodeval); - free((yyvsp[(3) - (8)].sval)); /* thanks to valgrind for pointing these out */ - free((yyvsp[(5) - (8)].sval)); + */ + NODE *arr = NULL; + INSTRUCTION *ip = (yyvsp[(8) - (8)])->nexti->nexti; + + if ((yyvsp[(5) - (8)])->nexti->opcode == Op_push && (yyvsp[(5) - (8)])->lasti == (yyvsp[(5) - (8)])->nexti) + arr = (yyvsp[(5) - (8)])->nexti->memory; + if (arr != NULL + && ip->opcode == Op_no_op + && ip->nexti->opcode == Op_push_array + && strcmp(ip->nexti->memory->vname, arr->vname) == 0 + && ip->nexti->nexti == (yyvsp[(8) - (8)])->lasti + ) { + (void) make_assignable((yyvsp[(8) - (8)])->nexti); + (yyvsp[(8) - (8)])->lasti->opcode = Op_K_delete_loop; + (yyvsp[(8) - (8)])->lasti->expr_count = 0; + bcfree((yyvsp[(1) - (8)])); + efree(var_name); + bcfree((yyvsp[(3) - (8)])); + bcfree((yyvsp[(4) - (8)])); + bcfree((yyvsp[(5) - (8)])); + (yyval) = (yyvsp[(8) - (8)]); } - else - goto regular_loop; } else { - regular_loop: - (yyval.nodeval) = node((yyvsp[(8) - (8)].nodeval), Node_K_arrayfor, - make_for_loop(variable((yyvsp[(3) - (8)].sval), CAN_FREE, Node_var), - (NODE *) NULL, variable((yyvsp[(5) - (8)].sval), CAN_FREE, Node_var_array))); - } + + /* [ Op_push_array a ] + * [ Op_arrayfor_init| w ] + * [ Op_push_loop | z | y ] + * z: [ Op_arrayfor_incr | y ] + * [ Op_var_assign if any ] + * + * body + * + * [Op_jmp | z ] + * y: [Op_pop_loop ] + * w: [Op_arrayfor_final ] + */ + INSTRUCTION *ip; + + ip = (yyvsp[(5) - (8)]); + ip->nexti->opcode = Op_push_array; + (yyvsp[(3) - (8)])->opcode = Op_arrayfor_init; + (void) list_append(ip, (yyvsp[(3) - (8)])); + + (yyvsp[(4) - (8)])->opcode = Op_arrayfor_incr; + (yyvsp[(4) - (8)])->array_var = variable(var_name, Node_var); + (yyvsp[(1) - (8)])->opcode = Op_push_loop; + (yyvsp[(1) - (8)])->target_continue = (yyvsp[(4) - (8)]); + + (void) list_append(ip, (yyvsp[(1) - (8)])); + + /* add update_FOO instruction if necessary */ + if ((yyvsp[(4) - (8)])->array_var->type == Node_var && (yyvsp[(4) - (8)])->array_var->var_update) { + (void) list_append(ip, instruction(Op_var_update)); + ip->lasti->memory = (yyvsp[(4) - (8)])->array_var; + } + (void) list_append(ip, (yyvsp[(4) - (8)])); + + /* add set_FOO instruction if necessary */ + if ((yyvsp[(4) - (8)])->array_var->type == Node_var && (yyvsp[(4) - (8)])->array_var->var_assign) { + (void) list_append(ip, instruction(Op_var_assign)); + ip->lasti->memory = (yyvsp[(4) - (8)])->array_var; + } + + if (do_profiling) { + (void) list_append(ip, instruction(Op_exec_count)); + ((yyvsp[(1) - (8)]) + 1)->opcode = Op_K_arrayfor; + ((yyvsp[(1) - (8)]) + 1)->forloop_cond = (yyvsp[(4) - (8)]); + ((yyvsp[(1) - (8)]) + 1)->forloop_body = ip->lasti; + } + + if ((yyvsp[(8) - (8)]) != NULL) + (void) list_merge(ip, (yyvsp[(8) - (8)])); + + (void) list_append(ip, instruction(Op_jmp)); + ip->lasti->target_jmp = (yyvsp[(4) - (8)]); + (void) list_append(ip, instruction(Op_pop_loop)); + (yyvsp[(4) - (8)])->target_jmp = (yyvsp[(1) - (8)])->target_break = ip->lasti; + (yyval) = list_append(ip, instruction(Op_arrayfor_final)); + (yyvsp[(3) - (8)])->target_jmp = (yyval)->lasti; + + fix_break_continue((yyvsp[(1) - (8)]), (yyvsp[(4) - (8)])->target_jmp, TRUE); + } + + break_allowed--; + continue_allowed--; } break; - case 40: + case 46: /* Line 1455 of yacc.c */ -#line 459 "awkgram.y" +#line 709 "awkgram.y" { - (yyval.nodeval) = node((yyvsp[(12) - (12)].nodeval), Node_K_for, (NODE *) make_for_loop((yyvsp[(3) - (12)].nodeval), (yyvsp[(6) - (12)].nodeval), (yyvsp[(9) - (12)].nodeval))); + (yyval) = mk_for_loop((yyvsp[(1) - (12)]), (yyvsp[(3) - (12)]), (yyvsp[(6) - (12)]), (yyvsp[(9) - (12)]), (yyvsp[(12) - (12)])); + + break_allowed--; + continue_allowed--; } break; - case 41: + case 47: /* Line 1455 of yacc.c */ -#line 463 "awkgram.y" +#line 716 "awkgram.y" { - (yyval.nodeval) = node((yyvsp[(11) - (11)].nodeval), Node_K_for, - (NODE *) make_for_loop((yyvsp[(3) - (11)].nodeval), (NODE *) NULL, (yyvsp[(8) - (11)].nodeval))); + (yyval) = mk_for_loop((yyvsp[(1) - (11)]), (yyvsp[(3) - (11)]), (INSTRUCTION *) NULL, (yyvsp[(8) - (11)]), (yyvsp[(11) - (11)])); + + break_allowed--; + continue_allowed--; } break; - case 42: + case 48: /* Line 1455 of yacc.c */ -#line 469 "awkgram.y" - { (yyval.nodeval) = node((NODE *) NULL, Node_K_break, (NODE *) NULL); } +#line 723 "awkgram.y" + { + if (do_profiling) + (yyval) = list_prepend((yyvsp[(1) - (1)]), instruction(Op_exec_count)); + else + (yyval) = (yyvsp[(1) - (1)]); + } break; - case 43: + case 49: /* Line 1455 of yacc.c */ -#line 472 "awkgram.y" - { (yyval.nodeval) = node((NODE *) NULL, Node_K_continue, (NODE *) NULL); } +#line 733 "awkgram.y" + { + if (! break_allowed) + yyerror(_("`break' is not allowed outside a loop or switch")); + + (yyvsp[(1) - (2)])->target_jmp = NULL; + (yyval) = list_create((yyvsp[(1) - (2)])); + + } break; - case 44: + case 50: /* Line 1455 of yacc.c */ -#line 474 "awkgram.y" - { NODETYPE type; +#line 742 "awkgram.y" + { + if (! continue_allowed) + yyerror(_("`continue' is not allowed outside a loop")); - if (begin_or_end_rule) - yyerror(_("`%s' used in %s action"), "next", - (parsing_end_rule ? "END" : "BEGIN")); - else if (beginfile_or_endfile_rule) - yyerror(_("`%s' used in %s action"), "next", - (parsing_endfile_rule ? "ENDFILE" : "BEGINFILE")); - type = Node_K_next; - (yyval.nodeval) = node((NODE *) NULL, type, (NODE *) NULL); - } + (yyvsp[(1) - (2)])->target_jmp = NULL; + (yyval) = list_create((yyvsp[(1) - (2)])); + + } break; - case 45: + case 51: /* Line 1455 of yacc.c */ -#line 486 "awkgram.y" +#line 751 "awkgram.y" { - static short warned = FALSE; + if (rule != Rule) + yyerror(_("`next' used in %s action"), ruletab[rule]); + (yyvsp[(1) - (2)])->target_jmp = ip_rec; + (yyval) = list_create((yyvsp[(1) - (2)])); + } + break; - if (do_traditional) { - /* - * can't use yyerror, since may have overshot - * the source line - */ + case 52: + +/* Line 1455 of yacc.c */ +#line 758 "awkgram.y" + { + static short warned = FALSE; + + if (do_traditional) { + /* + * can't use yyerror, since may have overshot + * the source line + */ errcount++; error(_("`nextfile' is a gawk extension")); - } - if (do_lint && ! warned) { - warned = TRUE; + } + if (do_lint && ! warned) { + warned = TRUE; lintwarn(_("`nextfile' is a gawk extension")); - } - if (begin_or_end_rule) { - /* same thing */ - errcount++; - error(_("`%s' used in %s action"), "nextfile", - (parsing_end_rule ? "END" : "BEGIN")); - } -#if 0 - else if (beginfile_or_endfile_rule) { - /* same thing */ - errcount++; - error(_("`%s' used in %s action"), "nextfile", - (parsing_endfile_rule ? "END" : "BEGIN")); - } -#endif - else if (parsing_endfile_rule) { - /* same thing */ + } + if (rule == BEGIN || rule == END || rule == ENDFILE) { errcount++; - error(_("`%s' used in %s action"), "nextfile", - (parsing_endfile_rule ? "ENDFILE" : "BEGINFILE")); - } - (yyval.nodeval) = node((NODE *) NULL, Node_K_nextfile, (NODE *) NULL); + error(_("`nextfile' used in %s action"), ruletab[rule]); } + + (yyvsp[(1) - (2)])->target_jmp = ip_newfile; + (yyvsp[(1) - (2)])->target_endfile = ip_endfile; + (yyval) = list_create((yyvsp[(1) - (2)])); + } break; - case 46: + case 53: /* Line 1455 of yacc.c */ -#line 524 "awkgram.y" - { (yyval.nodeval) = node((yyvsp[(2) - (3)].nodeval), Node_K_exit, (NODE *) NULL); } +#line 783 "awkgram.y" + { + if (rule == END) + (yyvsp[(1) - (3)])->target_jmp = ip_atexit; + else + (yyvsp[(1) - (3)])->target_jmp = ip_end; /* first instruction (no-op) in end block */ + + if ((yyvsp[(2) - (3)]) == NULL) { + (yyval) = list_create((yyvsp[(1) - (3)])); + (void) list_prepend((yyval), instruction(Op_push_i)); + (yyval)->nexti->memory = Nnull_string; + } else + (yyval) = list_append((yyvsp[(2) - (3)]), (yyvsp[(1) - (3)])); + } break; - case 47: + case 54: /* Line 1455 of yacc.c */ -#line 526 "awkgram.y" +#line 797 "awkgram.y" { - if (! can_return) + if (! can_return) yyerror(_("`return' used outside function context")); - } + } break; - case 48: + case 55: /* Line 1455 of yacc.c */ -#line 531 "awkgram.y" +#line 800 "awkgram.y" { - (yyval.nodeval) = node((yyvsp[(3) - (4)].nodeval) == NULL ? Nnull_string : (yyvsp[(3) - (4)].nodeval), - Node_K_return, (NODE *) NULL); - } + if ((yyvsp[(3) - (4)]) == NULL) { + (yyval) = list_create((yyvsp[(1) - (4)])); + (void) list_prepend((yyval), instruction(Op_push_i)); + (yyval)->nexti->memory = Nnull_string; + } else + (yyval) = list_append((yyvsp[(3) - (4)]), (yyvsp[(1) - (4)])); + } break; - case 50: + case 57: /* Line 1455 of yacc.c */ -#line 547 "awkgram.y" +#line 820 "awkgram.y" { in_print = TRUE; in_parens = 0; } break; - case 51: + case 58: /* Line 1455 of yacc.c */ -#line 548 "awkgram.y" +#line 821 "awkgram.y" { /* * Optimization: plain `print' has no expression list, so $3 is null. - * If $3 is an expression list with one element (rnode == null) - * and lnode is a field spec for field 0, we have `print $0'. - * For both, use Node_K_print_rec, which is faster for these two cases. + * If $3 is NULL or is a bytecode list for $0 use Op_K_print_rec, + * which is faster for these two cases. */ - if ((yyvsp[(1) - (4)].nodetypeval) == Node_K_print && - ((yyvsp[(3) - (4)].nodeval) == NULL - || ((yyvsp[(3) - (4)].nodeval)->type == Node_expression_list - && (yyvsp[(3) - (4)].nodeval)->rnode == NULL - && (yyvsp[(3) - (4)].nodeval)->lnode->type == Node_field_spec - && (yyvsp[(3) - (4)].nodeval)->lnode->lnode->type == Node_val - && (yyvsp[(3) - (4)].nodeval)->lnode->lnode->numbr == 0.0)) + + if ((yyvsp[(1) - (4)])->opcode == Op_K_print && + ((yyvsp[(3) - (4)]) == NULL + || ((yyvsp[(3) - (4)])->lasti->opcode == Op_field_spec + && (yyvsp[(3) - (4)])->nexti->nexti->nexti == (yyvsp[(3) - (4)])->lasti + && (yyvsp[(3) - (4)])->nexti->nexti->opcode == Op_push_i + && (yyvsp[(3) - (4)])->nexti->nexti->memory->type == Node_val + && (yyvsp[(3) - (4)])->nexti->nexti->memory->numbr == 0.0) + ) ) { static short warned = FALSE; + /* ----------------- + * output_redir + * [ redirect exp ] + * ----------------- + * expression_list + * ------------------ + * [Op_K_print_rec | NULL | redir_type | expr_count] + */ - (yyval.nodeval) = node(NULL, Node_K_print_rec, (yyvsp[(4) - (4)].nodeval)); + if ((yyvsp[(3) - (4)]) != NULL) { + bcfree((yyvsp[(3) - (4)])->lasti); /* Op_field_spec */ + (yyvsp[(3) - (4)])->nexti->nexti->memory->flags &= ~PERM; + (yyvsp[(3) - (4)])->nexti->nexti->memory->flags |= MALLOC; + unref((yyvsp[(3) - (4)])->nexti->nexti->memory); /* Node_val */ + bcfree((yyvsp[(3) - (4)])->nexti->nexti); /* Op_push_i */ + bcfree((yyvsp[(3) - (4)])->nexti); /* Op_list */ + bcfree((yyvsp[(3) - (4)])); /* Op_list */ + } else { + if (do_lint && (rule == BEGIN || rule == END) && ! warned) { + warned = TRUE; + lintwarn( + _("plain `print' in BEGIN or END rule should probably be `print \"\"'")); + } + } - if (do_lint && (yyvsp[(3) - (4)].nodeval) == NULL && begin_or_end_rule && ! warned) { - warned = TRUE; - lintwarn( - _("plain `print' in BEGIN or END rule should probably be `print \"\"'")); + (yyvsp[(1) - (4)])->expr_count = 0; + (yyvsp[(1) - (4)])->opcode = Op_K_print_rec; + if ((yyvsp[(4) - (4)]) == NULL) { /* no redircetion */ + (yyvsp[(1) - (4)])->redir_type = 0; + (yyval) = list_create((yyvsp[(1) - (4)])); + } else { + INSTRUCTION *ip; + ip = (yyvsp[(4) - (4)])->nexti; + (yyvsp[(1) - (4)])->redir_type = ip->redir_type; + (yyvsp[(4) - (4)])->nexti = ip->nexti; + bcfree(ip); + (yyval) = list_append((yyvsp[(4) - (4)]), (yyvsp[(1) - (4)])); } } else { - (yyval.nodeval) = node((yyvsp[(3) - (4)].nodeval), (yyvsp[(1) - (4)].nodetypeval), (yyvsp[(4) - (4)].nodeval)); - if ((yyval.nodeval)->type == Node_K_printf) - count_args((yyval.nodeval)); + /* ----------------- + * [ output_redir ] + * [ redirect exp ] + * ----------------- + * [ expression_list ] + * ------------------ + * [$1 | NULL | redir_type | expr_count] + * + */ + + if ((yyvsp[(4) - (4)]) == NULL) { /* no redirection */ + if ((yyvsp[(3) - (4)]) == NULL) { /* printf without arg */ + (yyvsp[(1) - (4)])->expr_count = 0; + (yyvsp[(1) - (4)])->redir_type = 0; + (yyval) = list_create((yyvsp[(1) - (4)])); + } else { + INSTRUCTION *t = (yyvsp[(3) - (4)]); + (yyvsp[(1) - (4)])->expr_count = count_expressions(&t, FALSE); + (yyvsp[(1) - (4)])->redir_type = 0; + (yyval) = list_append(t, (yyvsp[(1) - (4)])); + } + } else { + INSTRUCTION *ip; + ip = (yyvsp[(4) - (4)])->nexti; + (yyvsp[(1) - (4)])->redir_type = ip->redir_type; + (yyvsp[(4) - (4)])->nexti = ip->nexti; + bcfree(ip); + if ((yyvsp[(3) - (4)]) == NULL) { + (yyvsp[(1) - (4)])->expr_count = 0; + (yyval) = list_append((yyvsp[(4) - (4)]), (yyvsp[(1) - (4)])); + } else { + INSTRUCTION *t = (yyvsp[(3) - (4)]); + (yyvsp[(1) - (4)])->expr_count = count_expressions(&t, FALSE); + (yyval) = list_append(list_merge((yyvsp[(4) - (4)]), t), (yyvsp[(1) - (4)])); + } + } } } break; - case 52: + case 59: /* Line 1455 of yacc.c */ -#line 579 "awkgram.y" - { (yyval.nodeval) = node(variable((yyvsp[(2) - (5)].sval), CAN_FREE, Node_var_array), Node_K_delete, (yyvsp[(4) - (5)].nodeval)); } +#line 916 "awkgram.y" + { sub_counter = 0; } break; - case 53: + case 60: /* Line 1455 of yacc.c */ -#line 581 "awkgram.y" +#line 917 "awkgram.y" { - static short warned = FALSE; + char *arr = (yyvsp[(2) - (4)])->lextok; - if (do_lint && ! warned) { - warned = TRUE; - lintwarn(_("`delete array' is a gawk extension")); - } - if (do_traditional) { - /* - * can't use yyerror, since may have overshot - * the source line - */ - errcount++; - error(_("`delete array' is a gawk extension")); - } - (yyval.nodeval) = node(variable((yyvsp[(2) - (2)].sval), CAN_FREE, Node_var_array), Node_K_delete, (NODE *) NULL); + (yyvsp[(2) - (4)])->opcode = Op_push_array; + (yyvsp[(2) - (4)])->memory = variable(arr, Node_var_array); + + if ((yyvsp[(4) - (4)]) == NULL) { + static short warned = FALSE; + if (do_lint && ! warned) { + warned = TRUE; + lintwarn(_("`delete array' is a gawk extension")); + } + if (do_traditional) { + /* + * can't use yyerror, since may have overshot + * the source line + */ + errcount++; + error(_("`delete array' is a gawk extension")); + } + (yyvsp[(1) - (4)])->expr_count = 0; + (yyval) = list_append(list_create((yyvsp[(2) - (4)])), (yyvsp[(1) - (4)])); + } else { + (yyvsp[(1) - (4)])->expr_count = sub_counter; + (yyval) = list_append(list_append((yyvsp[(4) - (4)]), (yyvsp[(2) - (4)])), (yyvsp[(1) - (4)])); } + } break; - case 54: + case 61: /* Line 1455 of yacc.c */ -#line 599 "awkgram.y" +#line 949 "awkgram.y" { - /* - * this is for tawk compatibility. maybe the warnings - * should always be done. - */ - static short warned = FALSE; + static short warned = FALSE; + char *arr = (yyvsp[(3) - (4)])->lextok; - if (do_lint && ! warned) { + if (do_lint && ! warned) { warned = TRUE; lintwarn(_("`delete(array)' is a non-portable tawk extension")); - } - if (do_traditional) { + } + if (do_traditional) { /* * can't use yyerror, since may have overshot - * the source line + * the source line. */ errcount++; error(_("`delete(array)' is a non-portable tawk extension")); - } - (yyval.nodeval) = node(variable((yyvsp[(3) - (4)].sval), CAN_FREE, Node_var_array), Node_K_delete, (NODE *) NULL); } + (yyvsp[(3) - (4)])->memory = variable(arr, Node_var_array); + (yyvsp[(3) - (4)])->opcode = Op_push_array; + (yyvsp[(1) - (4)])->expr_count = 0; + (yyval) = list_append(list_create((yyvsp[(3) - (4)])), (yyvsp[(1) - (4)])); + } break; - case 55: + case 62: /* Line 1455 of yacc.c */ -#line 621 "awkgram.y" - { (yyval.nodeval) = (yyvsp[(1) - (1)].nodeval); } +#line 971 "awkgram.y" + { (yyval) = optimize_assignment((yyvsp[(1) - (1)])); } break; - case 56: + case 63: /* Line 1455 of yacc.c */ -#line 626 "awkgram.y" - { (yyval.nodeval) = NULL; } +#line 976 "awkgram.y" + { (yyval) = NULL; } break; - case 57: + case 64: /* Line 1455 of yacc.c */ -#line 628 "awkgram.y" - { (yyval.nodeval) = (yyvsp[(1) - (1)].nodeval); } +#line 978 "awkgram.y" + { (yyval) = (yyvsp[(1) - (1)]); } break; - case 58: + case 65: /* Line 1455 of yacc.c */ -#line 633 "awkgram.y" +#line 983 "awkgram.y" { - if ((yyvsp[(1) - (1)].nodeval) == NULL) { - (yyval.nodeval) = NULL; - } else { - NODE *dflt = NULL; - NODE *head = (yyvsp[(1) - (1)].nodeval); - NODE *curr; - - const char **case_values = NULL; - - int maxcount = 128; - int case_count = 0; - int i; - - emalloc(case_values, const char **, sizeof(char*) * maxcount, "switch_body"); - for (curr = (yyvsp[(1) - (1)].nodeval); curr != NULL; curr = curr->rnode) { - /* Assure that case statement values are unique. */ - if (curr->lnode->type == Node_K_case) { - char *caseval; - - if (curr->lnode->lnode->type == Node_regex) - caseval = curr->lnode->lnode->re_exp->stptr; - else - caseval = force_string(tree_eval(curr->lnode->lnode))->stptr; - - for (i = 0; i < case_count; i++) - if (strcmp(caseval, case_values[i]) == 0) - yyerror(_("duplicate case values in switch body: %s"), caseval); - - if (case_count >= maxcount) { - maxcount += 128; - erealloc(case_values, const char **, sizeof(char*) * maxcount, "switch_body"); + INSTRUCTION *dflt = NULL; + + if ((yyvsp[(1) - (1)]) != NULL) { + INSTRUCTION *curr; + const char **case_values = NULL; + int maxcount = 128; + int case_count = 0; + int i; + + emalloc(case_values, const char **, sizeof(char *) * maxcount, "statement"); + + for (curr = (yyvsp[(1) - (1)])->case_val->nexti; curr != NULL; curr = curr->nexti) { + if (curr->opcode == Op_K_case) { + char *caseval; + if (curr->memory->type == Node_regex) + caseval = curr->memory->re_exp->stptr; + else + caseval = force_string(curr->memory)->stptr; + for (i = 0; i < case_count; i++) + if (strcmp(caseval, case_values[i]) == 0) + yyerror(_("duplicate case values in switch body: %s"), caseval); + + if (case_count >= maxcount) { + maxcount += 128; + erealloc(case_values, const char **, sizeof(char*) * maxcount, "statement"); + } + case_values[case_count++] = caseval; + } else { + /* Otherwise save a pointer to the default node. */ + if (dflt != NULL) + yyerror(_("duplicate `default' detected in switch body")); + dflt = curr; } - case_values[case_count++] = caseval; - } else { - /* Otherwise save a pointer to the default node. */ - if (dflt != NULL) - yyerror(_("Duplicate `default' detected in switch body")); - dflt = curr; } + + efree(case_values); + (yyval) = list_prepend((yyvsp[(1) - (1)])->case_stmt, instruction(Op_K_switch)); + (yyval)->nexti->case_val = (yyvsp[(1) - (1)])->case_val->nexti; + (yyval)->nexti->switch_dflt = dflt; + bcfree((yyvsp[(1) - (1)])->case_val); /* Op_list */ + bcfree((yyvsp[(1) - (1)])); /* Op_case_list */ + } else { + (yyval) = list_create(instruction(Op_K_switch)); + (yyval)->nexti->case_val = NULL; + (yyval)->nexti->switch_dflt = NULL; } - - free(case_values); - - /* Create the switch body. */ - (yyval.nodeval) = node(head, Node_switch_body, dflt); } - } break; - case 59: + case 66: /* Line 1455 of yacc.c */ -#line 685 "awkgram.y" - { (yyval.nodeval) = NULL; } +#line 1035 "awkgram.y" + { (yyval) = NULL; } break; - case 60: + case 67: /* Line 1455 of yacc.c */ -#line 687 "awkgram.y" +#line 1037 "awkgram.y" { - if ((yyvsp[(2) - (2)].nodeval) == NULL) - (yyval.nodeval) = (yyvsp[(1) - (2)].nodeval); - else { - if (do_lint && isnoeffect((yyvsp[(2) - (2)].nodeval)->type)) - lintwarn(_("statement may have no effect")); - if ((yyvsp[(1) - (2)].nodeval) == NULL) - (yyval.nodeval) = node((yyvsp[(2) - (2)].nodeval), Node_case_list, (NODE *) NULL); - else - (yyval.nodeval) = append_right( - ((yyvsp[(1) - (2)].nodeval)->type == Node_case_list ? (yyvsp[(1) - (2)].nodeval) : node((yyvsp[(1) - (2)].nodeval), Node_case_list, (NODE *) NULL)), - ((yyvsp[(2) - (2)].nodeval)->type == Node_case_list ? (yyvsp[(2) - (2)].nodeval) : node((yyvsp[(2) - (2)].nodeval), Node_case_list, (NODE *) NULL)) - ); + if ((yyvsp[(1) - (2)]) == NULL) { + (yyvsp[(2) - (2)])->case_val = list_create((yyvsp[(2) - (2)])->case_val); + (yyval) = (yyvsp[(2) - (2)]); + } else { + (void) list_append((yyvsp[(1) - (2)])->case_val, (yyvsp[(2) - (2)])->case_val); + (void) list_merge((yyvsp[(1) - (2)])->case_stmt, (yyvsp[(2) - (2)])->case_stmt); + bcfree((yyvsp[(2) - (2)])); /* Op_case_list */ + (yyval) = (yyvsp[(1) - (2)]); } - yyerrok; } break; - case 61: - -/* Line 1455 of yacc.c */ -#line 704 "awkgram.y" - { (yyval.nodeval) = NULL; } - break; - - case 62: - -/* Line 1455 of yacc.c */ -#line 709 "awkgram.y" - { (yyval.nodeval) = node((yyvsp[(2) - (5)].nodeval), Node_K_case, (yyvsp[(5) - (5)].nodeval)); } - break; - - case 63: - -/* Line 1455 of yacc.c */ -#line 711 "awkgram.y" - { (yyval.nodeval) = node((NODE *) NULL, Node_K_default, (yyvsp[(4) - (4)].nodeval)); } - break; - - case 64: + case 68: /* Line 1455 of yacc.c */ -#line 716 "awkgram.y" - { (yyval.nodeval) = (yyvsp[(1) - (1)].nodeval); } +#line 1049 "awkgram.y" + { (yyval) = NULL; } break; - case 65: + case 69: /* Line 1455 of yacc.c */ -#line 718 "awkgram.y" +#line 1054 "awkgram.y" { - (yyvsp[(2) - (2)].nodeval)->numbr = -(force_number((yyvsp[(2) - (2)].nodeval))); - (yyval.nodeval) = (yyvsp[(2) - (2)].nodeval); + INSTRUCTION *casestmt = (yyvsp[(5) - (5)]); + + (yyvsp[(1) - (5)])->memory = (yyvsp[(2) - (5)])->memory; + bcfree((yyvsp[(2) - (5)])); + if ((yyvsp[(5) - (5)]) == NULL) + casestmt = list_create(instruction(Op_no_op)); + if (do_profiling) + (void) list_prepend(casestmt, instruction(Op_exec_count)); + + (yyvsp[(1) - (5)])->target_stmt = casestmt->nexti; + + /* recycle $3 as Op_case_list */ + (yyvsp[(3) - (5)])->opcode = Op_case_list; + (yyvsp[(3) - (5)])->case_val = (yyvsp[(1) - (5)]); /* Op_K_case */ + (yyvsp[(3) - (5)])->case_stmt = casestmt; /* Op_list */ + (yyval) = (yyvsp[(3) - (5)]); } break; - case 66: - -/* Line 1455 of yacc.c */ -#line 723 "awkgram.y" - { (yyval.nodeval) = (yyvsp[(2) - (2)].nodeval); } - break; - - case 67: + case 70: /* Line 1455 of yacc.c */ -#line 725 "awkgram.y" - { (yyval.nodeval) = (yyvsp[(1) - (1)].nodeval); } +#line 1073 "awkgram.y" + { + INSTRUCTION *casestmt = (yyvsp[(4) - (4)]); + + if ((yyvsp[(4) - (4)]) == NULL) + casestmt = list_create(instruction(Op_no_op)); + if (do_profiling) + (void) list_prepend(casestmt, instruction(Op_exec_count)); + + (yyvsp[(1) - (4)])->target_stmt = casestmt->nexti; + (yyvsp[(2) - (4)])->opcode = Op_case_list; + (yyvsp[(2) - (4)])->case_val = (yyvsp[(1) - (4)]); /* Op_K_default */ + (yyvsp[(2) - (4)])->case_stmt = casestmt; /* Op_list */ + (yyval) = (yyvsp[(2) - (4)]); + } break; - case 68: + case 71: /* Line 1455 of yacc.c */ -#line 727 "awkgram.y" - { (yyval.nodeval) = (yyvsp[(1) - (1)].nodeval); } +#line 1091 "awkgram.y" + { + (yyvsp[(1) - (1)])->opcode = Op_K_case; + (yyval) = (yyvsp[(1) - (1)]); + } break; case 72: /* Line 1455 of yacc.c */ -#line 742 "awkgram.y" - { (yyval.nodeval) = node((yyvsp[(2) - (5)].nodeval), Node_expression_list, (yyvsp[(4) - (5)].nodeval)); } +#line 1096 "awkgram.y" + { + (yyvsp[(2) - (2)])->memory->numbr = -(force_number((yyvsp[(2) - (2)])->memory)); + bcfree((yyvsp[(1) - (2)])); + (yyvsp[(2) - (2)])->opcode = Op_K_case; + (yyval) = (yyvsp[(2) - (2)]); + } break; case 73: /* Line 1455 of yacc.c */ -#line 747 "awkgram.y" +#line 1103 "awkgram.y" { - in_print = FALSE; - in_parens = 0; - (yyval.nodeval) = NULL; + bcfree((yyvsp[(1) - (2)])); + (yyvsp[(2) - (2)])->opcode = Op_K_case; + (yyval) = (yyvsp[(2) - (2)]); } break; case 74: /* Line 1455 of yacc.c */ -#line 752 "awkgram.y" - { in_print = FALSE; in_parens = 0; } +#line 1109 "awkgram.y" + { + (yyvsp[(1) - (1)])->opcode = Op_K_case; + (yyval) = (yyvsp[(1) - (1)]); + } break; case 75: /* Line 1455 of yacc.c */ -#line 753 "awkgram.y" +#line 1114 "awkgram.y" { - (yyval.nodeval) = node((yyvsp[(3) - (3)].nodeval), (yyvsp[(1) - (3)].nodetypeval), (NODE *) NULL); - if ((yyvsp[(1) - (3)].nodetypeval) == Node_redirect_twoway - && (yyvsp[(3) - (3)].nodeval)->type == Node_K_getline - && (yyvsp[(3) - (3)].nodeval)->rnode != NULL - && (yyvsp[(3) - (3)].nodeval)->rnode->type == Node_redirect_twoway) - yyerror(_("multistage two-way pipelines don't work")); + (yyvsp[(1) - (1)])->opcode = Op_K_case; + (yyval) = (yyvsp[(1) - (1)]); } break; case 76: /* Line 1455 of yacc.c */ -#line 765 "awkgram.y" - { - (yyval.nodeval) = node((yyvsp[(3) - (6)].nodeval), Node_K_if, - node((yyvsp[(6) - (6)].nodeval), Node_if_branches, (NODE *) NULL)); - } +#line 1122 "awkgram.y" + { (yyval) = (yyvsp[(1) - (1)]); } break; case 77: /* Line 1455 of yacc.c */ -#line 771 "awkgram.y" - { (yyval.nodeval) = node((yyvsp[(3) - (9)].nodeval), Node_K_if, - node((yyvsp[(6) - (9)].nodeval), Node_if_branches, (yyvsp[(9) - (9)].nodeval))); } +#line 1124 "awkgram.y" + { (yyval) = (yyvsp[(1) - (1)]); } break; - case 82: + case 79: /* Line 1455 of yacc.c */ -#line 787 "awkgram.y" - { (yyval.nodeval) = NULL; } - break; - - case 83: - -/* Line 1455 of yacc.c */ -#line 789 "awkgram.y" - { (yyval.nodeval) = node((yyvsp[(2) - (2)].nodeval), Node_redirect_input, (NODE *) NULL); } +#line 1134 "awkgram.y" + { + (yyval) = (yyvsp[(2) - (3)]); + } break; - case 84: + case 80: /* Line 1455 of yacc.c */ -#line 794 "awkgram.y" - { (yyval.nodeval) = NULL; } +#line 1141 "awkgram.y" + { + in_print = FALSE; + in_parens = 0; + (yyval) = NULL; + } break; - case 85: + case 81: /* Line 1455 of yacc.c */ -#line 796 "awkgram.y" - { (yyval.nodeval) = (yyvsp[(1) - (1)].nodeval); } +#line 1146 "awkgram.y" + { in_print = FALSE; in_parens = 0; } break; - case 86: + case 82: /* Line 1455 of yacc.c */ -#line 801 "awkgram.y" - { (yyval.nodeval) = make_param((yyvsp[(1) - (1)].sval)); } +#line 1147 "awkgram.y" + { + if ((yyvsp[(1) - (3)])->redir_type == redirect_twoway + && (yyvsp[(3) - (3)])->lasti->opcode == Op_K_getline_redir + && (yyvsp[(3) - (3)])->lasti->redir_type == redirect_twoway) + yyerror(_("multistage two-way pipelines don't work")); + (yyval) = list_prepend((yyvsp[(3) - (3)]), (yyvsp[(1) - (3)])); + } break; - case 87: + case 83: /* Line 1455 of yacc.c */ -#line 803 "awkgram.y" - { (yyval.nodeval) = append_right((yyvsp[(1) - (3)].nodeval), make_param((yyvsp[(3) - (3)].sval))); yyerrok; } +#line 1158 "awkgram.y" + { + (yyval) = mk_condition((yyvsp[(3) - (6)]), (yyvsp[(1) - (6)]), (yyvsp[(6) - (6)]), NULL, NULL); + } break; - case 88: + case 84: /* Line 1455 of yacc.c */ -#line 805 "awkgram.y" - { (yyval.nodeval) = NULL; } +#line 1163 "awkgram.y" + { + (yyval) = mk_condition((yyvsp[(3) - (9)]), (yyvsp[(1) - (9)]), (yyvsp[(6) - (9)]), (yyvsp[(7) - (9)]), (yyvsp[(9) - (9)])); + } break; case 89: /* Line 1455 of yacc.c */ -#line 807 "awkgram.y" - { (yyval.nodeval) = NULL; } +#line 1180 "awkgram.y" + { (yyval) = NULL; } break; case 90: /* Line 1455 of yacc.c */ -#line 809 "awkgram.y" - { (yyval.nodeval) = NULL; } - break; - - case 91: - -/* Line 1455 of yacc.c */ -#line 815 "awkgram.y" - { (yyval.nodeval) = NULL; } - break; - - case 92: - -/* Line 1455 of yacc.c */ -#line 817 "awkgram.y" - { (yyval.nodeval) = (yyvsp[(1) - (1)].nodeval); } +#line 1182 "awkgram.y" + { + bcfree((yyvsp[(1) - (2)])); + (yyval) = (yyvsp[(2) - (2)]); + } break; case 93: /* Line 1455 of yacc.c */ -#line 822 "awkgram.y" - { (yyval.nodeval) = NULL; } +#line 1195 "awkgram.y" + { + append_param((yyvsp[(1) - (1)])->lextok); + (yyvsp[(1) - (1)])->lextok = NULL; + bcfree((yyvsp[(1) - (1)])); + } break; case 94: /* Line 1455 of yacc.c */ -#line 824 "awkgram.y" - { (yyval.nodeval) = (yyvsp[(1) - (1)].nodeval); } +#line 1201 "awkgram.y" + { + append_param((yyvsp[(3) - (3)])->lextok); + (yyvsp[(3) - (3)])->lextok = NULL; + bcfree((yyvsp[(3) - (3)])); + yyerrok; + } break; case 95: /* Line 1455 of yacc.c */ -#line 829 "awkgram.y" - { (yyval.nodeval) = node((yyvsp[(1) - (1)].nodeval), Node_expression_list, (NODE *) NULL); } +#line 1208 "awkgram.y" + { /* func_params = NULL; */ } break; case 96: /* Line 1455 of yacc.c */ -#line 831 "awkgram.y" - { - (yyval.nodeval) = append_right((yyvsp[(1) - (3)].nodeval), - node((yyvsp[(3) - (3)].nodeval), Node_expression_list, (NODE *) NULL)); - yyerrok; - } +#line 1210 "awkgram.y" + { /* func_params = NULL; */ } break; case 97: /* Line 1455 of yacc.c */ -#line 837 "awkgram.y" - { (yyval.nodeval) = NULL; } +#line 1212 "awkgram.y" + { /* func_params = NULL; */ } break; case 98: /* Line 1455 of yacc.c */ -#line 839 "awkgram.y" - { (yyval.nodeval) = NULL; } +#line 1218 "awkgram.y" + { (yyval) = NULL; } break; case 99: /* Line 1455 of yacc.c */ -#line 841 "awkgram.y" - { (yyval.nodeval) = NULL; } +#line 1220 "awkgram.y" + { (yyval) = (yyvsp[(1) - (1)]); } break; case 100: /* Line 1455 of yacc.c */ -#line 843 "awkgram.y" - { (yyval.nodeval) = NULL; } +#line 1225 "awkgram.y" + { (yyval) = NULL; } break; case 101: /* Line 1455 of yacc.c */ -#line 848 "awkgram.y" - { - if (do_lint && (yyvsp[(3) - (3)].nodeval)->type == Node_regex) - lintwarn(_("regular expression on right of assignment")); - (yyval.nodeval) = optimize_concat((yyvsp[(1) - (3)].nodeval), (yyvsp[(2) - (3)].nodetypeval), (yyvsp[(3) - (3)].nodeval)); - } +#line 1227 "awkgram.y" + { (yyval) = (yyvsp[(1) - (1)]); } break; case 102: /* Line 1455 of yacc.c */ -#line 854 "awkgram.y" - { (yyval.nodeval) = node((yyvsp[(1) - (3)].nodeval), Node_and, (yyvsp[(3) - (3)].nodeval)); } +#line 1232 "awkgram.y" + { (yyval) = mk_expression_list(NULL, (yyvsp[(1) - (1)])); } break; case 103: /* Line 1455 of yacc.c */ -#line 856 "awkgram.y" - { (yyval.nodeval) = node((yyvsp[(1) - (3)].nodeval), Node_or, (yyvsp[(3) - (3)].nodeval)); } +#line 1234 "awkgram.y" + { + (yyval) = mk_expression_list((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)])); + yyerrok; + } break; case 104: /* Line 1455 of yacc.c */ -#line 858 "awkgram.y" - { - if ((yyvsp[(1) - (3)].nodeval)->type == Node_regex) - warning(_("regular expression on left of `~' or `!~' operator")); - (yyval.nodeval) = node((yyvsp[(1) - (3)].nodeval), (yyvsp[(2) - (3)].nodetypeval), mk_rexp((yyvsp[(3) - (3)].nodeval))); - } +#line 1239 "awkgram.y" + { (yyval) = NULL; } break; case 105: /* Line 1455 of yacc.c */ -#line 864 "awkgram.y" - { - if (do_lint_old) - warning(_("old awk does not support the keyword `in' except after `for'")); - (yyval.nodeval) = node(variable((yyvsp[(3) - (3)].sval), CAN_FREE, Node_var_array), Node_in_array, (yyvsp[(1) - (3)].nodeval)); - } +#line 1241 "awkgram.y" + { (yyval) = NULL; } break; case 106: /* Line 1455 of yacc.c */ -#line 870 "awkgram.y" - { - if (do_lint && (yyvsp[(3) - (3)].nodeval)->type == Node_regex) - lintwarn(_("regular expression on right of comparison")); - (yyval.nodeval) = node((yyvsp[(1) - (3)].nodeval), (yyvsp[(2) - (3)].nodetypeval), (yyvsp[(3) - (3)].nodeval)); - } +#line 1243 "awkgram.y" + { (yyval) = NULL; } break; case 107: /* Line 1455 of yacc.c */ -#line 876 "awkgram.y" - { (yyval.nodeval) = node((yyvsp[(1) - (5)].nodeval), Node_cond_exp, node((yyvsp[(3) - (5)].nodeval), Node_if_branches, (yyvsp[(5) - (5)].nodeval)));} +#line 1245 "awkgram.y" + { (yyval) = NULL; } break; case 108: /* Line 1455 of yacc.c */ -#line 878 "awkgram.y" - { (yyval.nodeval) = (yyvsp[(1) - (1)].nodeval); } +#line 1251 "awkgram.y" + { + if (do_lint && (yyvsp[(3) - (3)])->lasti->opcode == Op_match_rec) + lintwarn(_("regular expression on right of assignment")); + (yyval) = mk_assignment((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) - (3)])); + } break; case 109: /* Line 1455 of yacc.c */ -#line 883 "awkgram.y" - { (yyval.nodetypeval) = (yyvsp[(1) - (1)].nodetypeval); } +#line 1257 "awkgram.y" + { (yyval) = mk_boolean((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) - (3)])); } break; case 110: /* Line 1455 of yacc.c */ -#line 885 "awkgram.y" - { (yyval.nodetypeval) = (yyvsp[(1) - (1)].nodetypeval); } +#line 1259 "awkgram.y" + { (yyval) = mk_boolean((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) - (3)])); } break; case 111: /* Line 1455 of yacc.c */ -#line 887 "awkgram.y" - { (yyval.nodetypeval) = Node_assign_quotient; } +#line 1261 "awkgram.y" + { + if ((yyvsp[(1) - (3)])->lasti->opcode == Op_match_rec) + warning(_("regular expression on left of `~' or `!~' operator")); + + if ((yyvsp[(3) - (3)])->lasti == (yyvsp[(3) - (3)])->nexti && (yyvsp[(3) - (3)])->nexti->opcode == Op_match_rec) { + (yyvsp[(2) - (3)])->memory = (yyvsp[(3) - (3)])->nexti->memory; + bcfree((yyvsp[(3) - (3)])->nexti); /* Op_match_rec */ + bcfree((yyvsp[(3) - (3)])); /* Op_list */ + (yyval) = list_append((yyvsp[(1) - (3)]), (yyvsp[(2) - (3)])); + } else { + (yyvsp[(2) - (3)])->memory = make_regnode(Node_dynregex, NULL); + (yyval) = list_append(list_merge((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)])), (yyvsp[(2) - (3)])); + } + } break; case 112: /* Line 1455 of yacc.c */ -#line 892 "awkgram.y" - { (yyval.nodetypeval) = (yyvsp[(1) - (1)].nodetypeval); } +#line 1276 "awkgram.y" + { + if (do_lint_old) + warning(_("old awk does not support the keyword `in' except after `for'")); + (yyvsp[(3) - (3)])->nexti->opcode = Op_push_array; + (yyvsp[(2) - (3)])->opcode = Op_in_array; + (yyvsp[(2) - (3)])->expr_count = 1; + (yyval) = list_append(list_merge((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)])), (yyvsp[(2) - (3)])); + } break; case 113: /* Line 1455 of yacc.c */ -#line 894 "awkgram.y" - { (yyval.nodetypeval) = Node_less; } +#line 1285 "awkgram.y" + { + if (do_lint && (yyvsp[(3) - (3)])->lasti->opcode == Op_match_rec) + lintwarn(_("regular expression on right of comparison")); + (yyval) = list_append(list_merge((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)])), (yyvsp[(2) - (3)])); + } + break; + + case 114: + +/* Line 1455 of yacc.c */ +#line 1291 "awkgram.y" + { (yyval) = mk_condition((yyvsp[(1) - (5)]), (yyvsp[(2) - (5)]), (yyvsp[(3) - (5)]), (yyvsp[(4) - (5)]), (yyvsp[(5) - (5)])); } break; case 115: /* Line 1455 of yacc.c */ -#line 899 "awkgram.y" - { (yyval.nodetypeval) = Node_greater; } +#line 1293 "awkgram.y" + { (yyval) = (yyvsp[(1) - (1)]); } break; case 116: /* Line 1455 of yacc.c */ -#line 904 "awkgram.y" - { (yyval.nodeval) = (yyvsp[(1) - (1)].nodeval); } +#line 1298 "awkgram.y" + { (yyval) = (yyvsp[(1) - (1)]); } break; case 117: /* Line 1455 of yacc.c */ -#line 906 "awkgram.y" - { (yyval.nodeval) = (yyvsp[(1) - (1)].nodeval); } +#line 1300 "awkgram.y" + { (yyval) = (yyvsp[(1) - (1)]); } break; case 118: /* Line 1455 of yacc.c */ -#line 908 "awkgram.y" - { (yyval.nodeval) = constant_fold((yyvsp[(1) - (2)].nodeval), Node_concat, (yyvsp[(2) - (2)].nodeval)); } +#line 1302 "awkgram.y" + { + (yyvsp[(2) - (2)])->opcode = Op_assign_quotient; + (yyval) = (yyvsp[(2) - (2)]); + } + break; + + case 119: + +/* Line 1455 of yacc.c */ +#line 1310 "awkgram.y" + { (yyval) = (yyvsp[(1) - (1)]); } break; case 120: /* Line 1455 of yacc.c */ -#line 915 "awkgram.y" - { (yyval.nodeval) = constant_fold((yyvsp[(1) - (3)].nodeval), Node_exp, (yyvsp[(3) - (3)].nodeval)); } +#line 1312 "awkgram.y" + { (yyval) = (yyvsp[(1) - (1)]); } break; case 121: /* Line 1455 of yacc.c */ -#line 917 "awkgram.y" - { (yyval.nodeval) = constant_fold((yyvsp[(1) - (3)].nodeval), Node_times, (yyvsp[(3) - (3)].nodeval)); } +#line 1317 "awkgram.y" + { (yyval) = (yyvsp[(1) - (1)]); } break; case 122: /* Line 1455 of yacc.c */ -#line 919 "awkgram.y" - { (yyval.nodeval) = constant_fold((yyvsp[(1) - (3)].nodeval), Node_quotient, (yyvsp[(3) - (3)].nodeval)); } +#line 1319 "awkgram.y" + { (yyval) = (yyvsp[(1) - (1)]); } break; case 123: /* Line 1455 of yacc.c */ -#line 921 "awkgram.y" - { (yyval.nodeval) = constant_fold((yyvsp[(1) - (3)].nodeval), Node_mod, (yyvsp[(3) - (3)].nodeval)); } +#line 1324 "awkgram.y" + { (yyval) = (yyvsp[(1) - (1)]); } break; case 124: /* Line 1455 of yacc.c */ -#line 923 "awkgram.y" - { (yyval.nodeval) = constant_fold((yyvsp[(1) - (3)].nodeval), Node_plus, (yyvsp[(3) - (3)].nodeval)); } +#line 1326 "awkgram.y" + { (yyval) = (yyvsp[(1) - (1)]); } break; case 125: /* Line 1455 of yacc.c */ -#line 925 "awkgram.y" - { (yyval.nodeval) = constant_fold((yyvsp[(1) - (3)].nodeval), Node_minus, (yyvsp[(3) - (3)].nodeval)); } - break; - - case 126: - -/* Line 1455 of yacc.c */ -#line 927 "awkgram.y" +#line 1328 "awkgram.y" { - /* - * In BEGINFILE/ENDFILE, allow `getline var < file' - */ - if (beginfile_or_endfile_rule) { - if ((yyvsp[(2) - (3)].nodeval) != NULL && (yyvsp[(3) - (3)].nodeval) != NULL) - ; /* all ok */ - else { - if ((yyvsp[(2) - (3)].nodeval) != NULL) - fatal(_("`getline var' invalid inside %s rule"), - parsing_endfile_rule ? "ENDFILE" : "BEGINFILE"); - else - fatal(_("`getline' invalid inside %s rule"), - parsing_endfile_rule ? "ENDFILE" : "BEGINFILE"); - } - } - if (do_lint && parsing_end_rule && (yyvsp[(3) - (3)].nodeval) == NULL) - lintwarn(_("non-redirected `getline' undefined inside END action")); - (yyval.nodeval) = node((yyvsp[(2) - (3)].nodeval), Node_K_getline, (yyvsp[(3) - (3)].nodeval)); + int count = 2; + int is_simple_var = FALSE; + INSTRUCTION *ip1, *ip2; + + if ((yyvsp[(1) - (2)])->lasti->opcode == Op_concat) { + /* multiple (> 2) adjacent strings optimization */ + is_simple_var = ((yyvsp[(1) - (2)])->lasti->concat_flag & CSVAR); + count = (yyvsp[(1) - (2)])->lasti->expr_count + 1; + (yyvsp[(1) - (2)])->lasti->opcode = Op_no_op; + } else { + is_simple_var = ((yyvsp[(1) - (2)])->nexti->opcode == Op_push + && (yyvsp[(1) - (2)])->lasti == (yyvsp[(1) - (2)])->nexti); /* first exp. is a simple + * variable?; kludge for use + * in Op_assign_concat. + */ + } + ip1 = (yyvsp[(1) - (2)])->nexti; + ip2 = (yyvsp[(2) - (2)])->nexti; + if (ip1->memory != NULL && ip1->memory->type == Node_val && ip1 == (yyvsp[(1) - (2)])->lasti + && ip2->memory != NULL && ip2->memory->type == Node_val && ip2 == (yyvsp[(2) - (2)])->lasti && do_optimize > 1){ + size_t nlen; + + ip1->memory = force_string(ip1->memory); + ip2->memory = force_string(ip2->memory); + nlen = ip1->memory->stlen + ip2->memory->stlen; + erealloc(ip1->memory->stptr, char *, nlen + 2, "constant fold"); + memcpy(ip1->memory->stptr + ip1->memory->stlen, ip2->memory->stptr, ip2->memory->stlen); + ip1->memory->stlen = nlen; + ip1->memory->stptr[nlen] = '\0'; + ip1->memory->flags &= ~(NUMCUR|NUMBER); + ip1->memory->flags |= (STRING|STRCUR); + bcfree((yyvsp[(2) - (2)])); + bcfree(ip2); + (yyvsp[(1) - (2)])->opcode = Op_push_i; + (yyval) = (yyvsp[(1) - (2)]); + } else { + (yyval) = list_append(list_merge((yyvsp[(1) - (2)]), (yyvsp[(2) - (2)])), instruction(Op_concat)); + (yyval)->lasti->concat_flag = (is_simple_var ? CSVAR : 0); + (yyval)->lasti->expr_count = count; + if (count > max_args) + max_args = count; } + } break; case 127: /* Line 1455 of yacc.c */ -#line 948 "awkgram.y" - { (yyval.nodeval) = node((yyvsp[(1) - (2)].nodeval), Node_postincrement, (NODE *) NULL); } +#line 1378 "awkgram.y" + { (yyval) = mk_binary((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) - (3)])); } break; case 128: /* Line 1455 of yacc.c */ -#line 950 "awkgram.y" - { (yyval.nodeval) = node((yyvsp[(1) - (2)].nodeval), Node_postdecrement, (NODE *) NULL); } +#line 1380 "awkgram.y" + { (yyval) = mk_binary((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) - (3)])); } break; case 129: /* Line 1455 of yacc.c */ -#line 952 "awkgram.y" - { - if (do_lint_old) { - warning(_("old awk does not support the keyword `in' except after `for'")); - warning(_("old awk does not support multidimensional arrays")); - } - (yyval.nodeval) = node(variable((yyvsp[(5) - (5)].sval), CAN_FREE, Node_var_array), Node_in_array, (yyvsp[(2) - (5)].nodeval)); - } +#line 1382 "awkgram.y" + { (yyval) = mk_binary((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) - (3)])); } break; case 130: /* Line 1455 of yacc.c */ -#line 965 "awkgram.y" - { - (yyval.nodeval) = node((yyvsp[(4) - (4)].nodeval), Node_K_getline, - node((yyvsp[(1) - (4)].nodeval), (yyvsp[(2) - (4)].nodetypeval), (NODE *) NULL)); - } +#line 1384 "awkgram.y" + { (yyval) = mk_binary((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) - (3)])); } break; case 131: /* Line 1455 of yacc.c */ -#line 970 "awkgram.y" - { (yyval.nodeval) = node((yyvsp[(1) - (3)].nodeval), Node_exp, (yyvsp[(3) - (3)].nodeval)); } +#line 1386 "awkgram.y" + { (yyval) = mk_binary((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) - (3)])); } break; case 132: /* Line 1455 of yacc.c */ -#line 972 "awkgram.y" - { (yyval.nodeval) = node((yyvsp[(1) - (3)].nodeval), Node_times, (yyvsp[(3) - (3)].nodeval)); } +#line 1388 "awkgram.y" + { (yyval) = mk_binary((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) - (3)])); } break; case 133: /* Line 1455 of yacc.c */ -#line 974 "awkgram.y" - { (yyval.nodeval) = node((yyvsp[(1) - (3)].nodeval), Node_quotient, (yyvsp[(3) - (3)].nodeval)); } +#line 1390 "awkgram.y" + { + /* + * In BEGINFILE/ENDFILE, allow `getline var < file' + */ + if (rule == BEGINFILE || rule == ENDFILE) { + if ((yyvsp[(2) - (3)]) != NULL && (yyvsp[(3) - (3)]) != NULL) + ; /* all ok */ + else { + if ((yyvsp[(2) - (3)]) != NULL) + yyerror(_("`getline var' invalid inside `%s' rule"), ruletab[rule]); + else + yyerror(_("`getline' invalid inside `%s' rule"), ruletab[rule]); + YYABORT; + } + } + + if (do_lint && rule == END && (yyvsp[(3) - (3)]) == NULL) + lintwarn(_("non-redirected `getline' undefined inside END action")); + (yyval) = mk_getline((yyvsp[(1) - (3)]), (yyvsp[(2) - (3)]), (yyvsp[(3) - (3)]), redirect_input); + } break; case 134: /* Line 1455 of yacc.c */ -#line 976 "awkgram.y" - { (yyval.nodeval) = node((yyvsp[(1) - (3)].nodeval), Node_mod, (yyvsp[(3) - (3)].nodeval)); } +#line 1411 "awkgram.y" + { + (yyvsp[(2) - (2)])->opcode = Op_postincrement; + (yyval) = mk_assignment((yyvsp[(1) - (2)]), NULL, (yyvsp[(2) - (2)])); + } break; case 135: /* Line 1455 of yacc.c */ -#line 978 "awkgram.y" - { (yyval.nodeval) = node((yyvsp[(1) - (3)].nodeval), Node_plus, (yyvsp[(3) - (3)].nodeval)); } +#line 1416 "awkgram.y" + { + (yyvsp[(2) - (2)])->opcode = Op_postdecrement; + (yyval) = mk_assignment((yyvsp[(1) - (2)]), NULL, (yyvsp[(2) - (2)])); + } break; case 136: /* Line 1455 of yacc.c */ -#line 980 "awkgram.y" - { (yyval.nodeval) = node((yyvsp[(1) - (3)].nodeval), Node_minus, (yyvsp[(3) - (3)].nodeval)); } +#line 1421 "awkgram.y" + { + if (do_lint_old) { + warning(_("old awk does not support the keyword `in' except after `for'")); + warning(_("old awk does not support multidimensional arrays")); + } + (yyvsp[(5) - (5)])->nexti->opcode = Op_push_array; + (yyvsp[(4) - (5)])->opcode = Op_in_array; + if ((yyvsp[(2) - (5)]) == NULL) { /* error */ + errcount++; + (yyvsp[(4) - (5)])->expr_count = 0; + (yyval) = list_merge((yyvsp[(5) - (5)]), (yyvsp[(4) - (5)])); + } else { + INSTRUCTION *t = (yyvsp[(2) - (5)]); + (yyvsp[(4) - (5)])->expr_count = count_expressions(&t, FALSE); + (yyval) = list_append(list_merge(t, (yyvsp[(5) - (5)])), (yyvsp[(4) - (5)])); + } + } break; case 137: /* Line 1455 of yacc.c */ -#line 985 "awkgram.y" - { (yyval.nodeval) = (yyvsp[(1) - (1)].nodeval); } +#line 1444 "awkgram.y" + { + (yyval) = mk_getline((yyvsp[(3) - (4)]), (yyvsp[(4) - (4)]), (yyvsp[(1) - (4)]), (yyvsp[(2) - (4)])->redir_type); + bcfree((yyvsp[(2) - (4)])); + } break; case 138: /* Line 1455 of yacc.c */ -#line 987 "awkgram.y" - { (yyval.nodeval) = constant_fold((yyvsp[(2) - (2)].nodeval), Node_not, (NODE *) NULL); } +#line 1450 "awkgram.y" + { (yyval) = mk_binary((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) - (3)])); } break; case 139: /* Line 1455 of yacc.c */ -#line 989 "awkgram.y" - { (yyval.nodeval) = (yyvsp[(2) - (3)].nodeval); } +#line 1452 "awkgram.y" + { (yyval) = mk_binary((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) - (3)])); } break; case 140: /* Line 1455 of yacc.c */ -#line 992 "awkgram.y" - { (yyval.nodeval) = snode((yyvsp[(3) - (4)].nodeval), Node_builtin, (int) (yyvsp[(1) - (4)].lval)); } +#line 1454 "awkgram.y" + { (yyval) = mk_binary((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) - (3)])); } break; case 141: /* Line 1455 of yacc.c */ -#line 994 "awkgram.y" - { (yyval.nodeval) = snode((yyvsp[(3) - (4)].nodeval), Node_builtin, (int) (yyvsp[(1) - (4)].lval)); } +#line 1456 "awkgram.y" + { (yyval) = mk_binary((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) - (3)])); } break; case 142: /* Line 1455 of yacc.c */ -#line 996 "awkgram.y" - { - static short warned1 = FALSE, warned2 = FALSE; +#line 1458 "awkgram.y" + { (yyval) = mk_binary((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) - (3)])); } + break; - if (do_lint && ! warned1) { - warned1 = TRUE; - lintwarn(_("call of `length' without parentheses is not portable")); - } - (yyval.nodeval) = snode((NODE *) NULL, Node_builtin, (int) (yyvsp[(1) - (1)].lval)); - if (do_posix && ! warned2) { - warned2 = TRUE; - warning(_("call of `length' without parentheses is deprecated by POSIX")); - } + case 143: + +/* Line 1455 of yacc.c */ +#line 1460 "awkgram.y" + { (yyval) = mk_binary((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) - (3)])); } + break; + + case 144: + +/* Line 1455 of yacc.c */ +#line 1465 "awkgram.y" + { + (yyval) = list_create((yyvsp[(1) - (1)])); } break; case 145: /* Line 1455 of yacc.c */ -#line 1012 "awkgram.y" - { (yyval.nodeval) = node((yyvsp[(2) - (2)].nodeval), Node_preincrement, (NODE *) NULL); } +#line 1469 "awkgram.y" + { + if ((yyvsp[(2) - (2)])->opcode == Op_match_rec) { + (yyvsp[(2) - (2)])->opcode = Op_nomatch; + (yyvsp[(1) - (2)])->opcode = Op_push_i; + (yyvsp[(1) - (2)])->memory = mk_number(0.0, (PERM|NUMCUR|NUMBER)); + (yyval) = list_append(list_append(list_create((yyvsp[(1) - (2)])), + instruction(Op_field_spec)), (yyvsp[(2) - (2)])); + } else { + INSTRUCTION *ip; + ip = (yyvsp[(2) - (2)])->nexti; + if (ip->memory->type == Node_val && (yyvsp[(2) - (2)])->lasti == ip && do_optimize > 1) { + NODE *ret; + if ((ip->memory->flags & (STRCUR|STRING)) != 0) { + if (ip->memory->stlen == 0) { + ret = make_number((AWKNUM) 1.0); + } else { + ret = make_number((AWKNUM) 0.0); + } + } else { + if (ip->memory->numbr == 0) { + ret = make_number((AWKNUM) 1.0); + } else { + ret = make_number((AWKNUM) 0.0); + } + } + ret->flags &= ~MALLOC; + ret->flags |= PERM; + (yyvsp[(1) - (2)])->memory = ret; + (yyvsp[(1) - (2)])->opcode = Op_push_i; + bcfree(ip); + bcfree((yyvsp[(2) - (2)])); + (yyval) = list_create((yyvsp[(1) - (2)])); + } else { + (yyvsp[(1) - (2)])->opcode = Op_not; + add_lint((yyvsp[(2) - (2)]), LINT_assign_in_cond); + (yyval) = list_append((yyvsp[(2) - (2)]), (yyvsp[(1) - (2)])); + } + } + } break; case 146: /* Line 1455 of yacc.c */ -#line 1014 "awkgram.y" - { (yyval.nodeval) = node((yyvsp[(2) - (2)].nodeval), Node_predecrement, (NODE *) NULL); } +#line 1509 "awkgram.y" + { (yyval) = (yyvsp[(2) - (3)]); } break; case 147: /* Line 1455 of yacc.c */ -#line 1016 "awkgram.y" - { (yyval.nodeval) = (yyvsp[(1) - (1)].nodeval); } +#line 1511 "awkgram.y" + { + (yyval) = snode((yyvsp[(3) - (4)]), (yyvsp[(1) - (4)])); + if ((yyval) == NULL) + YYABORT; + } break; case 148: /* Line 1455 of yacc.c */ -#line 1018 "awkgram.y" - { (yyval.nodeval) = (yyvsp[(1) - (1)].nodeval); } +#line 1517 "awkgram.y" + { + (yyval) = snode((yyvsp[(3) - (4)]), (yyvsp[(1) - (4)])); + if ((yyval) == NULL) + YYABORT; + } break; case 149: /* Line 1455 of yacc.c */ -#line 1021 "awkgram.y" +#line 1523 "awkgram.y" { - if ((yyvsp[(2) - (2)].nodeval)->type == Node_val && ((yyvsp[(2) - (2)].nodeval)->flags & (STRCUR|STRING)) == 0) { - (yyvsp[(2) - (2)].nodeval)->numbr = -(force_number((yyvsp[(2) - (2)].nodeval))); - (yyval.nodeval) = (yyvsp[(2) - (2)].nodeval); - } else - (yyval.nodeval) = node((yyvsp[(2) - (2)].nodeval), Node_unary_minus, (NODE *) NULL); + static short warned1 = FALSE; + + if (do_lint && ! warned1) { + warned1 = TRUE; + lintwarn(_("call of `length' without parentheses is not portable")); } + (yyval) = snode(NULL, (yyvsp[(1) - (1)])); + if ((yyval) == NULL) + YYABORT; + } break; - case 150: + case 152: + +/* Line 1455 of yacc.c */ +#line 1537 "awkgram.y" + { + (yyvsp[(1) - (2)])->opcode = Op_preincrement; + (yyval) = mk_assignment((yyvsp[(2) - (2)]), NULL, (yyvsp[(1) - (2)])); + } + break; + + case 153: + +/* Line 1455 of yacc.c */ +#line 1542 "awkgram.y" + { + (yyvsp[(1) - (2)])->opcode = Op_predecrement; + (yyval) = mk_assignment((yyvsp[(2) - (2)]), NULL, (yyvsp[(1) - (2)])); + } + break; + + case 154: /* Line 1455 of yacc.c */ -#line 1029 "awkgram.y" +#line 1547 "awkgram.y" { - /* - * was: $$ = $2 - * POSIX semantics: force a conversion to numeric type - */ - (yyval.nodeval) = node (make_number(0.0), Node_plus, (yyvsp[(2) - (2)].nodeval)); + (yyval) = list_create((yyvsp[(1) - (1)])); + } + break; + + case 155: + +/* Line 1455 of yacc.c */ +#line 1551 "awkgram.y" + { + (yyval) = list_create((yyvsp[(1) - (1)])); + } + break; + + case 156: + +/* Line 1455 of yacc.c */ +#line 1555 "awkgram.y" + { + if ((yyvsp[(2) - (2)])->lasti->opcode == Op_push_i + && ((yyvsp[(2) - (2)])->lasti->memory->flags & (STRCUR|STRING)) == 0) { + (yyvsp[(2) - (2)])->lasti->memory->numbr = -(force_number((yyvsp[(2) - (2)])->lasti->memory)); + (yyval) = (yyvsp[(2) - (2)]); + bcfree((yyvsp[(1) - (2)])); + } else { + (yyvsp[(1) - (2)])->opcode = Op_unary_minus; + (yyval) = list_append((yyvsp[(2) - (2)]), (yyvsp[(1) - (2)])); } + } break; - case 151: + case 157: /* Line 1455 of yacc.c */ -#line 1040 "awkgram.y" +#line 1567 "awkgram.y" { - func_use((yyvsp[(1) - (1)].nodeval)->rnode->stptr, FUNC_USE); - (yyval.nodeval) = (yyvsp[(1) - (1)].nodeval); + /* + * was: $$ = $2 + * POSIX semantics: force a conversion to numeric type + */ + (yyvsp[(1) - (2)])->opcode = Op_plus_i; + (yyvsp[(1) - (2)])->memory = mk_number((AWKNUM) 0.0, (PERM|NUMCUR|NUMBER)); + (yyval) = list_append((yyvsp[(2) - (2)]), (yyvsp[(1) - (2)])); } break; - case 152: + case 158: + +/* Line 1455 of yacc.c */ +#line 1580 "awkgram.y" + { + func_use((yyvsp[(1) - (1)])->lasti->func_name, FUNC_USE); + (yyval) = (yyvsp[(1) - (1)]); + } + break; + + case 159: /* Line 1455 of yacc.c */ -#line 1045 "awkgram.y" +#line 1585 "awkgram.y" { /* indirect function call */ + INSTRUCTION *f, *t; + char *name; + NODE *indirect_var; static short warned = FALSE; + const char *msg = _("indirect function calls are a gawk extension"); - if (do_lint && ! warned) { + if (do_traditional || do_posix) + yyerror("%s", msg); + else if (do_lint && ! warned) { warned = TRUE; - lintwarn(_("indirect function calls are a gawk extension")); + lintwarn("%s", msg); } + + f = (yyvsp[(2) - (2)])->lasti; + f->opcode = Op_indirect_func_call; + name = estrdup(f->func_name, strlen(f->func_name)); + indirect_var = variable(name, Node_var_new); + if (is_std_var(name)) + yyerror(_("can not use special variable `%s' for indirect function call"), name); + t = instruction(Op_push); + t->memory = indirect_var; + + /* prepend indirect var instead of appending to arguments (opt_expression_list), + * and pop it off in setup_frame (eval.c) (left to right evaluation order); Test case: + * f = "fun" + * @f(f="real_fun") + */ - (yyval.nodeval) = (yyvsp[(2) - (2)].nodeval); - (yyval.nodeval)->type = Node_indirect_func_call; + (yyval) = list_prepend((yyvsp[(2) - (2)]), t); } break; - case 153: + case 160: /* Line 1455 of yacc.c */ -#line 1061 "awkgram.y" +#line 1621 "awkgram.y" { - (yyval.nodeval) = node((yyvsp[(3) - (4)].nodeval), Node_func_call, make_string((yyvsp[(1) - (4)].sval), strlen((yyvsp[(1) - (4)].sval)))); - (yyval.nodeval)->funcbody = NULL; - param_sanity((yyvsp[(3) - (4)].nodeval)); - free((yyvsp[(1) - (4)].sval)); + param_sanity((yyvsp[(3) - (4)])); + (yyvsp[(1) - (4)])->opcode = Op_func_call; + (yyvsp[(1) - (4)])->func_body = NULL; + if ((yyvsp[(3) - (4)]) == NULL) { /* no argument or error */ + ((yyvsp[(1) - (4)]) + 1)->expr_count = 0; + (yyval) = list_create((yyvsp[(1) - (4)])); + } else { + INSTRUCTION *t = (yyvsp[(3) - (4)]); + ((yyvsp[(1) - (4)]) + 1)->expr_count = count_expressions(&t, TRUE); + (yyval) = list_append(t, (yyvsp[(1) - (4)])); + } } break; - case 154: + case 161: /* Line 1455 of yacc.c */ -#line 1071 "awkgram.y" - { (yyval.nodeval) = NULL; } +#line 1638 "awkgram.y" + { (yyval) = NULL; } break; - case 155: + case 162: /* Line 1455 of yacc.c */ -#line 1073 "awkgram.y" - { (yyval.nodeval) = (yyvsp[(1) - (1)].nodeval); } +#line 1640 "awkgram.y" + { (yyval) = (yyvsp[(1) - (1)]); } break; - case 156: + case 163: /* Line 1455 of yacc.c */ -#line 1078 "awkgram.y" - { (yyval.nodeval) = variable((yyvsp[(1) - (1)].sval), CAN_FREE, Node_var_new); } +#line 1645 "awkgram.y" + { (yyval) = NULL; } break; - case 157: + case 164: /* Line 1455 of yacc.c */ -#line 1080 "awkgram.y" +#line 1647 "awkgram.y" + { (yyval) = (yyvsp[(1) - (2)]); } + break; + + case 165: + +/* Line 1455 of yacc.c */ +#line 1652 "awkgram.y" + { (yyval) = (yyvsp[(1) - (1)]); } + break; + + case 166: + +/* Line 1455 of yacc.c */ +#line 1654 "awkgram.y" + { + (yyval) = list_merge((yyvsp[(1) - (2)]), (yyvsp[(2) - (2)])); + } + break; + + case 167: + +/* Line 1455 of yacc.c */ +#line 1661 "awkgram.y" + { + INSTRUCTION *ip = (yyvsp[(1) - (1)])->lasti; + int count = ip->sub_count; /* # of SUBSEP-seperated expressions */ + if (count > 1) { + /* change Op_subscript or Op_sub_array to Op_concat */ + ip->opcode = Op_concat; + ip->concat_flag = CSUBSEP; + ip->expr_count = count; + } else + ip->opcode = Op_no_op; + sub_counter++; /* count # of dimensions */ + (yyval) = (yyvsp[(1) - (1)]); + } + break; + + case 168: + +/* Line 1455 of yacc.c */ +#line 1678 "awkgram.y" + { + INSTRUCTION *t = (yyvsp[(2) - (3)]); + if ((yyvsp[(2) - (3)]) == NULL) { + errcount++; + error(_("invalid subscript expression")); + /* install Null string as subscript. */ + t = list_create(instruction(Op_push_i)); + t->nexti->memory = Nnull_string; + (yyvsp[(3) - (3)])->sub_count = 1; + } else + (yyvsp[(3) - (3)])->sub_count = count_expressions(&t, FALSE); + (yyval) = list_append(t, (yyvsp[(3) - (3)])); + } + break; + + case 169: + +/* Line 1455 of yacc.c */ +#line 1695 "awkgram.y" + { (yyval) = (yyvsp[(1) - (1)]); } + break; + + case 170: + +/* Line 1455 of yacc.c */ +#line 1697 "awkgram.y" + { + (yyval) = list_merge((yyvsp[(1) - (2)]), (yyvsp[(2) - (2)])); + } + break; + + case 171: + +/* Line 1455 of yacc.c */ +#line 1704 "awkgram.y" + { (yyval) = (yyvsp[(1) - (2)]); } + break; + + case 172: + +/* Line 1455 of yacc.c */ +#line 1709 "awkgram.y" + { + char *var_name = (yyvsp[(1) - (1)])->lextok; + + (yyvsp[(1) - (1)])->opcode = Op_push; + (yyvsp[(1) - (1)])->memory = variable(var_name, Node_var_new); + (yyval) = list_create((yyvsp[(1) - (1)])); + } + break; + + case 173: + +/* Line 1455 of yacc.c */ +#line 1717 "awkgram.y" { NODE *n; - if ((n = lookup((yyvsp[(1) - (4)].sval))) != NULL && ! isarray(n)) { + char *arr = (yyvsp[(1) - (2)])->lextok; + if ((n = lookup(arr)) != NULL && ! isarray(n)) yyerror(_("use of non-array as array")); - (yyval.nodeval) = node(variable((yyvsp[(1) - (4)].sval), CAN_FREE, Node_var_array), Node_subscript, (yyvsp[(3) - (4)].nodeval)); - } else if ((yyvsp[(3) - (4)].nodeval) == NULL) { - fatal(_("invalid subscript expression")); - } else if ((yyvsp[(3) - (4)].nodeval)->rnode == NULL) { - (yyval.nodeval) = node(variable((yyvsp[(1) - (4)].sval), CAN_FREE, Node_var_array), Node_subscript, (yyvsp[(3) - (4)].nodeval)->lnode); - freenode((yyvsp[(3) - (4)].nodeval)); - } else - (yyval.nodeval) = node(variable((yyvsp[(1) - (4)].sval), CAN_FREE, Node_var_array), Node_subscript, (yyvsp[(3) - (4)].nodeval)); + (yyvsp[(1) - (2)])->memory = variable(arr, Node_var_array); + (yyvsp[(1) - (2)])->opcode = Op_push_array; + (yyval) = list_prepend((yyvsp[(2) - (2)]), (yyvsp[(1) - (2)])); } break; - case 158: + case 174: /* Line 1455 of yacc.c */ -#line 1094 "awkgram.y" - { (yyval.nodeval) = (yyvsp[(1) - (1)].nodeval); } +#line 1731 "awkgram.y" + { + INSTRUCTION *ip = (yyvsp[(1) - (1)])->nexti; + if (ip->opcode == Op_push + && ip->memory->type == Node_var + && ip->memory->var_update + ) { + (yyval) = list_prepend((yyvsp[(1) - (1)]), instruction(Op_var_update)); + (yyval)->nexti->memory = ip->memory; + } else + (yyval) = (yyvsp[(1) - (1)]); + } break; - case 159: + case 175: /* Line 1455 of yacc.c */ -#line 1105 "awkgram.y" +#line 1743 "awkgram.y" { - NODE *n = node((yyvsp[(2) - (3)].nodeval), Node_field_spec, (NODE *) NULL); - if ((yyvsp[(3) - (3)].sval) != NULL) { - if ((yyvsp[(3) - (3)].sval)[0] == '+') - (yyval.nodeval) = node(n, Node_postincrement, (NODE *) NULL); - else - (yyval.nodeval) = node(n, Node_postdecrement, (NODE *) NULL); - } else { - (yyval.nodeval) = n; - } + (yyval) = list_append((yyvsp[(2) - (3)]), (yyvsp[(1) - (3)])); + if ((yyvsp[(3) - (3)]) != NULL) + mk_assignment((yyvsp[(2) - (3)]), NULL, (yyvsp[(3) - (3)])); } break; - case 160: + case 176: /* Line 1455 of yacc.c */ -#line 1119 "awkgram.y" - { (yyval.sval) = "+"; } +#line 1752 "awkgram.y" + { + (yyvsp[(1) - (1)])->opcode = Op_postincrement; + } break; - case 161: + case 177: /* Line 1455 of yacc.c */ -#line 1120 "awkgram.y" - { (yyval.sval) = "-"; } +#line 1756 "awkgram.y" + { + (yyvsp[(1) - (1)])->opcode = Op_postdecrement; + } break; - case 162: + case 178: /* Line 1455 of yacc.c */ -#line 1121 "awkgram.y" - { (yyval.sval) = NULL; } +#line 1759 "awkgram.y" + { (yyval) = NULL; } break; - case 164: + case 180: /* Line 1455 of yacc.c */ -#line 1129 "awkgram.y" +#line 1767 "awkgram.y" { yyerrok; } break; - case 165: + case 181: /* Line 1455 of yacc.c */ -#line 1133 "awkgram.y" +#line 1771 "awkgram.y" { yyerrok; } break; - case 168: + case 184: /* Line 1455 of yacc.c */ -#line 1142 "awkgram.y" +#line 1780 "awkgram.y" { yyerrok; } break; - case 169: + case 185: /* Line 1455 of yacc.c */ -#line 1146 "awkgram.y" - { yyerrok; } +#line 1784 "awkgram.y" + { (yyval) = (yyvsp[(1) - (1)]); yyerrok; } break; - case 170: + case 186: /* Line 1455 of yacc.c */ -#line 1149 "awkgram.y" +#line 1788 "awkgram.y" { yyerrok; } break; /* Line 1455 of yacc.c */ -#line 3487 "awkgram.c" +#line 4231 "awkgram.c" default: break; } YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc); @@ -3695,14 +4427,14 @@ yyreturn: /* Line 1675 of yacc.c */ -#line 1152 "awkgram.y" +#line 1790 "awkgram.y" struct token { - const char *operator; /* text to match */ - NODETYPE value; /* node type */ - int class; /* lexical class */ - unsigned flags; /* # of args. allowed and compatability */ + const char *operator; /* text to match */ + OPCODE value; /* type */ + int class; /* lexical class */ + unsigned flags; /* # of args. allowed and compatability */ # define ARGS 0xFF /* 0, 1, 2, 3 args allowed (any combination */ # define A(n) (1<<(n)) # define VERSION_MASK 0xFF00 /* old awk is zero */ @@ -3710,7 +4442,9 @@ struct token { # define NOT_POSIX 0x0200 /* feature not in POSIX */ # define GAWKX 0x0400 /* gawk extension */ # define RESX 0x0800 /* Bell Labs Research extension */ - NODE *(*ptr) P((NODE *)); /* function that implements this keyword */ +# define BREAK 0x1000 /* break allowed inside */ +# define CONTINUE 0x2000 /* continue allowed inside */ + NODE *(*ptr)(int); /* function that implements this keyword */ }; #if 'a' == 0x81 /* it's EBCDIC */ @@ -3735,77 +4469,79 @@ tokcompare(void *l, void *r) */ static const struct token tokentab[] = { -{"BEGIN", Node_illegal, LEX_BEGIN, 0, 0}, -{"BEGINFILE", Node_illegal, LEX_BEGINFILE, GAWKX, 0}, -{"END", Node_illegal, LEX_END, 0, 0}, -{"ENDFILE", Node_illegal, LEX_ENDFILE, GAWKX, 0}, +{"BEGIN", Op_rule, LEX_BEGIN, 0, 0}, +{"BEGINFILE", Op_rule, LEX_BEGINFILE, GAWKX, 0}, +{"END", Op_rule, LEX_END, 0, 0}, +{"ENDFILE", Op_rule, LEX_ENDFILE, GAWKX, 0}, #ifdef ARRAYDEBUG -{"adump", Node_builtin, LEX_BUILTIN, GAWKX|A(1), do_adump}, +{"adump", Op_builtin, LEX_BUILTIN, GAWKX|A(1), do_adump}, #endif -{"and", Node_builtin, LEX_BUILTIN, GAWKX|A(2), do_and}, -{"asort", Node_builtin, LEX_BUILTIN, GAWKX|A(1)|A(2), do_asort}, -{"asorti", Node_builtin, LEX_BUILTIN, GAWKX|A(1)|A(2), do_asorti}, -{"atan2", Node_builtin, LEX_BUILTIN, NOT_OLD|A(2), do_atan2}, -{"bindtextdomain", Node_builtin, LEX_BUILTIN, GAWKX|A(1)|A(2), do_bindtextdomain}, -{"break", Node_K_break, LEX_BREAK, 0, 0}, -{"case", Node_K_case, LEX_CASE, GAWKX, 0}, -{"close", Node_builtin, LEX_BUILTIN, NOT_OLD|A(1)|A(2), do_close}, -{"compl", Node_builtin, LEX_BUILTIN, GAWKX|A(1), do_compl}, -{"continue", Node_K_continue, LEX_CONTINUE, 0, 0}, -{"cos", Node_builtin, LEX_BUILTIN, NOT_OLD|A(1), do_cos}, -{"dcgettext", Node_builtin, LEX_BUILTIN, GAWKX|A(1)|A(2)|A(3), do_dcgettext}, -{"dcngettext", Node_builtin, LEX_BUILTIN, GAWKX|A(1)|A(2)|A(3)|A(4)|A(5), do_dcngettext}, -{"default", Node_K_default, LEX_DEFAULT, GAWKX, 0}, -{"delete", Node_K_delete, LEX_DELETE, NOT_OLD, 0}, -{"do", Node_K_do, LEX_DO, NOT_OLD, 0}, -{"else", Node_illegal, LEX_ELSE, 0, 0}, -{"exit", Node_K_exit, LEX_EXIT, 0, 0}, -{"exp", Node_builtin, LEX_BUILTIN, A(1), do_exp}, -{"extension", Node_builtin, LEX_BUILTIN, GAWKX|A(2), do_ext}, -{"fflush", Node_builtin, LEX_BUILTIN, RESX|A(0)|A(1), do_fflush}, -{"for", Node_K_for, LEX_FOR, 0, 0}, -{"func", Node_K_function, LEX_FUNCTION, NOT_POSIX|NOT_OLD, 0}, -{"function", Node_K_function, LEX_FUNCTION, NOT_OLD, 0}, -{"gensub", Node_builtin, LEX_BUILTIN, GAWKX|A(3)|A(4), do_gensub}, -{"getline", Node_K_getline, LEX_GETLINE, NOT_OLD, 0}, -{"gsub", Node_builtin, LEX_BUILTIN, NOT_OLD|A(2)|A(3), do_gsub}, -{"if", Node_K_if, LEX_IF, 0, 0}, -{"in", Node_illegal, LEX_IN, 0, 0}, -{"index", Node_builtin, LEX_BUILTIN, A(2), do_index}, -{"int", Node_builtin, LEX_BUILTIN, A(1), do_int}, -{"length", Node_builtin, LEX_LENGTH, A(0)|A(1), do_length}, -{"log", Node_builtin, LEX_BUILTIN, A(1), do_log}, -{"lshift", Node_builtin, LEX_BUILTIN, GAWKX|A(2), do_lshift}, -{"match", Node_builtin, LEX_BUILTIN, NOT_OLD|A(2)|A(3), do_match}, -{"mktime", Node_builtin, LEX_BUILTIN, GAWKX|A(1), do_mktime}, -{"next", Node_K_next, LEX_NEXT, 0, 0}, -{"nextfile", Node_K_nextfile, LEX_NEXTFILE, GAWKX, 0}, -{"or", Node_builtin, LEX_BUILTIN, GAWKX|A(2), do_or}, -{"patsplit", Node_builtin, LEX_BUILTIN, GAWKX|A(2)|A(3)|A(4), do_patsplit}, -{"print", Node_K_print, LEX_PRINT, 0, 0}, -{"printf", Node_K_printf, LEX_PRINTF, 0, 0}, -{"rand", Node_builtin, LEX_BUILTIN, NOT_OLD|A(0), do_rand}, -{"return", Node_K_return, LEX_RETURN, NOT_OLD, 0}, -{"rshift", Node_builtin, LEX_BUILTIN, GAWKX|A(2), do_rshift}, -{"sin", Node_builtin, LEX_BUILTIN, NOT_OLD|A(1), do_sin}, -{"split", Node_builtin, LEX_BUILTIN, A(2)|A(3)|A(4), do_split}, -{"sprintf", Node_builtin, LEX_BUILTIN, 0, do_sprintf}, -{"sqrt", Node_builtin, LEX_BUILTIN, A(1), do_sqrt}, -{"srand", Node_builtin, LEX_BUILTIN, NOT_OLD|A(0)|A(1), do_srand}, +{"and", Op_builtin, LEX_BUILTIN, GAWKX|A(2), do_and}, +{"asort", Op_builtin, LEX_BUILTIN, GAWKX|A(1)|A(2), do_asort}, +{"asorti", Op_builtin, LEX_BUILTIN, GAWKX|A(1)|A(2), do_asorti}, +{"atan2", Op_builtin, LEX_BUILTIN, NOT_OLD|A(2), do_atan2}, +{"bindtextdomain", Op_builtin, LEX_BUILTIN, GAWKX|A(1)|A(2), do_bindtextdomain}, +{"break", Op_K_break, LEX_BREAK, 0, 0}, +{"case", Op_K_case, LEX_CASE, GAWKX, 0}, +{"close", Op_builtin, LEX_BUILTIN, NOT_OLD|A(1)|A(2), do_close}, +{"compl", Op_builtin, LEX_BUILTIN, GAWKX|A(1), do_compl}, +{"continue", Op_K_continue, LEX_CONTINUE, 0, 0}, +{"cos", Op_builtin, LEX_BUILTIN, NOT_OLD|A(1), do_cos}, +{"dcgettext", Op_builtin, LEX_BUILTIN, GAWKX|A(1)|A(2)|A(3), do_dcgettext}, +{"dcngettext", Op_builtin, LEX_BUILTIN, GAWKX|A(1)|A(2)|A(3)|A(4)|A(5), do_dcngettext}, +{"default", Op_K_default, LEX_DEFAULT, GAWKX, 0}, +{"delete", Op_K_delete, LEX_DELETE, NOT_OLD, 0}, +{"do", Op_symbol, LEX_DO, NOT_OLD|BREAK|CONTINUE, 0}, +{"else", Op_K_else, LEX_ELSE, 0, 0}, +{"eval", Op_symbol, LEX_EVAL, 0, 0}, +{"exit", Op_K_exit, LEX_EXIT, 0, 0}, +{"exp", Op_builtin, LEX_BUILTIN, A(1), do_exp}, +{"extension", Op_builtin, LEX_BUILTIN, GAWKX|A(2), do_ext}, +{"fflush", Op_builtin, LEX_BUILTIN, RESX|A(0)|A(1), do_fflush}, +{"for", Op_symbol, LEX_FOR, BREAK|CONTINUE, 0}, +{"func", Op_func, LEX_FUNCTION, NOT_POSIX|NOT_OLD, 0}, +{"function",Op_func, LEX_FUNCTION, NOT_OLD, 0}, +{"gensub", Op_builtin, LEX_BUILTIN, GAWKX|A(3)|A(4), do_gensub}, +{"getline", Op_K_getline_redir, LEX_GETLINE, NOT_OLD, 0}, +{"gsub", Op_builtin, LEX_BUILTIN, NOT_OLD|A(2)|A(3), do_gsub}, +{"if", Op_K_if, LEX_IF, 0, 0}, +{"in", Op_symbol, LEX_IN, 0, 0}, +{"include", Op_symbol, LEX_INCLUDE, GAWKX, 0}, +{"index", Op_builtin, LEX_BUILTIN, A(2), do_index}, +{"int", Op_builtin, LEX_BUILTIN, A(1), do_int}, +{"length", Op_builtin, LEX_LENGTH, A(0)|A(1), do_length}, +{"log", Op_builtin, LEX_BUILTIN, A(1), do_log}, +{"lshift", Op_builtin, LEX_BUILTIN, GAWKX|A(2), do_lshift}, +{"match", Op_builtin, LEX_BUILTIN, NOT_OLD|A(2)|A(3), do_match}, +{"mktime", Op_builtin, LEX_BUILTIN, GAWKX|A(1), do_mktime}, +{"next", Op_K_next, LEX_NEXT, 0, 0}, +{"nextfile", Op_K_nextfile, LEX_NEXTFILE, GAWKX, 0}, +{"or", Op_builtin, LEX_BUILTIN, GAWKX|A(2), do_or}, +{"patsplit", Op_builtin, LEX_BUILTIN, GAWKX|A(2)|A(3)|A(4), do_patsplit}, +{"print", Op_K_print, LEX_PRINT, 0, 0}, +{"printf", Op_K_printf, LEX_PRINTF, 0, 0}, +{"rand", Op_builtin, LEX_BUILTIN, NOT_OLD|A(0), do_rand}, +{"return", Op_K_return, LEX_RETURN, NOT_OLD, 0}, +{"rshift", Op_builtin, LEX_BUILTIN, GAWKX|A(2), do_rshift}, +{"sin", Op_builtin, LEX_BUILTIN, NOT_OLD|A(1), do_sin}, +{"split", Op_builtin, LEX_BUILTIN, A(2)|A(3)|A(4), do_split}, +{"sprintf", Op_builtin, LEX_BUILTIN, 0, do_sprintf}, +{"sqrt", Op_builtin, LEX_BUILTIN, A(1), do_sqrt}, +{"srand", Op_builtin, LEX_BUILTIN, NOT_OLD|A(0)|A(1), do_srand}, #if defined(GAWKDEBUG) || defined(ARRAYDEBUG) /* || ... */ -{"stopme", Node_builtin, LEX_BUILTIN, GAWKX|A(0), stopme}, +{"stopme", Op_builtin, LEX_BUILTIN, GAWKX|A(0), stopme}, #endif -{"strftime", Node_builtin, LEX_BUILTIN, GAWKX|A(0)|A(1)|A(2)|A(3), do_strftime}, -{"strtonum", Node_builtin, LEX_BUILTIN, GAWKX|A(1), do_strtonum}, -{"sub", Node_builtin, LEX_BUILTIN, NOT_OLD|A(2)|A(3), do_sub}, -{"substr", Node_builtin, LEX_BUILTIN, A(2)|A(3), do_substr}, -{"switch", Node_K_switch, LEX_SWITCH, GAWKX, 0}, -{"system", Node_builtin, LEX_BUILTIN, NOT_OLD|A(1), do_system}, -{"systime", Node_builtin, LEX_BUILTIN, GAWKX|A(0), do_systime}, -{"tolower", Node_builtin, LEX_BUILTIN, NOT_OLD|A(1), do_tolower}, -{"toupper", Node_builtin, LEX_BUILTIN, NOT_OLD|A(1), do_toupper}, -{"while", Node_K_while, LEX_WHILE, 0, 0}, -{"xor", Node_builtin, LEX_BUILTIN, GAWKX|A(2), do_xor}, +{"strftime", Op_builtin, LEX_BUILTIN, GAWKX|A(0)|A(1)|A(2)|A(3), do_strftime}, +{"strtonum", Op_builtin, LEX_BUILTIN, GAWKX|A(1), do_strtonum}, +{"sub", Op_builtin, LEX_BUILTIN, NOT_OLD|A(2)|A(3), do_sub}, +{"substr", Op_builtin, LEX_BUILTIN, A(2)|A(3), do_substr}, +{"switch", Op_symbol, LEX_SWITCH, GAWKX|BREAK, 0}, +{"system", Op_builtin, LEX_BUILTIN, NOT_OLD|A(1), do_system}, +{"systime", Op_builtin, LEX_BUILTIN, GAWKX|A(0), do_systime}, +{"tolower", Op_builtin, LEX_BUILTIN, NOT_OLD|A(1), do_tolower}, +{"toupper", Op_builtin, LEX_BUILTIN, NOT_OLD|A(1), do_toupper}, +{"while", Op_symbol, LEX_WHILE, BREAK|CONTINUE, 0}, +{"xor", Op_builtin, LEX_BUILTIN, GAWKX|A(2), do_xor}, }; #ifdef MBS_SUPPORT @@ -3828,9 +4564,9 @@ static int cur_ring_idx; /* getfname --- return name of a builtin function (for pretty printing) */ const char * -getfname(register NODE *(*fptr)(NODE *)) +getfname(NODE *(*fptr)(int)) { - register int i, j; + int i, j; j = sizeof(tokentab) / sizeof(tokentab[0]); /* linear search, no other way to do it */ @@ -3849,22 +4585,44 @@ getfname(register NODE *(*fptr)(NODE *)) */ static void -#ifdef CAN_USE_STDARG_H - yyerror(const char *m, ...) -#else -/* VARARGS0 */ - yyerror(va_alist) - va_dcl -#endif +yyerror(const char *m, ...) { va_list args; const char *mesg = NULL; - register char *bp, *cp; + char *bp, *cp; char *scan; char *buf; int count; static char end_of_file_line[] = "(END OF FILE)"; char save; + int saveline; + SRCFILE *s; + + /* suppress current file name, line # from `.. included from ..' msgs */ + saveline = sourceline; + sourceline = 0; + + for (s = sourcefile; s->stype == SRC_INC; ) { + int line; + s = s->next; + if (s->fd <= INVALID_HANDLE) + continue; + + line = s->srclines; + /* if last token is NEWLINE, line number is off by 1. */ + if (s->lasttok == NEWLINE) + line--; + + msg("%s %s:%d%c", + s->prev == sourcefile ? "In file included from" + : " from", + (s->stype == SRC_INC || + s->stype == SRC_FILE) ? s->src : "cmd. line", + line, + s->stype == SRC_INC ? ',' : ':' + ); + } + sourceline = saveline; errcount++; /* Find the current line in the input file */ @@ -3904,15 +4662,9 @@ static void *bp = save; -#ifdef CAN_USE_STDARG_H va_start(args, m); if (mesg == NULL) mesg = m; -#else - va_start(args); - if (mesg == NULL) - mesg = va_arg(args, char *); -#endif count = (bp - thisline) + strlen(mesg) + 2 + 1; emalloc(buf, char *, count, "yyerror"); @@ -3931,7 +4683,333 @@ static void strcpy(bp, mesg); err("", buf, args); va_end(args); - free(buf); + efree(buf); +} + +/* mk_program --- create a single list of instructions */ + +static INSTRUCTION * +mk_program() +{ + INSTRUCTION *cp, *tmp; + +#define begin_block rule_block[BEGIN] +#define end_block rule_block[END] +#define prog_block rule_block[Rule] +#define beginfile_block rule_block[BEGINFILE] +#define endfile_block rule_block[ENDFILE] + + if (end_block == NULL) + end_block = list_create(ip_end); + else + (void) list_prepend(end_block, ip_end); + + if (get_context()->level > 0) { + if (begin_block != NULL && prog_block != NULL) + cp = list_merge(begin_block, prog_block); + else + cp = (begin_block != NULL) ? begin_block : prog_block; + + if (cp != NULL) + (void) list_merge(cp, end_block); + else + cp = end_block; + + (void) list_append(cp, instruction(Op_stop)); + goto out; + } + + if (endfile_block == NULL) + endfile_block = list_create(ip_endfile); + else { + extern int has_endfile; /* kludge for use in inrec (io.c) */ + has_endfile = TRUE; + (void) list_prepend(endfile_block, ip_endfile); + } + + if (beginfile_block == NULL) + beginfile_block = list_create(ip_beginfile); + else + (void) list_prepend(beginfile_block, ip_beginfile); + + if (prog_block == NULL) { + if (end_block->nexti == end_block->lasti + && beginfile_block->nexti == beginfile_block->lasti + && endfile_block->nexti == endfile_block->lasti + ) { + /* no pattern-action and (real) end, beginfile or endfile blocks */ + bcfree(ip_rec); + bcfree(ip_newfile); + ip_rec = ip_newfile = NULL; + + list_append(beginfile_block, instruction(Op_after_beginfile)); + (void) list_append(endfile_block, instruction(Op_after_endfile)); + + if (begin_block == NULL) /* no program at all */ + cp = end_block; + else + cp = list_merge(begin_block, end_block); + (void) list_append(cp, ip_atexit); + (void) list_append(cp, instruction(Op_stop)); + + /* append beginfile_block and endfile_block for sole use + * in getline without redirection (Op_K_getline). + */ + + (void) list_merge(cp, beginfile_block); + (void) list_merge(cp, endfile_block); + + goto out; + + } else { + /* install a do-nothing prog block */ + prog_block = list_create(instruction(Op_no_op)); + } + } + + (void) list_append(endfile_block, instruction(Op_after_endfile)); + (void) list_prepend(prog_block, ip_rec); + (void) list_append(prog_block, instruction(Op_jmp)); + prog_block->lasti->target_jmp = ip_rec; + + list_append(beginfile_block, instruction(Op_after_beginfile)); + + cp = list_merge(beginfile_block, prog_block); + (void) list_prepend(cp, ip_newfile); + (void) list_merge(cp, endfile_block); + (void) list_merge(cp, end_block); + if (begin_block != NULL) + cp = list_merge(begin_block, cp); + + (void) list_append(cp, ip_atexit); + (void) list_append(cp, instruction(Op_stop)); + +out: + /* delete the Op_list, not needed */ + tmp = cp->nexti; + bcfree(cp); + return tmp; + +#undef begin_block +#undef end_block +#undef prog_block +#undef beginfile_block +#undef endfile_block +} + +/* parse_program --- read in the program and convert into a list of instructions */ + +int +parse_program(INSTRUCTION **pcode) +{ + int ret; + + /* pre-create non-local jump targets + * ip_end (Op_no_op) -- used as jump target for `exit' + * outside an END block. + */ + ip_end = instruction(Op_no_op); + + if (get_context()->level > 0) + ip_newfile = ip_rec = ip_atexit = ip_beginfile = ip_endfile = NULL; + else { + ip_endfile = instruction(Op_no_op); + ip_beginfile = instruction(Op_no_op); + ip_newfile = instruction(Op_newfile); /* target for `nextfile' */ + ip_newfile->target_jmp = ip_end; + ip_newfile->target_endfile = ip_endfile; + ip_rec = instruction(Op_get_record); /* target for `next' */ + ip_atexit = instruction(Op_atexit); /* target for `exit' in END block */ + } + + sourcefile = srcfiles->next; + lexeof = FALSE; + lexptr = NULL; + lasttok = 0; + memset(rule_block, 0, sizeof(ruletab) * sizeof(INSTRUCTION *)); + errcount = 0; + tok = tokstart != NULL ? tokstart : tokexpand(); + + ret = yyparse(); + *pcode = mk_program(); + + /* avoid false source indications */ + source = NULL; + sourceline = 0; + + check_funcs(); + return (ret || errcount); +} + +/* do_add_srcfile --- add one item to srcfiles */ + +static SRCFILE * +do_add_srcfile(int stype, char *src, char *path, SRCFILE *thisfile) +{ + SRCFILE *s; + + emalloc(s, SRCFILE *, sizeof(SRCFILE), "do_add_srcfile"); + memset(s, 0, sizeof(SRCFILE)); + s->src = estrdup(src, strlen(src)); + s->fullpath = path; + s->stype = stype; + s->fd = INVALID_HANDLE; + s->next = thisfile; + s->prev = thisfile->prev; + thisfile->prev->next = s; + thisfile->prev = s; + return s; +} + +/* add_srcfile --- add one item to srcfiles after checking if + * a source file exists and not already in list. + */ + +SRCFILE * +add_srcfile(int stype, char *src, SRCFILE *thisfile, int *already_included, int *errcode) +{ + SRCFILE *s; + struct stat sbuf; + char *path; + int errno_val = 0; + + if (already_included) + *already_included = FALSE; + if (errcode) + *errcode = 0; + if (stype == SRC_CMDLINE || stype == SRC_STDIN) + return do_add_srcfile(stype, src, NULL, thisfile); + + path = find_source(src, &sbuf, &errno_val); + if (path == NULL) { + if (errcode) { + *errcode = errno_val; + return NULL; + } + fatal(_("can't open source file `%s' for reading (%s)"), + src, errno_val ? strerror(errno_val) : _("reason unknown")); + } + + for (s = srcfiles->next; s != srcfiles; s = s->next) { + if ((s->stype == SRC_FILE || s->stype == SRC_INC) + && files_are_same(& sbuf, & s->sbuf) + ) { + if (do_lint) + lintwarn(_("already included source file `%s'"), src); + efree(path); + if (already_included) + *already_included = TRUE; + return NULL; + } + } + + s = do_add_srcfile(stype, src, path, thisfile); + s->sbuf = sbuf; + s->mtime = sbuf.st_mtime; + return s; +} + +/* include_source --- read program from source included using `@include' */ + +static int +include_source(char *src) +{ + SRCFILE *s; + int errcode; + int already_included; + + if (do_traditional || do_posix) { + error(_("@include is a gawk extension")); + errcount++; + return -1; + } + + if (strlen(src) == 0) { + if (do_lint) + lintwarn(_("empty filename after @include")); + return 0; + } + + s = add_srcfile(SRC_INC, src, sourcefile, &already_included, &errcode); + if (s == NULL) { + if (already_included) + return 0; + error(_("can't open source file `%s' for reading (%s)"), + src, errcode ? strerror(errcode) : _("reason unknown")); + errcount++; + return -1; + } + + /* save scanner state for the current sourcefile */ + sourcefile->srclines = sourceline; + sourcefile->lexptr = lexptr; + sourcefile->lexend = lexend; + sourcefile->lexptr_begin = lexptr_begin; + sourcefile->lexeme = lexeme; + sourcefile->lasttok = lasttok; + + /* included file becomes the current source */ + sourcefile = s; + lexptr = NULL; + sourceline = 0; + source = NULL; + lasttok = 0; + lexeof = FALSE; + eof_warned = FALSE; + return 0; +} + +/* next_sourcefile --- read program from the next source in srcfiles */ + +static void +next_sourcefile() +{ + static int (*closefunc)(int fd) = NULL; + + if (closefunc == NULL) { + char *cp = getenv("AWKREADFUNC"); + + /* If necessary, one day, test value for different functions. */ + if (cp == NULL) + closefunc = close; + else + closefunc = one_line_close; + } + + assert(lexeof == TRUE); + lexeof = FALSE; + eof_warned = FALSE; + sourcefile->srclines = sourceline; /* total no of lines in current file */ + if (sourcefile->fd > INVALID_HANDLE) { + if (sourcefile->fd != fileno(stdin)) /* safety */ + (*closefunc)(sourcefile->fd); + sourcefile->fd = INVALID_HANDLE; + } + if (sourcefile->buf != NULL) { + efree(sourcefile->buf); + sourcefile->buf = NULL; + sourcefile->lexptr_begin = NULL; + } + + sourcefile = sourcefile->next; + if (sourcefile == srcfiles) + return; + + if (sourcefile->lexptr_begin != NULL) { + /* resume reading from already opened file (postponed to process '@include') */ + lexptr = sourcefile->lexptr; + lexend = sourcefile->lexend; + lasttok = sourcefile->lasttok; + lexptr_begin = sourcefile->lexptr_begin; + lexeme = sourcefile->lexeme; + sourceline = sourcefile->srclines; + source = sourcefile->src; + } else { + lexptr = NULL; + sourceline = 0; + source = NULL; + lasttok = 0; + } } /* get_src_buf --- read the next buffer of source program */ @@ -3939,11 +5017,11 @@ static void static char * get_src_buf() { - static int samefile = FALSE; - static int nextfile = 0; - static char *buf = NULL; - static size_t buflen = 0; - static int fd; + int n; + char *scan; + int newfile; + int savelen; + struct stat sbuf; /* * No argument prototype on readfunc on purpose, @@ -3951,105 +5029,94 @@ get_src_buf() * the types of arguments to read() aren't up to date. */ static ssize_t (*readfunc)() = 0; - static int (*closefunc)P((int fd)) = NULL; - - int n; - register char *scan; - int newfile; - struct stat sbuf; - int readcount = 0; - int l; - char *readloc; if (readfunc == NULL) { char *cp = getenv("AWKREADFUNC"); /* If necessary, one day, test value for different functions. */ - if (cp == NULL) { + if (cp == NULL) readfunc = read; - closefunc = close; - } else { + else readfunc = read_one_line; - closefunc = one_line_close; - } } -again: newfile = FALSE; - if (nextfile > numfiles) + if (sourcefile == srcfiles) return NULL; - if (srcfiles[nextfile].stype == CMDLINE) { - if ((l = strlen(srcfiles[nextfile].val)) == 0) { + if (sourcefile->stype == SRC_CMDLINE) { + if (sourcefile->bufsize == 0) { + sourcefile->bufsize = strlen(sourcefile->src); + lexptr = lexptr_begin = lexeme = sourcefile->src; + lexend = lexptr + sourcefile->bufsize; + sourceline = 1; + if (sourcefile->bufsize == 0) { + /* + * Yet Another Special case: + * gawk '' /path/name + * Sigh. + */ + static short warned = FALSE; + + if (do_lint && ! warned) { + warned = TRUE; + lintwarn(_("empty program text on command line")); + } + lexeof = TRUE; + } + } else if (sourcefile->buf == NULL && *(lexptr-1) != '\n') { /* - * Yet Another Special case: - * gawk '' /path/name - * Sigh. + * The following goop is to ensure that the source + * ends with a newline and that the entire current + * line is available for error messages. */ - static short warned = FALSE; + int offset; + char *buf; - if (do_lint && ! warned) { - warned = TRUE; - lintwarn(_("empty program text on command line")); - } - ++nextfile; - goto again; - } - if (srcfiles[nextfile].val[l-1] == '\n') { - /* has terminating newline, can use it directly */ - sourceline = 1; - source = NULL; - lexptr = lexptr_begin = srcfiles[nextfile].val; - /* fall through to pointer adjustment and return, below */ - } else { - /* copy it into static buffer */ - - /* make sure buffer exists and has room */ - if (buflen == 0) { - emalloc(buf, char *, l+2, "get_src_buf"); - buflen = l + 2; - } else if (l+2 > buflen) { - erealloc(buf, char *, l+2, "get_src_buf"); - buflen = l + 2; - } /* else - buffer has room, just use it */ - - /* copy in data */ - memcpy(buf, srcfiles[nextfile].val, l); - buf[l] = '\n'; - buf[++l] = '\0'; - - /* set vars and return */ - sourceline = 0; - source = NULL; - lexptr = lexptr_begin = buf; - } - lexend = lexptr + l; - nextfile++; /* for next entry to this routine */ + offset = lexptr - lexeme; + for (scan = lexeme; scan > lexptr_begin; scan--) + if (*scan == '\n') { + scan++; + break; + } + savelen = lexptr - scan; + emalloc(buf, char *, savelen + 1, "get_src_buf"); + memcpy(buf, scan, savelen); + thisline = buf; + lexptr = buf + savelen; + *lexptr = '\n'; + lexeme = lexptr - offset; + lexptr_begin = buf; + lexend = lexptr + 1; + sourcefile->buf = buf; + } else + lexeof = TRUE; return lexptr; } - if (! samefile) { - source = srcfiles[nextfile].val; - if (source == NULL) { /* read all the source files, all done */ - if (buf != NULL) { - free(buf); - buf = NULL; - } - buflen = 0; - return lexeme = lexptr = lexptr_begin = NULL; - } - fd = pathopen(source); + if (sourcefile->fd <= INVALID_HANDLE) { + int fd; + int l; + + source = sourcefile->src; + if (source == NULL) + return NULL; + fd = srcopen(sourcefile); if (fd <= INVALID_HANDLE) { char *in; /* suppress file name and line no. in error mesg */ in = source; source = NULL; - fatal(_("can't open source file `%s' for reading (%s)"), + error(_("can't open source file `%s' for reading (%s)"), in, strerror(errno)); + errcount++; + lexeof = TRUE; + return sourcefile->src; } - l = optimal_bufsize(fd, & sbuf); + + sourcefile->fd = fd; + l = optimal_bufsize(fd, &sbuf); /* * Make sure that something silly like * AWKBUFSIZE=8 make check @@ -4059,110 +5126,71 @@ again: if (l < A_DECENT_BUFFER_SIZE) l = A_DECENT_BUFFER_SIZE; #undef A_DECENT_BUFFER_SIZE - + sourcefile->bufsize = l; newfile = TRUE; - - /* make sure buffer exists and has room */ - if (buflen == 0) { - emalloc(buf, char *, l+2, "get_src_buf"); - buflen = l + 2; - } else if (l+2 > buflen) { - erealloc(buf, char *, l+2, "get_src_buf"); - buflen = l + 2; - } /* else - buffer has room, just use it */ - - readcount = l; - readloc = lexeme = lexptr = lexptr_begin = buf; - samefile = TRUE; + emalloc(sourcefile->buf, char *, sourcefile->bufsize, "get_src_buf"); + lexptr = lexptr_begin = lexeme = sourcefile->buf; + savelen = 0; sourceline = 1; + thisline = NULL; } else { /* - * In same file, ran off edge of buffer. - * Shift current line down to front, adjust - * pointers and fill in the rest of the buffer. + * Here, we retain the current source line in the beginning of the buffer. */ - - int lexeme_offset = lexeme - lexptr_begin; - int lexptr_offset = lexptr - lexptr_begin; - int lexend_offset = lexend - lexptr_begin; - - /* find beginning of current line */ - for (scan = lexeme; scan >= lexptr_begin; scan--) { + int offset; + for (scan = lexeme; scan > lexptr_begin; scan--) if (*scan == '\n') { scan++; break; } - } - /* - * This condition can be read as follows: IF - * 1. The beginning of the line is at the beginning of the - * buffer (no newline was found: scan <= buf) - * AND: - * 2. The start of valid lexical data is into the buffer - * (lexptr_begin > buf) - * OR: - * 3. We have scanned past the end of the last data read - * (lexptr == lexend) - * AND: - * 4. There's no room left in the buffer - * (lexptr_offset >= buflen - 2) - * - * If all that's true, grow the buffer to add more to - * the current line. - */ + savelen = lexptr - scan; + offset = lexptr - lexeme; - if (scan <= buf - && (lexptr_begin > buf - || (lexptr == lexend - && lexptr_offset >= buflen - 2))) { - /* have to grow the buffer */ - buflen *= 2; - erealloc(buf, char *, buflen, "get_src_buf"); - } else if (scan > buf) { - /* Line starts in middle of the buffer, shift things down. */ - memmove(buf, scan, lexend - scan); + if (savelen > 0) { /* - * make offsets relative to start of line, - * not start of buffer. + * Need to make sure we have room left for reading new text; + * grow the buffer (by doubling, an arbitrary choice), if the retained line + * takes up more than a certain percentage (50%, again an arbitrary figure) + * of the available space. */ - lexend_offset = lexend - scan; - lexeme_offset = lexeme - scan; - lexptr_offset = lexptr - scan; - } - /* adjust pointers */ - lexeme = buf + lexeme_offset; - lexptr = buf + lexptr_offset; - lexend = buf + lexend_offset; - lexptr_begin = buf; - readcount = buflen - (lexend - buf); - readloc = lexend; + if (savelen > sourcefile->bufsize / 2) { /* long line or token */ + sourcefile->bufsize *= 2; + erealloc(sourcefile->buf, char *, sourcefile->bufsize, "get_src_buf"); + scan = sourcefile->buf + (scan - lexptr_begin); + lexptr_begin = sourcefile->buf; + } + + thisline = lexptr_begin; + memmove(thisline, scan, savelen); + lexptr = thisline + savelen; + lexeme = lexptr - offset; + } else { + savelen = 0; + lexptr = lexeme = lexptr_begin; + thisline = NULL; + } } - /* add more data to buffer */ - n = (*readfunc)(fd, readloc, readcount); - if (n == -1) - fatal(_("can't read sourcefile `%s' (%s)"), - source, strerror(errno)); - if (n == 0) { - if (newfile) { + n = (*readfunc)(sourcefile->fd, lexptr, sourcefile->bufsize - savelen); + if (n == -1) { + error(_("can't read sourcefile `%s' (%s)"), + source, strerror(errno)); + errcount++; + lexeof = TRUE; + } else { + lexend = lexptr + n; + if (n == 0) { static short warned = FALSE; - - if (do_lint && ! warned) { + if (do_lint && newfile && ! warned){ warned = TRUE; lintwarn(_("source file `%s' is empty"), source); } + lexeof = TRUE; } - if (fd != fileno(stdin)) /* safety */ - (*closefunc)(fd); - samefile = FALSE; - nextfile++; - goto again; } - lexend = lexptr + n; - return lexptr; + return sourcefile->buf; } /* tokadd --- add a character to the token buffer */ @@ -4171,20 +5199,23 @@ again: /* tokexpand --- grow the token buffer */ -char * +static char * tokexpand() { - static int toksize = 60; + static int toksize; int tokoffset; - - tokoffset = tok - tokstart; - toksize *= 2; - if (tokstart != NULL) + + if (tokstart != NULL) { + tokoffset = tok - tokstart; + toksize *= 2; erealloc(tokstart, char *, toksize, "tokexpand"); - else + tok = tokstart + tokoffset; + } else { + toksize = 60; emalloc(tokstart, char *, toksize, "tokexpand"); + tok = tokstart; + } tokend = tokstart + toksize; - tok = tokstart + tokoffset; return tok; } @@ -4196,9 +5227,13 @@ static int nextc(void) { if (gawk_mb_cur_max > 1) { - if (!lexptr || lexptr >= lexend) { - if (! get_src_buf()) - return EOF; +again: + if (lexeof) + return END_FILE; + if (lexptr == NULL || lexptr >= lexend) { + if (get_src_buf()) + goto again; + return END_SRC; } /* Update the buffer index. */ @@ -4211,7 +5246,7 @@ nextc(void) int idx, work_ring_idx = cur_ring_idx; mbstate_t tmp_state; size_t mbclen; - + for (idx = 0 ; lexptr + idx < lexend ; idx++) { tmp_state = cur_mbstate; mbclen = mbrlen(lexptr, idx + 1, &tmp_state); @@ -4242,44 +5277,30 @@ nextc(void) } return (int) (unsigned char) *lexptr++; - } - else { - int c; - - if (lexptr && lexptr < lexend) - c = (int) (unsigned char) *lexptr++; - else if (get_src_buf()) - c = (int) (unsigned char) *lexptr++; - else - c = EOF; - - return c; + } else { + do { + if (lexeof) + return END_FILE; + if (lexptr && lexptr < lexend) + return ((int) (unsigned char) *lexptr++); + } while (get_src_buf()); + return END_SRC; } } #else /* MBS_SUPPORT */ -#if GAWKDEBUG int -nextc(void) +nextc() { - int c; - - if (lexptr && lexptr < lexend) - c = (int) (unsigned char) *lexptr++; - else if (get_src_buf()) - c = (int) (unsigned char) *lexptr++; - else - c = EOF; - - return c; + do { + if (lexeof) + return END_FILE; + if (lexptr && lexptr < lexend) + return ((int) (unsigned char) *lexptr++); + } while (get_src_buf()); + return END_SRC; } -#else -#define nextc() ((lexptr && lexptr < lexend) ? \ - ((int) (unsigned char) *lexptr++) : \ - (get_src_buf() ? ((int) (unsigned char) *lexptr++) : EOF) \ - ) -#endif #endif /* MBS_SUPPORT */ @@ -4293,7 +5314,7 @@ pushback(void) cur_ring_idx = (cur_ring_idx == 0)? RING_BUFFER_SIZE - 1 : cur_ring_idx - 1; #endif - (lexptr && lexptr > lexptr_begin ? lexptr-- : lexptr); + (! lexeof && lexptr && lexptr > lexptr_begin ? lexptr-- : lexptr); } @@ -4306,13 +5327,17 @@ allow_newline(void) for (;;) { c = nextc(); - if (c == EOF) + if (c == END_FILE) { + pushback(); break; + } if (c == '#') { - while ((c = nextc()) != '\n' && c != EOF) + while ((c = nextc()) != '\n' && c != END_FILE) continue; - if (c == EOF) + if (c == END_FILE) { + pushback(); break; + } } if (c == '\n') sourceline++; @@ -4328,30 +5353,44 @@ allow_newline(void) static int yylex(void) { - register int c; + int c; int seen_e = FALSE; /* These are for numbers */ int seen_point = FALSE; int esc_seen; /* for literal strings */ int mid; static int did_newline = FALSE; char *tokkey; - static int lasttok = 0; - static short eof_warned = FALSE; int inhex = FALSE; int intlstr = FALSE; - if (nextc() == EOF) { - if (lasttok != NEWLINE) { - lasttok = NEWLINE; - if (do_lint && ! eof_warned) { - lintwarn(_("source file does not end in newline")); - eof_warned = TRUE; - } - return NEWLINE; /* fake it */ - } - return 0; +#define GET_INSTRUCTION(op) bcalloc(op, 1, sourceline) + + /* NB: a newline at end does not start a source line. */ + +#define NEWLINE_EOF \ + (lasttok != NEWLINE ? \ + (pushback(), do_lint && ! eof_warned && \ + (lintwarn(_("source file does not end in newline")), \ + eof_warned = TRUE), sourceline++, NEWLINE) : \ + (sourceline--, eof_warned = FALSE, LEX_EOF)) + + + yylval = (INSTRUCTION *) NULL; + if (lasttok == SUBSCRIPT) { + lasttok = 0; + return SUBSCRIPT; } + + if (lasttok == LEX_EOF) /* error earlier in current source, must give up !! */ + return 0; + + c = nextc(); + if (c == END_SRC) + return 0; + if (c == END_FILE) + return lasttok = NEWLINE_EOF; pushback(); + #if defined OS2 || defined __EMX__ /* * added for OS/2's extproc feature of cmd.exe @@ -4362,6 +5401,7 @@ yylex(void) lexptr++; } #endif + lexeme = lexptr; thisline = NULL; if (want_regexp) { @@ -4405,7 +5445,8 @@ yylex(void) in_brack--; break; case '\\': - if ((c = nextc()) == EOF) { + if ((c = nextc()) == END_FILE) { + pushback(); yyerror(_("unterminated regexp ends with `\\' at end of file")); goto end_regexp; /* kludge */ } else if (c == '\n') { @@ -4421,8 +5462,8 @@ yylex(void) if (in_brack > 0) break; end_regexp: - tokadd('\0'); - yylval.sval = tokstart; + yylval = GET_INSTRUCTION(Op_token); + yylval->lextok = estrdup(tokstart, tok - tokstart); if (do_lint) { int peek = nextc(); @@ -4443,7 +5484,8 @@ end_regexp: pushback(); yyerror(_("unterminated regexp")); goto end_regexp; /* kludge */ - case EOF: + case END_FILE: + pushback(); yyerror(_("unterminated regexp at end of file")); goto end_regexp; /* kludge */ } @@ -4459,42 +5501,32 @@ retry: lexeme = lexptr ? lexptr - 1 : lexptr; thisline = NULL; tok = tokstart; - yylval.nodetypeval = Node_illegal; - - if (gawk_mb_cur_max == 1 || nextc_is_1stbyte) switch (c) { - case EOF: - if (lasttok != NEWLINE) { - lasttok = NEWLINE; - if (do_lint && ! eof_warned) { - lintwarn(_("source file does not end in newline")); - eof_warned = TRUE; - } - return NEWLINE; /* fake it */ - } + +#ifdef MBS_SUPPORT + if (gawk_mb_cur_max == 1 || nextc_is_1stbyte) +#endif + switch (c) { + case END_SRC: return 0; + case END_FILE: + return lasttok = NEWLINE_EOF; + case '\n': sourceline++; return lasttok = NEWLINE; case '#': /* it's a comment */ while ((c = nextc()) != '\n') { - if (c == EOF) { - if (lasttok != NEWLINE) { - lasttok = NEWLINE; - if (do_lint && ! eof_warned) { - lintwarn( - _("source file does not end in newline")); - eof_warned = TRUE; - } - return NEWLINE; /* fake it */ - } - return 0; - } + if (c == END_FILE) + return lasttok = NEWLINE_EOF; } sourceline++; return lasttok = NEWLINE; + case '@': + return lasttok = '@'; + case '\\': #ifdef RELAXED_CONTINUATION /* @@ -4516,23 +5548,27 @@ retry: _("use of `\\ #...' line continuation is not portable")); } while ((c = nextc()) != '\n') - if (c == EOF) + if (c == END_FILE) break; } pushback(); } #endif /* RELAXED_CONTINUATION */ - if (nextc() == '\n') { + c = nextc(); + if (c == '\r') /* allow MS-DOS files. bleah */ + c = nextc(); + if (c == '\n') { sourceline++; goto retry; } else { yyerror(_("backslash not last character on line")); - exit(EXIT_FAILURE); + return lasttok = LEX_EOF; } break; case ':': case '?': + yylval = GET_INSTRUCTION(Op_cond_exp); if (! do_posix) allow_newline(); return lasttok = c; @@ -4547,21 +5583,36 @@ retry: case '(': in_parens++; - /* FALL THROUGH */ + return lasttok = c; case '$': - case ';': + yylval = GET_INSTRUCTION(Op_field_spec); + return lasttok = c; case '{': + if (++in_braces == 1) + firstline = sourceline; + case ';': case ',': case '[': + return lasttok = c; case ']': - return lasttok = c; + c = nextc(); + pushback(); + if (c == '[') { + yylval = GET_INSTRUCTION(Op_sub_array); + lasttok = ']'; + } else { + yylval = GET_INSTRUCTION(Op_subscript); + lasttok = SUBSCRIPT; /* end of subscripts */ + } + return ']'; case '*': if ((c = nextc()) == '=') { - yylval.nodetypeval = Node_assign_times; + yylval = GET_INSTRUCTION(Op_assign_times); return lasttok = ASSIGNOP; } else if (do_posix) { pushback(); + yylval = GET_INSTRUCTION(Op_times); return lasttok = '*'; } else if (c == '*') { /* make ** and **= aliases for ^ and ^= */ @@ -4575,7 +5626,7 @@ retry: if (do_lint_old) warning(_("old awk does not support operator `**='")); } - yylval.nodetypeval = Node_assign_exp; + yylval = GET_INSTRUCTION(Op_assign_exp); return ASSIGNOP; } else { pushback(); @@ -4586,10 +5637,12 @@ retry: if (do_lint_old) warning(_("old awk does not support operator `**'")); } + yylval = GET_INSTRUCTION(Op_exp); return lasttok = '^'; } } pushback(); + yylval = GET_INSTRUCTION(Op_times); return lasttok = '*'; case '/': @@ -4598,14 +5651,16 @@ retry: return lasttok = SLASH_BEFORE_EQUAL; } pushback(); + yylval = GET_INSTRUCTION(Op_quotient); return lasttok = '/'; case '%': if (nextc() == '=') { - yylval.nodetypeval = Node_assign_mod; + yylval = GET_INSTRUCTION(Op_assign_mod); return lasttok = ASSIGNOP; } pushback(); + yylval = GET_INSTRUCTION(Op_mod); return lasttok = '%'; case '^': @@ -4617,7 +5672,7 @@ retry: did_warn_assgn = TRUE; warning(_("operator `^=' is not supported in old awk")); } - yylval.nodetypeval = Node_assign_exp; + yylval = GET_INSTRUCTION(Op_assign_exp); return lasttok = ASSIGNOP; } pushback(); @@ -4625,67 +5680,74 @@ retry: did_warn_op = TRUE; warning(_("operator `^' is not supported in old awk")); } + yylval = GET_INSTRUCTION(Op_exp); return lasttok = '^'; } case '+': if ((c = nextc()) == '=') { - yylval.nodetypeval = Node_assign_plus; + yylval = GET_INSTRUCTION(Op_assign_plus); return lasttok = ASSIGNOP; } - if (c == '+') + if (c == '+') { + yylval = GET_INSTRUCTION(Op_symbol); return lasttok = INCREMENT; + } pushback(); + yylval = GET_INSTRUCTION(Op_plus); return lasttok = '+'; case '!': if ((c = nextc()) == '=') { - yylval.nodetypeval = Node_notequal; + yylval = GET_INSTRUCTION(Op_notequal); return lasttok = RELOP; } if (c == '~') { - yylval.nodetypeval = Node_nomatch; + yylval = GET_INSTRUCTION(Op_nomatch); return lasttok = MATCHOP; } pushback(); + yylval = GET_INSTRUCTION(Op_symbol); return lasttok = '!'; case '<': if (nextc() == '=') { - yylval.nodetypeval = Node_leq; + yylval = GET_INSTRUCTION(Op_leq); return lasttok = RELOP; } - yylval.nodetypeval = Node_less; + yylval = GET_INSTRUCTION(Op_less); pushback(); return lasttok = '<'; case '=': if (nextc() == '=') { - yylval.nodetypeval = Node_equal; + yylval = GET_INSTRUCTION(Op_equal); return lasttok = RELOP; } - yylval.nodetypeval = Node_assign; + yylval = GET_INSTRUCTION(Op_assign); pushback(); return lasttok = ASSIGN; case '>': if ((c = nextc()) == '=') { - yylval.nodetypeval = Node_geq; + yylval = GET_INSTRUCTION(Op_geq); return lasttok = RELOP; } else if (c == '>') { - yylval.nodetypeval = Node_redirect_append; + yylval = GET_INSTRUCTION(Op_symbol); + yylval->redir_type = redirect_append; return lasttok = IO_OUT; } pushback(); if (in_print && in_parens == 0) { - yylval.nodetypeval = Node_redirect_output; + yylval = GET_INSTRUCTION(Op_symbol); + yylval->redir_type = redirect_output; return lasttok = IO_OUT; } - yylval.nodetypeval = Node_greater; + yylval = GET_INSTRUCTION(Op_greater); return lasttok = '>'; case '~': - yylval.nodetypeval = Node_match; + yylval = GET_INSTRUCTION(Op_match); return lasttok = MATCHOP; case '}': @@ -4695,6 +5757,8 @@ retry: */ if (did_newline) { did_newline = FALSE; + if (--in_braces == 0) + lastline = sourceline; return lasttok = c; } did_newline++; @@ -4708,7 +5772,7 @@ retry: if (c == '\n') { pushback(); yyerror(_("unterminated string")); - exit(EXIT_FAILURE); + return lasttok = LEX_EOF; } if ((gawk_mb_cur_max == 1 || nextc_is_1stbyte) && c == '\\') { @@ -4718,35 +5782,46 @@ retry: continue; } esc_seen = TRUE; - tokadd('\\'); + if (! want_source || c != '"') + tokadd('\\'); } - if (c == EOF) { + if (c == END_FILE) { pushback(); yyerror(_("unterminated string")); - exit(EXIT_FAILURE); + return lasttok = LEX_EOF; } tokadd(c); } - yylval.nodeval = make_str_node(tokstart, - tok - tokstart, esc_seen ? SCAN : 0); - yylval.nodeval->flags |= PERM; + yylval = GET_INSTRUCTION(Op_token); + if (want_source) { + yylval->lextok = estrdup(tokstart, tok - tokstart); + return lasttok = FILENAME; + } + + yylval->opcode = Op_push_i; + yylval->memory = make_str_node(tokstart, + tok - tokstart, esc_seen ? SCAN : 0); + yylval->memory->flags &= ~MALLOC; + yylval->memory->flags |= PERM; if (intlstr) { - yylval.nodeval->flags |= INTLSTR; + yylval->memory->flags |= INTLSTR; intlstr = FALSE; if (do_intl) - dumpintlstr(yylval.nodeval->stptr, - yylval.nodeval->stlen); - } + dumpintlstr(yylval->memory->stptr, yylval->memory->stlen); + } return lasttok = YSTRING; case '-': if ((c = nextc()) == '=') { - yylval.nodetypeval = Node_assign_minus; + yylval = GET_INSTRUCTION(Op_assign_minus); return lasttok = ASSIGNOP; } - if (c == '-') + if (c == '-') { + yylval = GET_INSTRUCTION(Op_symbol); return lasttok = DECREMENT; + } pushback(); + yylval = GET_INSTRUCTION(Op_minus); return lasttok = '-'; case '.': @@ -4856,13 +5931,10 @@ retry: break; c = nextc(); } - if (c != EOF) - pushback(); - else if (do_lint && ! eof_warned) { - lintwarn(_("source file does not end in newline")); - eof_warned = TRUE; - } + pushback(); + tokadd('\0'); + yylval = GET_INSTRUCTION(Op_push_i); if (! do_traditional && isnondecimal(tokstart, FALSE)) { if (do_lint) { if (isdigit(tokstart[1])) /* not an 'x' or 'X' */ @@ -4872,48 +5944,47 @@ retry: lintwarn("numeric constant `%.*s' treated as hexadecimal", (int) strlen(tokstart)-1, tokstart); } - yylval.nodeval = make_number(nondec2awknum(tokstart, strlen(tokstart))); + yylval->memory = mk_number(nondec2awknum(tokstart, strlen(tokstart)), + PERM|NUMCUR|NUMBER); } else - yylval.nodeval = make_number(atof(tokstart)); - yylval.nodeval->flags |= PERM; + yylval->memory = mk_number(atof(tokstart), PERM|NUMCUR|NUMBER); return lasttok = YNUMBER; case '&': if ((c = nextc()) == '&') { - yylval.nodetypeval = Node_and; + yylval = GET_INSTRUCTION(Op_and); allow_newline(); return lasttok = LEX_AND; } pushback(); + yylval = GET_INSTRUCTION(Op_symbol); return lasttok = '&'; case '|': if ((c = nextc()) == '|') { - yylval.nodetypeval = Node_or; + yylval = GET_INSTRUCTION(Op_or); allow_newline(); return lasttok = LEX_OR; } else if (! do_traditional && c == '&') { - yylval.nodetypeval = Node_redirect_twoway; + yylval = GET_INSTRUCTION(Op_symbol); + yylval->redir_type = redirect_twoway; return lasttok = (in_print && in_parens == 0 ? IO_OUT : IO_IN); } pushback(); if (in_print && in_parens == 0) { - yylval.nodetypeval = Node_redirect_pipe; + yylval = GET_INSTRUCTION(Op_symbol); + yylval->redir_type = redirect_pipe; return lasttok = IO_OUT; } else { - yylval.nodetypeval = Node_redirect_pipein; + yylval = GET_INSTRUCTION(Op_symbol); + yylval->redir_type = redirect_pipein; return lasttok = IO_IN; } - - case '@': /* indirect function call */ - if (do_posix || do_traditional) - break; - return lasttok = c; } if (c != '_' && ! isalpha(c)) { yyerror(_("invalid char '%c' in expression"), c); - exit(EXIT_FAILURE); + return lasttok = LEX_EOF; } /* @@ -4941,23 +6012,21 @@ retry: /* it's some type of name-type-thing. Find its length. */ tok = tokstart; - while (is_identchar(c)) { + while (c != END_FILE && is_identchar(c)) { tokadd(c); c = nextc(); } tokadd('\0'); - emalloc(tokkey, char *, tok - tokstart, "yylex"); - memcpy(tokkey, tokstart, tok - tokstart); - if (c != EOF) - pushback(); - else if (do_lint && ! eof_warned) { - lintwarn(_("source file does not end in newline")); - eof_warned = TRUE; - } + pushback(); /* See if it is a special token. */ - if ((mid = check_special(tokstart)) >= 0) { + int class = tokentab[mid].class; + + if ((class == LEX_INCLUDE || class == LEX_EVAL) + && lasttok != '@') + goto out; + if (do_lint) { if (tokentab[mid].flags & GAWKX) lintwarn(_("`%s' is a gawk extension"), @@ -4972,26 +6041,64 @@ retry: if (do_lint_old && (tokentab[mid].flags & NOT_OLD)) warning(_("`%s' is not supported in old awk"), tokentab[mid].operator); + if (tokentab[mid].flags & BREAK) + break_allowed++; + if (tokentab[mid].flags & CONTINUE) + continue_allowed++; if ((do_traditional && (tokentab[mid].flags & GAWKX)) || (do_posix && (tokentab[mid].flags & NOT_POSIX))) - ; - else { - if (tokentab[mid].class == LEX_BUILTIN - || tokentab[mid].class == LEX_LENGTH) - yylval.lval = mid; - else - yylval.nodetypeval = tokentab[mid].value; - free(tokkey); - return lasttok = tokentab[mid].class; + goto out; + + switch (class) { + case LEX_INCLUDE: + want_source = TRUE; + break; + case LEX_EVAL: + if (get_context()->level == 0) + goto out; + emalloc(tokkey, char *, tok - tokstart + 1, "yylex"); + tokkey[0] = '@'; + memcpy(tokkey + 1, tokstart, tok - tokstart); + yylval = GET_INSTRUCTION(Op_token); + yylval->lextok = tokkey; + break; + + case LEX_FUNCTION: + case LEX_BEGIN: + case LEX_END: + case LEX_BEGINFILE: + case LEX_ENDFILE: + yylval = bcalloc(tokentab[mid].value, 3, sourceline); + break; + + case LEX_WHILE: + case LEX_DO: + case LEX_FOR: + case LEX_SWITCH: + yylval = bcalloc(tokentab[mid].value, + !!do_profiling + 1, sourceline); + break; + + default: + yylval = GET_INSTRUCTION(tokentab[mid].value); + if (class == LEX_BUILTIN || class == LEX_LENGTH) + yylval->builtin_idx = mid; + break; } + return lasttok = class; } - - yylval.sval = tokkey; - if (*lexptr == '(') +out: + tokkey = estrdup(tokstart, tok - tokstart); + if (*lexptr == '(') { + yylval = bcalloc(Op_token, 2, sourceline); + yylval->lextok = tokkey; return lasttok = FUNC_CALL; - else { + } else { static short goto_warned = FALSE; + yylval = GET_INSTRUCTION(Op_token); + yylval->lextok = tokkey; + #define SMART_ALECK 1 if (SMART_ALECK && do_lint && ! goto_warned && strcasecmp(tokkey, "goto") == 0) { @@ -5000,147 +6107,215 @@ retry: } return lasttok = NAME; } -} - -/* node_common --- common code for allocating a new node */ -static NODE * -node_common(NODETYPE op) -{ - register NODE *r; - - getnode(r); - r->type = op; - r->flags = MALLOC; - /* if lookahead is a NL, lineno is 1 too high */ - if (lexeme && lexeme >= lexptr_begin && *lexeme == '\n') - r->source_line = sourceline - 1; - else - r->source_line = sourceline; - r->source_file = source; - return r; +#undef GET_INSTRUCTION +#undef NEWLINE_EOF } -/* node --- allocates a node with defined lnode and rnode. */ +/* mk_symbol --- allocates a symbol for the symbol table. */ NODE * -node(NODE *left, NODETYPE op, NODE *right) +mk_symbol(NODETYPE type, NODE *value) { - register NODE *r; + NODE *r; - r = node_common(op); - r->lnode = left; - r->rnode = right; + getnode(r); + r->type = type; + r->flags = MALLOC; + r->lnode = value; + r->rnode = NULL; + r->var_assign = (Func_ptr) 0; return r; } -/* snode --- allocate a node with defined subnode and builtin for builtin - functions. Checks for arg. count and supplies defaults where - possible. */ +/* snode --- instructions for builtin functions. Checks for arg. count + and supplies defaults where possible. */ -static NODE * -snode(NODE *subn, NODETYPE op, int idx) +static INSTRUCTION * +snode(INSTRUCTION *subn, INSTRUCTION *r) { - register NODE *r; - register NODE *n; + INSTRUCTION *arg; + INSTRUCTION *ip; + NODE *n; int nexp = 0; int args_allowed; + int idx = r->builtin_idx; + + if (subn != NULL) { + INSTRUCTION *tp; + for (tp = subn->nexti; tp; tp = tp->nexti) { + /* assert(tp->opcode == Op_list); */ + tp = tp->lasti; + nexp++; + } + assert(nexp > 0); + } - r = node_common(op); - - /* traverse expression list to see how many args. given */ - for (n = subn; n != NULL; n = n->rnode) { - nexp++; - if (nexp > 5) - break; - } + r->builtin = tokentab[idx].ptr; /* check against how many args. are allowed for this builtin */ args_allowed = tokentab[idx].flags & ARGS; - if (args_allowed && (args_allowed & A(nexp)) == 0) - fatal(_("%d is invalid as number of arguments for %s"), + if (args_allowed && (args_allowed & A(nexp)) == 0) { + yyerror(_("%d is invalid as number of arguments for %s"), nexp, tokentab[idx].operator); - - r->builtin = tokentab[idx].ptr; + return NULL; + } /* special case processing for a few builtins */ - if (nexp == 0 && r->builtin == do_length) { - subn = node(node(make_number(0.0), Node_field_spec, (NODE *) NULL), - Node_expression_list, - (NODE *) NULL); + if (r->builtin == do_length) { + if (nexp == 0) { + INSTRUCTION *list; /* no args. Use $0 */ + + r->expr_count = 1; + list = list_create(r); + (void) list_prepend(list, instruction(Op_field_spec)); + (void) list_prepend(list, instruction(Op_push_i)); + list->nexti->memory = mk_number((AWKNUM) 0.0, (PERM|NUMCUR|NUMBER)); + return list; + } } else if (r->builtin == do_match) { static short warned = FALSE; - if (subn->rnode->lnode->type != Node_regex) - subn->rnode->lnode = mk_rexp(subn->rnode->lnode); + arg = subn->nexti->lasti->nexti; /* 2nd arg list */ + (void) mk_rexp(arg); - if (subn->rnode->rnode != NULL) { /* 3rd argument there */ + if (nexp == 3) { /* 3rd argument there */ if (do_lint && ! warned) { warned = TRUE; lintwarn(_("match: third argument is a gawk extension")); } - if (do_traditional) - fatal(_("match: third argument is a gawk extension")); + if (do_traditional) { + yyerror(_("match: third argument is a gawk extension")); + return NULL; + } + + arg = arg->lasti->nexti; /* third arg list */ + ip = arg->lasti; + if (/*ip == arg->nexti && */ ip->opcode == Op_push) + ip->opcode = Op_push_array; } } else if (r->builtin == do_sub || r->builtin == do_gsub) { - if (subn->lnode->type != Node_regex) - subn->lnode = mk_rexp(subn->lnode); - if (nexp == 2) - append_right(subn, node(node(make_number(0.0), - Node_field_spec, - (NODE *) NULL), - Node_expression_list, - (NODE *) NULL)); - else if (subn->rnode->rnode->lnode->type == Node_val) { + int literal = FALSE; + + arg = subn->nexti; /* first arg list */ + (void) mk_rexp(arg); + + arg = arg->lasti->nexti; /* 2nd arg list */ + if (nexp == 2) { + INSTRUCTION *expr; + expr = list_create(instruction(Op_push_i)); + expr->nexti->memory = mk_number((AWKNUM) 0.0, (PERM|NUMCUR|NUMBER)); + (void) mk_expression_list(subn, + list_append(expr, instruction(Op_field_spec))); + } + + arg = arg->lasti->nexti; /* third arg list */ + ip = arg->lasti; + if (ip->opcode == Op_push_i) { if (do_lint) lintwarn(_("%s: string literal as last arg of substitute has no effect"), (r->builtin == do_sub) ? "sub" : "gsub"); - } else if (! isassignable(subn->rnode->rnode->lnode)) { - yyerror(_("%s third parameter is not a changeable object"), - (r->builtin == do_sub) ? "sub" : "gsub"); + literal = TRUE; + } else { + if (make_assignable(ip) == NULL) + yyerror(_("%s third parameter is not a changeable object"), + (r->builtin == do_sub) ? "sub" : "gsub"); + else + ip->do_reference = TRUE; } + + /* kludge: This is one of the few cases + * when we need to know the type of item on stack. + * In case of string literal as the last argument, + * pass 4 as # of args (See sub_common code in builtin.c). + * Other cases like length(array or scalar) seem + * to work out ok. + */ + + r->expr_count = count_expressions(&subn, FALSE) + !!literal; + ip = subn->lasti; + + (void) list_append(subn, r); + + /* add after_assign bytecode(s) */ + if (ip->opcode == Op_push_lhs && ip->memory->type == Node_var && ip->memory->var_assign) { + (void) list_append(subn, instruction(Op_var_assign)); + subn->lasti->memory = ip->memory; + } else if (ip->opcode == Op_field_spec_lhs) { + (void) list_append(subn, instruction(Op_field_assign)); + subn->lasti->field_assign = (Func_ptr) 0; + ip->target_assign = subn->lasti; + } + return subn; } else if (r->builtin == do_gensub) { - if (subn->lnode->type != Node_regex) - subn->lnode = mk_rexp(subn->lnode); - if (nexp == 3) - append_right(subn, node(node(make_number(0.0), - Node_field_spec, - (NODE *) NULL), - Node_expression_list, - (NODE *) NULL)); + if (nexp == 3) { + arg = subn->nexti->lasti->nexti->lasti->nexti; /* 3rd arg list */ + ip = instruction(Op_push_i); + ip->memory = mk_number((AWKNUM) 0.0, (PERM|NUMCUR|NUMBER)); + (void) mk_expression_list(subn, + list_append(list_create(ip), + instruction(Op_field_spec))); + } + arg = subn->nexti; /* first arg list */ + (void) mk_rexp(arg); } else if (r->builtin == do_split) { + arg = subn->nexti->lasti->nexti; /* 2nd arg list */ + ip = arg->lasti; + if (ip->opcode == Op_push) + ip->opcode = Op_push_array; + if (nexp == 2) { + INSTRUCTION *expr; + expr = list_create(instruction(Op_push)); + expr->nexti->memory = FS_node; + (void) mk_expression_list(subn, expr); + } + arg = arg->lasti->nexti; + n = mk_rexp(arg); if (nexp == 2) - append_right(subn, - node(FS_node, Node_expression_list, (NODE *) NULL)); - n = subn->rnode->rnode->lnode; - if (n->type != Node_regex) - subn->rnode->rnode->lnode = mk_rexp(n); - if (nexp == 2) - subn->rnode->rnode->lnode->re_flags |= FS_DFLT; + n->re_flags |= FS_DFLT; + if (nexp == 4) { + arg = arg->lasti->nexti; + ip = arg->lasti; + if (ip->opcode == Op_push) + ip->opcode = Op_push_array; + } } else if (r->builtin == do_patsplit) { - if (nexp == 2) - append_right(subn, - node(FPAT_node, Node_expression_list, (NODE *) NULL)); - n = subn->rnode->rnode->lnode; - if (n->type != Node_regex) - subn->rnode->rnode->lnode = mk_rexp(n); + arg = subn->nexti->lasti->nexti; /* 2nd arg list */ + ip = arg->lasti; + if (ip->opcode == Op_push) + ip->opcode = Op_push_array; + if (nexp == 2) { + INSTRUCTION *expr; + expr = list_create(instruction(Op_push)); + expr->nexti->memory = FPAT_node; + (void) mk_expression_list(subn, expr); + } + arg = arg->lasti->nexti; + n = mk_rexp(arg); + if (nexp == 4) { + arg = arg->lasti->nexti; + ip = arg->lasti; + if (ip->opcode == Op_push) + ip->opcode = Op_push_array; + } } else if (r->builtin == do_close) { static short warned = FALSE; - - if ( nexp == 2) { - if (do_lint && nexp == 2 && ! warned) { + if (nexp == 2) { + if (do_lint && ! warned) { warned = TRUE; lintwarn(_("close: second argument is a gawk extension")); } - if (do_traditional) - fatal(_("close: second argument is a gawk extension")); + if (do_traditional) { + yyerror(_("close: second argument is a gawk extension")); + return NULL; + } } } else if (do_intl /* --gen-po */ && r->builtin == do_dcgettext /* dcgettext(...) */ - && subn->lnode->type == Node_val /* 1st arg is constant */ - && (subn->lnode->flags & STRCUR) != 0) { /* it's a string constant */ + && subn->nexti->lasti->opcode == Op_push_i /* 1st arg is constant */ + && (subn->nexti->lasti->memory->flags & STRCUR) != 0) { /* it's a string constant */ /* ala xgettext, dcgettext("some string" ...) dumps the string */ - NODE *str = subn->lnode; + NODE *str = subn->nexti->lasti->memory; if ((str->flags & INTLSTR) != 0) warning(_("use of dcgettext(_\"...\") is incorrect: remove leading underscore")); @@ -5149,45 +6324,65 @@ snode(NODE *subn, NODETYPE op, int idx) dumpintlstr(str->stptr, str->stlen); } else if (do_intl /* --gen-po */ && r->builtin == do_dcngettext /* dcngettext(...) */ - && subn->lnode->type == Node_val /* 1st arg is constant */ - && (subn->lnode->flags & STRCUR) != 0 /* it's a string constant */ - && subn->rnode->lnode->type == Node_val /* 2nd arg is constant too */ - && (subn->rnode->lnode->flags & STRCUR) != 0) { /* it's a string constant */ + && subn->nexti->lasti->opcode == Op_push_i /* 1st arg is constant */ + && (subn->nexti->lasti->memory->flags & STRCUR) != 0 /* it's a string constant */ + && subn->nexti->lasti->nexti->lasti->opcode == Op_push_i /* 2nd arg is constant too */ + && (subn->nexti->lasti->nexti->lasti->memory->flags & STRCUR) != 0) { /* it's a string constant */ /* ala xgettext, dcngettext("some string", "some plural" ...) dumps the string */ - NODE *str1 = subn->lnode; - NODE *str2 = subn->rnode->lnode; + NODE *str1 = subn->nexti->lasti->memory; + NODE *str2 = subn->nexti->lasti->nexti->lasti->memory; if (((str1->flags | str2->flags) & INTLSTR) != 0) warning(_("use of dcngettext(_\"...\") is incorrect: remove leading underscore")); else dumpintlstr2(str1->stptr, str1->stlen, str2->stptr, str2->stlen); + } else if (r->builtin == do_asort || r->builtin == do_asorti) { + arg = subn->nexti; /* 1st arg list */ + ip = arg->lasti; + if (/* ip == arg->nexti && */ ip->opcode == Op_push) + ip->opcode = Op_push_array; + if (nexp == 2) { + arg = ip->nexti; + ip = arg->lasti; + if (/* ip == arg->nexti && */ ip->opcode == Op_push) + ip->opcode = Op_push_array; + } } +#ifdef ARRAYDEBUG + else if (r->builtin == do_adump) { + ip = subn->nexti->lasti; + if (ip->opcode == Op_push) + ip->opcode = Op_push_array; + } +#endif - r->subnode = subn; - if (r->builtin == do_sprintf) { - count_args(r); - if (r->lnode != NULL) /* r->lnode set from subn. guard against syntax errors & check it's valid */ - r->lnode->printf_count = r->printf_count; /* hack */ + if (subn != NULL) { + r->expr_count = count_expressions(&subn, FALSE); + return list_append(subn, r); } - return r; + + r->expr_count = 0; + return list_create(r); } -/* make_for_loop --- build a for loop */ +/* append_param --- append PNAME to the list of parameters + * for the current function. + */ -static NODE * -make_for_loop(NODE *init, NODE *cond, NODE *incr) +static void +append_param(char *pname) { - register FOR_LOOP_HEADER *r; - NODE *n; + static NODE *savetail = NULL; + NODE *p; - emalloc(r, FOR_LOOP_HEADER *, sizeof(FOR_LOOP_HEADER), "make_for_loop"); - getnode(n); - n->type = Node_illegal; - r->init = init; - r->cond = cond; - r->incr = incr; - n->sub.nodep.r.hd = r; - return n; + p = make_param(pname); + if (func_params == NULL) { + func_params = p; + savetail = p; + } else if (savetail != NULL) { + savetail->rnode = p; + savetail = p; + } } /* dup_parms --- return TRUE if there are duplicate parameters */ @@ -5195,7 +6390,7 @@ make_for_loop(NODE *init, NODE *cond, NODE *incr) static int dup_parms(NODE *func) { - register NODE *np; + NODE *np; const char *fname, **names; int count, i, j, dups; NODE *params; @@ -5218,7 +6413,7 @@ dup_parms(NODE *func) i = 0; for (np = params; np != NULL; np = np->rnode) { if (np->param == NULL) { /* error earlier, give up, go home */ - free(names); + efree(names); return TRUE; } names[i++] = np->param; @@ -5231,36 +6426,45 @@ dup_parms(NODE *func) dups++; error( _("function `%s': parameter #%d, `%s', duplicates parameter #%d"), - fname, i+1, names[j], j+1); + fname, i + 1, names[j], j+1); } } } - free(names); + efree(names); return (dups > 0 ? TRUE : FALSE); } /* parms_shadow --- check if parameters shadow globals */ static int -parms_shadow(const char *fname, NODE *func) +parms_shadow(INSTRUCTION *pc, int *shadow) { - int count, i; + int pcount, i; int ret = FALSE; + NODE *func; + char *fname; + func = pc->func_body; + fname = func->lnode->param; + +#if 0 /* can't happen, already exited if error ? */ if (fname == NULL || func == NULL) /* error earlier */ return FALSE; +#endif - count = func->lnode->param_cnt; + pcount = func->lnode->param_cnt; - if (count == 0) /* no args, no problem */ - return FALSE; + if (pcount == 0) /* no args, no problem */ + return 0; + source = pc->source_file; + sourceline = pc->source_line; /* * Use warning() and not lintwarn() so that can warn * about all shadowed parameters. */ - for (i = 0; i < count; i++) { + for (i = 0; i < pcount; i++) { if (lookup(func->parmlist[i]) != NULL) { warning( _("function `%s': parameter `%s' shadows global variable"), @@ -5269,21 +6473,27 @@ parms_shadow(const char *fname, NODE *func) } } - return ret; + *shadow |= ret; + return 0; } + /* - * install: + * install_symbol: * Install a name in the symbol table, even if it is already there. * Caller must check against redefinition if that is desired. */ + NODE * -install(char *name, NODE *value) +install_symbol(char *name, NODE *value) { - register NODE *hp; - register size_t len; - register int bucket; + NODE *hp; + size_t len; + int bucket; + + if (install_func) + (*install_func)(name); var_count++; len = strlen(name); @@ -5299,27 +6509,26 @@ install(char *name, NODE *value) return hp->hvalue; } -/* lookup --- find the most recent hash node for name installed by install */ +/* lookup --- find the most recent hash node for name installed by install_symbol */ NODE * lookup(const char *name) { - register NODE *bucket; - register size_t len; + NODE *bucket; + size_t len; len = strlen(name); for (bucket = variables[hash(name, len, (unsigned long) HASHSIZE, NULL)]; bucket != NULL; bucket = bucket->hnext) if (bucket->hlength == len && STREQN(bucket->hname, name, len)) return bucket->hvalue; - return NULL; } -/* var_comp --- compare two variable names */ +/* sym_comp --- compare two symbol (variable or function) names */ static int -var_comp(const void *v1, const void *v2) +sym_comp(const void *v1, const void *v2) { const NODE *const *npp1, *const *npp2; const NODE *n1, *n2; @@ -5340,77 +6549,90 @@ var_comp(const void *v1, const void *v2) /* valinfo --- dump var info */ -static void -valinfo(NODE *n, FILE *fp) +void +valinfo(NODE *n, int (*print_func)(FILE *, const char *, ...), FILE *fp) { - if (n->flags & STRING) { - fprintf(fp, "string ("); - pp_string_fp(fp, n->stptr, n->stlen, '"', FALSE); - fprintf(fp, ")\n"); + if (n == Nnull_string) + print_func(fp, "uninitialized scalar\n"); + else if (n->flags & STRING) { + pp_string_fp(print_func, fp, n->stptr, n->stlen, '"', FALSE); + print_func(fp, "\n"); } else if (n->flags & NUMBER) - fprintf(fp, "number (%.17g)\n", n->numbr); + print_func(fp, "%.17g\n", n->numbr); else if (n->flags & STRCUR) { - fprintf(fp, "string value ("); - pp_string_fp(fp, n->stptr, n->stlen, '"', FALSE); - fprintf(fp, ")\n"); + pp_string_fp(print_func, fp, n->stptr, n->stlen, '"', FALSE); + print_func(fp, "\n"); } else if (n->flags & NUMCUR) - fprintf(fp, "number value (%.17g)\n", n->numbr); + print_func(fp, "%.17g\n", n->numbr); else - fprintf(fp, "?? flags %s\n", flags2str(n->flags)); + print_func(fp, "?? flags %s\n", flags2str(n->flags)); } +/* get_varlist --- list of global variables */ -/* dump_vars --- dump the symbol table */ - -void -dump_vars(const char *fname) +NODE ** +get_varlist() { int i, j; NODE **table; NODE *p; - FILE *fp; - - emalloc(table, NODE **, var_count * sizeof(NODE *), "dump_vars"); - - if (fname == NULL) - fp = stderr; - else if ((fp = fopen(fname, "w")) == NULL) { - warning(_("could not open `%s' for writing (%s)"), fname, strerror(errno)); - warning(_("sending profile to standard error")); - fp = stderr; - } + emalloc(table, NODE **, (var_count + 1) * sizeof(NODE *), "get_varlist"); + update_global_values(); for (i = j = 0; i < HASHSIZE; i++) for (p = variables[i]; p != NULL; p = p->hnext) table[j++] = p; - assert(j == var_count); /* Shazzam! */ - qsort(table, j, sizeof(NODE *), var_comp); + qsort(table, j, sizeof(NODE *), sym_comp); + + table[j] = NULL; + return table; +} - for (i = 0; i < j; i++) { - p = table[i]; +/* print_vars --- print names and values of global variables */ + +void +print_vars(int (*print_func)(FILE *, const char *, ...), FILE *fp) +{ + int i; + NODE **table; + NODE *p; + + table = get_varlist(); + for (i = 0; (p = table[i]) != NULL; i++) { if (p->hvalue->type == Node_func) continue; - fprintf(fp, "%.*s: ", (int) p->hlength, p->hname); + print_func(fp, "%.*s: ", (int) p->hlength, p->hname); if (p->hvalue->type == Node_var_array) - fprintf(fp, "array, %ld elements\n", p->hvalue->table_size); + print_func(fp, "array, %ld elements\n", p->hvalue->table_size); else if (p->hvalue->type == Node_var_new) - fprintf(fp, "unused variable\n"); + print_func(fp, "untyped variable\n"); else if (p->hvalue->type == Node_var) - valinfo(p->hvalue->var_value, fp); - else { - NODE **lhs = get_lhs(p->hvalue, NULL, FALSE); + valinfo(p->hvalue->var_value, print_func, fp); + } + efree(table); +} - valinfo(*lhs, fp); - } +/* dump_vars --- dump the symbol table */ + +void +dump_vars(const char *fname) +{ + FILE *fp; + + if (fname == NULL) + fp = stderr; + else if ((fp = fopen(fname, "w")) == NULL) { + warning(_("could not open `%s' for writing (%s)"), fname, strerror(errno)); + warning(_("sending profile to standard error")); + fp = stderr; } + print_vars(fprintf, fp); if (fp != stderr && fclose(fp) != 0) warning(_("%s: close failed (%s)"), fname, strerror(errno)); - - free(table); } /* release_all_vars --- free all variable memory */ @@ -5420,8 +6642,8 @@ release_all_vars() { int i; NODE *p, *next; - - for (i = 0; i < HASHSIZE; i++) + + for (i = 0; i < HASHSIZE; i++) { for (p = variables[i]; p != NULL; p = next) { next = p->hnext; @@ -5429,40 +6651,14 @@ release_all_vars() continue; else if (p->hvalue->type == Node_var_array) assoc_clear(p->hvalue); - else if (p->hvalue->type != Node_var_new) { - NODE **lhs = get_lhs(p->hvalue, NULL, FALSE); - - unref(*lhs); - } - unref(p); - } -} - -/* finfo --- for use in comparison and sorting of function names */ - -struct finfo { - const char *name; - size_t nlen; - NODE *func; -}; - -/* fcompare --- comparison function for qsort */ - -static int -fcompare(const void *p1, const void *p2) -{ - const struct finfo *f1, *f2; - int minlen; - - f1 = (const struct finfo *) p1; - f2 = (const struct finfo *) p2; + else if (p->hvalue->type != Node_var_new) + unref(p->hvalue->var_value); - if (f1->nlen > f2->nlen) - minlen = f2->nlen; - else - minlen = f1->nlen; - - return strncmp(f1->name, f2->name, minlen); + efree(p->hname); + freenode(p->hvalue); + freenode(p); + } + } } /* dump_funcs --- print all functions */ @@ -5470,48 +6666,10 @@ fcompare(const void *p1, const void *p2) void dump_funcs() { - int i, j; - NODE *p; - struct finfo *tab = NULL; - - /* - * Walk through symbol table countng functions. - * Could be more than func_count if there are - * extension functions. - */ - for (i = j = 0; i < HASHSIZE; i++) { - for (p = variables[i]; p != NULL; p = p->hnext) { - if (p->hvalue->type == Node_func) { - j++; - } - } - } - - if (j == 0) + if (func_count <= 0) return; - emalloc(tab, struct finfo *, j * sizeof(struct finfo), "dump_funcs"); - - /* now walk again, copying info */ - for (i = j = 0; i < HASHSIZE; i++) { - for (p = variables[i]; p != NULL; p = p->hnext) { - if (p->hvalue->type == Node_func) { - tab[j].name = p->hname; - tab[j].nlen = p->hlength; - tab[j].func = p->hvalue; - j++; - } - } - } - - - /* Shazzam! */ - qsort(tab, j, sizeof(struct finfo), fcompare); - - for (i = 0; i < j; i++) - pp_func(tab[i].name, tab[i].nlen, tab[i].func); - - free(tab); + (void) foreach_func((int (*)(INSTRUCTION *, void *)) pp_func, TRUE, (void *) 0); } /* shadow_funcs --- check all functions for parameters that shadow globals */ @@ -5519,40 +6677,16 @@ dump_funcs() void shadow_funcs() { - int i, j; - NODE *p; - struct finfo *tab; static int calls = 0; int shadow = FALSE; - if (func_count == 0) + if (func_count <= 0) return; if (calls++ != 0) fatal(_("shadow_funcs() called twice!")); - emalloc(tab, struct finfo *, func_count * sizeof(struct finfo), "shadow_funcs"); - - for (i = j = 0; i < HASHSIZE; i++) { - for (p = variables[i]; p != NULL; p = p->hnext) { - if (p->hvalue->type == Node_func) { - tab[j].name = p->hname; - tab[j].nlen = p->hlength; - tab[j].func = p->hvalue; - j++; - } - } - } - - assert(j == func_count); - - /* Shazzam! */ - qsort(tab, func_count, sizeof(struct finfo), fcompare); - - for (i = 0; i < j; i++) - shadow |= parms_shadow(tab[i].name, tab[i].func); - - free(tab); + (void) foreach_func((int (*)(INSTRUCTION *, void *)) parms_shadow, TRUE, &shadow); /* End with fatal if the user requested it. */ if (shadow && lintfunc != warning) @@ -5560,54 +6694,6 @@ shadow_funcs() } /* - * append_right: - * Add new to the rightmost branch of LIST. This uses n^2 time, so we make - * a simple attempt at optimizing it. - */ - -static NODE * -append_right(NODE *list, NODE *new) -{ - register NODE *oldlist; - static NODE *savefront = NULL, *savetail = NULL; - - if (list == NULL || new == NULL) - return list; - - oldlist = list; - if (savefront == oldlist) - list = savetail; /* Be careful: maybe list->rnode != NULL */ - else - savefront = oldlist; - - while (list->rnode != NULL) - list = list->rnode; - savetail = list->rnode = new; - return oldlist; -} - -/* - * append_pattern: - * A wrapper around append_right, used for rule lists. - */ -static inline NODE * -append_pattern(NODE **list, NODE *patt) -{ - NODE *n = node(patt, Node_rule_node, (NODE *) NULL); - - if (*list == NULL) - *list = n; - else { - NODE *n1 = node(n, Node_rule_list, (NODE *) NULL); - if ((*list)->type != Node_rule_list) - *list = node(*list, Node_rule_list, n1); - else - (void) append_right(*list, n1); - } - return n; -} - -/* * func_install: * check if name is already installed; if so, it had better have Null value, * in which case def is added as the value. Otherwise, install name with def @@ -5618,92 +6704,117 @@ append_pattern(NODE **list, NODE *patt) * of each function parameter during a function call. See eval.c. */ -static void -func_install(NODE *params, NODE *def) +static int +func_install(INSTRUCTION *func, INSTRUCTION *def) { - NODE *r, *n, *thisfunc; - char **pnames, *names, *sp; - size_t pcount = 0, space = 0; + NODE *params; + NODE *r, *n, *thisfunc, *hp; + char **pnames = NULL; + char *fname; + int pcount = 0; int i; + params = func_params; + /* check for function foo(foo) { ... }. bleah. */ for (n = params->rnode; n != NULL; n = n->rnode) { - if (strcmp(n->param, params->param) == 0) - fatal(_("function `%s': can't use function name as parameter name"), - params->param); - else if (is_std_var(n->param)) - fatal(_("function `%s': can't use special variable `%s' as a function parameter"), + if (strcmp(n->param, params->param) == 0) { + error(_("function `%s': can't use function name as parameter name"), + params->param); + errcount++; + return -1; + } else if (is_std_var(n->param)) { + error(_("function `%s': can't use special variable `%s' as a function parameter"), params->param, n->param); + errcount++; + return -1; + } } - thisfunc = NULL; /* turn off warnings */ + thisfunc = NULL; /* turn off warnings */ - /* symbol table managment */ - pop_var(params, FALSE); - r = lookup(params->param); + fname = params->param; + /* symbol table management */ + hp = remove_symbol(params->param); /* remove function name out of symbol table */ + if (hp != NULL) + freenode(hp); + r = lookup(fname); if (r != NULL) { - fatal(_("function name `%s' previously defined"), params->param); - } else if (params->param == builtin_func) /* not a valid function name */ + error(_("function name `%s' previously defined"), fname); + errcount++; + return -1; + } else if (fname == builtin_func) /* not a valid function name */ goto remove_params; + /* add an implicit return at end; + * also used by 'return' command in debugger + */ + + (void) list_append(def, instruction(Op_push_i)); + def->lasti->memory = Nnull_string; + (void) list_append(def, instruction(Op_K_return)); + + if (do_profiling) + (void) list_prepend(def, instruction(Op_exec_count)); + + /* func->opcode is Op_func */ + (func + 1)->firsti = def->nexti; + (func + 1)->lasti = def->lasti; + (func + 2)->first_line = func->source_line; + (func + 2)->last_line = lastline; + + func->nexti = def->nexti; + bcfree(def); + + (void) list_append(rule_list, func + 1); /* debugging */ + /* install the function */ - thisfunc = node(params, Node_func, def); - (void) install(params->param, thisfunc); + thisfunc = mk_symbol(Node_func, params); + (void) install_symbol(fname, thisfunc); + thisfunc->code_ptr = func; + func->func_body = thisfunc; - /* figure out amount of space to allocate for variable names */ - for (n = params->rnode; n != NULL; n = n->rnode) { + for (n = params->rnode; n != NULL; n = n->rnode) pcount++; - space += strlen(n->param) + 1; - } - /* allocate it and fill it in */ if (pcount != 0) { - emalloc(names, char *, space, "func_install"); - emalloc(pnames, char **, pcount * sizeof(char *), "func_install"); - sp = names; - for (i = 0, n = params->rnode; i < pcount; i++, n = n->rnode) { - pnames[i] = sp; - strcpy(sp, n->param); - sp += strlen(n->param) + 1; - } - thisfunc->parmlist = pnames; - } else { - thisfunc->parmlist = NULL; + emalloc(pnames, char **, (pcount + 1) * sizeof(char *), "func_install"); + for (i = 0, n = params->rnode; i < pcount; i++, n = n->rnode) + pnames[i] = n->param; + pnames[pcount] = NULL; } + thisfunc->parmlist = pnames; /* update lint table info */ - func_use(params->param, FUNC_DEFINE); + func_use(fname, FUNC_DEFINE); - func_count++; /* used by profiling / pretty printer */ + func_count++; /* used in profiler / pretty printer */ remove_params: /* remove params from symbol table */ pop_params(params->rnode); + return 0; } -/* pop_var --- remove a variable from the symbol table */ +/* remove_symbol --- remove a variable from the symbol table */ -static void -pop_var(NODE *np, int freeit) +NODE * +remove_symbol(char *name) { - register NODE *bucket, **save; - register size_t len; - char *name; + NODE *bucket, **save; + size_t len; - name = np->param; len = strlen(name); save = &(variables[hash(name, len, (unsigned long) HASHSIZE, NULL)]); for (bucket = *save; bucket != NULL; bucket = bucket->hnext) { if (len == bucket->hlength && STREQN(bucket->hname, name, len)) { var_count--; *save = bucket->hnext; - freenode(bucket); - if (freeit) - free(np->param); - return; + return bucket; } save = &(bucket->hnext); } + return NULL; } /* pop_params --- remove list of function parameters from symbol table */ @@ -5715,10 +6826,13 @@ pop_var(NODE *np, int freeit) static void pop_params(NODE *params) { + NODE *hp; if (params == NULL) return; pop_params(params->rnode); - pop_var(params, TRUE); + hp = remove_symbol(params->param); + if (hp != NULL) + freenode(hp); } /* make_param --- make NAME into a function parameter */ @@ -5731,9 +6845,8 @@ make_param(char *name) getnode(r); r->type = Node_param_list; r->rnode = NULL; - r->param = name; r->param_cnt = param_counter++; - return (install(name, r)); + return (install_symbol(name, r)); } static struct fdesc { @@ -5787,6 +6900,9 @@ check_funcs() struct fdesc *fp, *next; int i; + if (get_context()->level > 0) + goto free_mem; + for (i = 0; i < HASHSIZE; i++) { for (fp = ftable[i]; fp != NULL; fp = fp->next) { #ifdef REALLYMEAN @@ -5808,29 +6924,98 @@ check_funcs() } } +free_mem: /* now let's free all the memory */ for (i = 0; i < HASHSIZE; i++) { for (fp = ftable[i]; fp != NULL; fp = next) { next = fp->next; - free(fp->name); - free(fp); + efree(fp->name); + efree(fp); } + ftable[i] = NULL; } } /* param_sanity --- look for parameters that are regexp constants */ static void -param_sanity(NODE *arglist) +param_sanity(INSTRUCTION *arglist) { - NODE *argp, *arg; - int i; + INSTRUCTION *argl, *arg; + int i = 1; - for (i = 1, argp = arglist; argp != NULL; argp = argp->rnode, i++) { - arg = argp->lnode; - if (arg->type == Node_regex) + if (arglist == NULL) + return; + for (argl = arglist->nexti; argl; ) { + arg = argl->lasti; + if (arg->opcode == Op_match_rec) warning(_("regexp constant for parameter #%d yields boolean value"), i); + argl = arg->nexti; + i++; + } +} + +/* foreach_func --- execute given function for each awk function in symbol table. */ + +int +foreach_func(int (*pfunc)(INSTRUCTION *, void *), int sort, void *data) +{ + int i, j; + NODE *p; + int ret = 0; + + if (sort) { + NODE **tab; + + /* + * Walk through symbol table counting functions. + * Could be more than func_count if there are + * extension functions. + */ + for (i = j = 0; i < HASHSIZE; i++) { + for (p = variables[i]; p != NULL; p = p->hnext) { + if (p->hvalue->type == Node_func) { + j++; + } + } + } + + if (j == 0) + return 0; + + emalloc(tab, NODE **, j * sizeof(NODE *), "foreach_func"); + + /* now walk again, copying info */ + for (i = j = 0; i < HASHSIZE; i++) { + for (p = variables[i]; p != NULL; p = p->hnext) { + if (p->hvalue->type == Node_func) { + tab[j] = p; + j++; + } + } + } + + /* Shazzam! */ + qsort(tab, j, sizeof(NODE *), sym_comp); + + for (i = 0; i < j; i++) { + if ((ret = pfunc(tab[i]->hvalue->code_ptr, data)) != 0) + break; + } + + efree(tab); + return ret; } + + /* unsorted */ + for (i = 0; i < HASHSIZE; i++) { + for (p = variables[i]; p != NULL; p = p->hnext) { + if (p->hvalue->type == Node_func + && (ret = pfunc(p->hvalue->code_ptr, data)) != 0) + return ret; + } + } + return 0; } /* deferred variables --- those that are only defined if needed. */ @@ -5867,33 +7052,31 @@ register_deferred_variable(const char *name, NODE *(*load_func)(void)) /* variable --- make sure NAME is in the symbol table */ NODE * -variable(char *name, int can_free, NODETYPE type) +variable(char *name, NODETYPE type) { - register NODE *r; + NODE *r; if ((r = lookup(name)) != NULL) { - if (r->type == Node_func) - fatal(_("function `%s' called with space between name and `(',\nor used as a variable or an array"), + if (r->type == Node_func) { + error(_("function `%s' called with space between name and `(',\nor used as a variable or an array"), r->vname); - + errcount++; + r->type = Node_var_new; /* continue parsing instead of exiting */ + } } else { /* not found */ struct deferred_variable *dv; for (dv = deferred_variables; TRUE; dv = dv->next) { if (dv == NULL) { - /* - * This is the only case in which we may not - * free the string. - */ - NODE *n; - - if (type == Node_var_array) - n = node(NULL, type, NULL); + /* + * This is the only case in which we may not free the string. + */ + if (type == Node_var) + r = mk_symbol(type, Nnull_string); else - n = node(Nnull_string, type, NULL); - - return install(name, n); + r = mk_symbol(type, (NODE *) NULL); + return install_symbol(name, r); } if (STREQ(name, dv->name)) { r = (*dv->load_func)(); @@ -5901,31 +7084,55 @@ variable(char *name, int can_free, NODETYPE type) } } } - if (can_free) - free(name); + efree(name); return r; } -/* mk_rexp --- make a regular expression constant */ +/* make_regnode --- make a regular expression node */ static NODE * -mk_rexp(NODE *exp) +make_regnode(int type, NODE *exp) { NODE *n; - if (exp->type == Node_regex) - return exp; - getnode(n); - n->type = Node_dynregex; - n->re_exp = exp; - n->re_text = NULL; - n->re_reg = NULL; - n->re_flags = 0; + memset(n, 0, sizeof(NODE)); + n->type = type; n->re_cnt = 1; + + if (type == Node_regex) { + n->re_reg = make_regexp(exp->stptr, exp->stlen, FALSE, TRUE, FALSE); + if (n->re_reg == NULL) { + freenode(n); + return NULL; + } + n->re_exp = exp; + n->re_flags = CONSTANT; + } return n; } + +/* mk_rexp --- make a regular expression constant */ + +static NODE * +mk_rexp(INSTRUCTION *list) +{ + INSTRUCTION *ip; + + ip = list->nexti; + if (ip == list->lasti && ip->opcode == Op_match_rec) + ip->opcode = Op_push_re; + else { + ip = instruction(Op_push_re); + ip->memory = make_regnode(Node_dynregex, NULL); + ip->nexti = list->lasti->nexti; + list->lasti->nexti = ip; + list->lasti = ip; + } + return ip->memory; +} + /* isnoeffect --- when used as a statement, has no side effects */ /* @@ -5936,48 +7143,38 @@ mk_rexp(NODE *exp) */ static int -isnoeffect(NODETYPE type) +isnoeffect(OPCODE type) { switch (type) { - case Node_times: - case Node_quotient: - case Node_mod: - case Node_plus: - case Node_minus: - case Node_subscript: - case Node_concat: - case Node_exp: - case Node_unary_minus: - case Node_field_spec: - case Node_and: - case Node_or: - case Node_equal: - case Node_notequal: - case Node_less: - case Node_greater: - case Node_leq: - case Node_geq: - case Node_match: - case Node_nomatch: - case Node_not: - case Node_val: - case Node_in_array: - case Node_NF: - case Node_NR: - case Node_FNR: - case Node_FPAT: - case Node_FS: - case Node_RS: - case Node_FIELDWIDTHS: - case Node_IGNORECASE: - case Node_OFS: - case Node_ORS: - case Node_OFMT: - case Node_CONVFMT: - case Node_BINMODE: - case Node_LINT: - case Node_SUBSEP: - case Node_TEXTDOMAIN: + case Op_times: + case Op_times_i: + case Op_quotient: + case Op_quotient_i: + case Op_mod: + case Op_mod_i: + case Op_plus: + case Op_plus_i: + case Op_minus: + case Op_minus_i: + case Op_subscript: + case Op_concat: + case Op_exp: + case Op_exp_i: + case Op_unary_minus: + case Op_field_spec: + case Op_and_final: + case Op_or_final: + case Op_equal: + case Op_notequal: + case Op_less: + case Op_greater: + case Op_leq: + case Op_geq: + case Op_match: + case Op_nomatch: + case Op_match_rec: + case Op_not: + case Op_in_array: return TRUE; default: break; /* keeps gcc -Wall happy */ @@ -5986,45 +7183,34 @@ isnoeffect(NODETYPE type) return FALSE; } -/* isassignable --- can this node be assigned to? */ +/* make_assignable --- make this operand an assignable one if posiible */ -static int -isassignable(register NODE *n) +static INSTRUCTION * +make_assignable(INSTRUCTION *ip) { - switch (n->type) { - case Node_var_new: - case Node_var: - case Node_FIELDWIDTHS: - case Node_RS: - case Node_FS: - case Node_FNR: - case Node_FPAT: - case Node_NR: - case Node_NF: - case Node_IGNORECASE: - case Node_OFMT: - case Node_CONVFMT: - case Node_ORS: - case Node_OFS: - case Node_LINT: - case Node_BINMODE: - case Node_SUBSEP: - case Node_TEXTDOMAIN: - case Node_field_spec: - case Node_subscript: - return TRUE; - case Node_param_list: - return ((n->flags & FUNC) == 0); /* ok if not func name */ + switch (ip->opcode) { + case Op_push: + if (ip->memory->type == Node_param_list + && (ip->memory->flags & FUNC) != 0) + return NULL; + ip->opcode = Op_push_lhs; + return ip; + case Op_field_spec: + ip->opcode = Op_field_spec_lhs; + return ip; + case Op_subscript: + ip->opcode = Op_subscript_lhs; + return ip; default: break; /* keeps gcc -Wall happy */ } - return FALSE; + return NULL; } /* stopme --- for debugging */ NODE * -stopme(NODE *tree ATTRIBUTE_UNUSED) +stopme(int nargs ATTRIBUTE_UNUSED) { return (NODE *) 0; } @@ -6046,7 +7232,7 @@ dumpintlstr(const char *str, size_t len) } printf("msgid "); - pp_string_fp(stdout, str, len, '"', TRUE); + pp_string_fp(fprintf, stdout, str, len, '"', TRUE); putchar('\n'); printf("msgstr \"\"\n\n"); fflush(stdout); @@ -6069,35 +7255,15 @@ dumpintlstr2(const char *str1, size_t len1, const char *str2, size_t len2) } printf("msgid "); - pp_string_fp(stdout, str1, len1, '"', TRUE); + pp_string_fp(fprintf, stdout, str1, len1, '"', TRUE); putchar('\n'); printf("msgid_plural "); - pp_string_fp(stdout, str2, len2, '"', TRUE); + pp_string_fp(fprintf, stdout, str2, len2, '"', TRUE); putchar('\n'); printf("msgstr[0] \"\"\nmsgstr[1] \"\"\n\n"); fflush(stdout); } -/* count_args --- count the number of printf arguments */ - -static void -count_args(NODE *tree) -{ - size_t count = 0; - NODE *save_tree; - - assert(tree->type == Node_K_printf - || (tree->type == Node_builtin && tree->builtin == do_sprintf)); - save_tree = tree; - - tree = tree->lnode; /* printf format string */ - - for (count = 0; tree != NULL; tree = tree->rnode) - count++; - - save_tree->printf_count = count; -} - /* isarray --- can this type be subscripted? */ static int @@ -6119,6 +7285,1194 @@ isarray(NODE *n) return FALSE; } + +static INSTRUCTION * +mk_binary(INSTRUCTION *s1, INSTRUCTION *s2, INSTRUCTION *op) +{ + INSTRUCTION *ip,*ip1; + AWKNUM res; + + ip = s2->nexti; + if (s2->lasti == ip && ip->opcode == Op_push_i) { + /* do any numeric constant folding */ + ip1 = s1->nexti; + if (ip1->memory != NULL && ip1->memory->type == Node_val + && (ip1->memory->flags & (STRCUR|STRING)) == 0 + && ip->memory != NULL && ip->memory->type == Node_val + && (ip->memory->flags & (STRCUR|STRING)) == 0 + && ip1 == s1->lasti && do_optimize > 1) { + ip1->memory->numbr = force_number(ip1->memory); + ip->memory->numbr = force_number(ip->memory); + res = ip1->memory->numbr; + switch (op->opcode) { + case Op_times: + res *= ip->memory->numbr; + break; + case Op_quotient: + if (ip->memory->numbr == 0) { + /* don't fatalize, allow parsing rest of the input */ + yyerror(_("division by zero attempted")); + goto regular; + } + + res /= ip->memory->numbr; + break; + case Op_mod: + if (ip->memory->numbr == 0) { + /* don't fatalize, allow parsing rest of the input */ + yyerror(_("division by zero attempted in `%%'")); + goto regular; + } +#ifdef HAVE_FMOD + res = fmod(res, ip->memory->numbr); +#else /* ! HAVE_FMOD */ + (void) modf(res / ip->memory->numbr, &res); + res = ip1->memory->numbr - res * ip->memory->numbr; +#endif /* ! HAVE_FMOD */ + break; + case Op_plus: + res += ip->memory->numbr; + break; + case Op_minus: + res -= ip->memory->numbr; + break; + case Op_exp: + res = calc_exp(res, ip->memory->numbr); + break; + default: + goto regular; + } + + op->opcode = Op_push_i; + op->memory = mk_number(res, (PERM|NUMCUR|NUMBER)); + bcfree(ip1); + bcfree(ip); + bcfree(s1); + bcfree(s2); + return list_create(op); + } else { + /* do basic arithmetic optimisation */ + /* convert (Op_push_i Node_val) + (Op_plus) to (Op_plus_i Node_val) */ + switch (op->opcode) { + case Op_times: + op->opcode = Op_times_i; + break; + case Op_quotient: + op->opcode = Op_quotient_i; + break; + case Op_mod: + op->opcode = Op_mod_i; + break; + case Op_plus: + op->opcode = Op_plus_i; + break; + case Op_minus: + op->opcode = Op_minus_i; + break; + case Op_exp: + op->opcode = Op_exp_i; + break; + default: + goto regular; + } + + op->memory = ip->memory; + bcfree(ip); + bcfree(s2); /* Op_list */ + return list_append(s1, op); + } + } + +regular: + /* append lists s1, s2 and add `op' bytecode */ + (void) list_merge(s1, s2); + return list_append(s1, op); +} + +/* mk_boolean --- instructions for boolean and, or */ + +static INSTRUCTION * +mk_boolean(INSTRUCTION *left, INSTRUCTION *right, INSTRUCTION *op) +{ + INSTRUCTION *tp; + OPCODE opc, final_opc; + + opc = op->opcode; /* Op_and or Op_or */ + final_opc = (opc == Op_or) ? Op_or_final : Op_and_final; + + add_lint(right, LINT_assign_in_cond); + + tp = left->lasti; + + if (tp->opcode != final_opc) { /* x || y */ + list_append(right, instruction(final_opc)); + add_lint(left, LINT_assign_in_cond); + (void) list_append(left, op); + left->lasti->target_jmp = right->lasti; + + /* NB: target_stmt points to previous Op_and(Op_or) in a chain; + * target_stmt only used in the parser (see below). + */ + + left->lasti->target_stmt = left->lasti; + right->lasti->target_stmt = left->lasti; + } else { /* optimization for x || y || z || ... */ + INSTRUCTION *ip; + + op->opcode = final_opc; + (void) list_append(right, op); + op->target_stmt = tp; + tp->opcode = opc; + tp->target_jmp = op; + + /* update jump targets */ + for (ip = tp->target_stmt; ; ip = ip->target_stmt) { + assert(ip->opcode == opc); + assert(ip->target_jmp == tp); + /* if (ip->opcode == opc && ip->target_jmp == tp) */ + ip->target_jmp = op; + if (ip->target_stmt == ip) + break; + } + } + + return list_merge(left, right); +} + +/* mk_condition --- if-else and conditional */ + +static INSTRUCTION * +mk_condition(INSTRUCTION *cond, INSTRUCTION *ifp, INSTRUCTION *true_branch, + INSTRUCTION *elsep, INSTRUCTION *false_branch) +{ + /* + * ---------------- + * cond + * ---------------- + * t: [Op_jmp_false f ] + * ---------------- + * true_branch + * + * ---------------- + * [Op_jmp y] + * ---------------- + * f: + * false_branch + * ---------------- + * y: [Op_no_op] + * ---------------- + */ + + INSTRUCTION *ip; + + /* FIXME else { } -- add elsep */ + + if (false_branch == NULL) { + if (elsep != NULL) /* else { } */ + false_branch = list_append(list_create(elsep), instruction(Op_no_op)); + else + false_branch = list_create(instruction(Op_no_op)); + } else { + /* assert(elsep != NULL); */ + + /* avoid a series of no_op's: if .. else if .. else if .. */ + if (false_branch->lasti->opcode != Op_no_op) + (void) list_append(false_branch, instruction(Op_no_op)); + (void) list_prepend(false_branch, elsep); + false_branch->nexti->branch_end = false_branch->lasti; + if (do_profiling) + (void) list_prepend(false_branch, instruction(Op_exec_count)); + } + + (void) list_prepend(false_branch, instruction(Op_jmp)); + false_branch->nexti->target_jmp = false_branch->lasti; + + add_lint(cond, LINT_assign_in_cond); + ip = list_append(cond, instruction(Op_jmp_false)); + ip->lasti->target_jmp = false_branch->nexti->nexti; + + (void) list_prepend(ip, ifp); + if (do_profiling) { + (void) list_append(ip, instruction(Op_exec_count)); + ip->nexti->branch_if = ip->lasti; + ip->nexti->branch_else = false_branch->nexti; + } + + if (true_branch != NULL) + list_merge(ip, true_branch); + return list_merge(ip, false_branch); +} + +enum defline { FIRST_LINE, LAST_LINE }; + +/* find_line -- find the first(last) line in a list of (pattern) instructions */ + +static int +find_line(INSTRUCTION *pattern, enum defline what) +{ + INSTRUCTION *ip; + int lineno = 0; + + for (ip = pattern->nexti; ip; ip = ip->nexti) { + if (what == LAST_LINE) { + if (ip->source_line > lineno) + lineno = ip->source_line; + } else { /* FIRST_LINE */ + if (ip->source_line > 0 + && (lineno == 0 || ip->source_line < lineno)) + lineno = ip->source_line; + } + if (ip == pattern->lasti) + break; + } + assert(lineno > 0); + return lineno; +} + +/* append_rule --- pattern-action instructions */ + +static INSTRUCTION * +append_rule(INSTRUCTION *pattern, INSTRUCTION *action) +{ + /* + * ---------------- + * pattern + * ---------------- + * [Op_jmp_false f ] + * ---------------- + * action + * ---------------- + * f: [Op_no_op ] + * ---------------- + */ + + INSTRUCTION *rp; + INSTRUCTION *tp; + INSTRUCTION *ip; + + if (rule != Rule) { + rp = pattern; + if (do_profiling) + (void) list_append(action, instruction(Op_no_op)); + (rp + 1)->firsti = action->nexti; + (rp + 1)->lasti = action->lasti; + (rp + 2)->first_line = pattern->source_line; + (rp + 2)->last_line = lastline; + ip = list_prepend(action, rp); + + } else { + rp = bcalloc(Op_rule, 3, 0); + rp->in_rule = Rule; + rp->source_file = source; + tp = instruction(Op_no_op); + + if (pattern == NULL) { + /* assert(action != NULL); */ + if (do_profiling) + (void) list_prepend(action, instruction(Op_exec_count)); + (rp + 1)->firsti = action->nexti; + (rp + 1)->lasti = tp; + (rp + 2)->first_line = firstline; + (rp + 2)->last_line = lastline; + rp->source_line = firstline; + ip = list_prepend(list_append(action, tp), rp); + } else { + (void) list_append(pattern, instruction(Op_jmp_false)); + pattern->lasti->target_jmp = tp; + (rp + 2)->first_line = find_line(pattern, FIRST_LINE); + rp->source_line = (rp + 2)->first_line; + if (action == NULL) { + (rp + 2)->last_line = find_line(pattern, LAST_LINE); + action = list_create(instruction(Op_K_print_rec)); + if (do_profiling) + (void) list_prepend(action, instruction(Op_exec_count)); + } else + (rp + 2)->last_line = lastline; + + if (do_profiling) { + (void) list_prepend(pattern, instruction(Op_exec_count)); + (void) list_prepend(action, instruction(Op_exec_count)); + } + (rp + 1)->firsti = action->nexti; + (rp + 1)->lasti = tp; + ip = list_append( + list_merge(list_prepend(pattern, rp), + action), + tp); + } + + } + + list_append(rule_list, rp + 1); + + if (rule_block[rule] == NULL) + rule_block[rule] = ip; + else + (void) list_merge(rule_block[rule], ip); + + return rule_block[rule]; +} + +/* mk_assignment --- assignment bytecodes */ + +static INSTRUCTION * +mk_assignment(INSTRUCTION *lhs, INSTRUCTION *rhs, INSTRUCTION *op) +{ + INSTRUCTION *tp; + INSTRUCTION *ip; + + tp = lhs->lasti; + switch (tp->opcode) { + case Op_field_spec: + tp->opcode = Op_field_spec_lhs; + break; + case Op_subscript: + tp->opcode = Op_subscript_lhs; + break; + case Op_push: + case Op_push_array: + tp->opcode = Op_push_lhs; + break; + default: + cant_happen(); + } + + tp->do_reference = (op->opcode != Op_assign); /* check for uninitialized reference */ + + if (rhs != NULL) + ip = list_merge(rhs, lhs); + else + ip = lhs; + + (void) list_append(ip, op); + + if (tp->opcode == Op_push_lhs + && tp->memory->type == Node_var + && tp->memory->var_assign + ) { + tp->do_reference = FALSE; /* no uninitialized reference checking + * for a special variable. + */ + (void) list_append(ip, instruction(Op_var_assign)); + ip->lasti->memory = tp->memory; + } else if (tp->opcode == Op_field_spec_lhs) { + (void) list_append(ip, instruction(Op_field_assign)); + ip->lasti->field_assign = (Func_ptr) 0; + tp->target_assign = ip->lasti; + } + + return ip; +} + +/* optimize_assignment --- peephole optimization for assignment */ + +static INSTRUCTION * +optimize_assignment(INSTRUCTION *exp) +{ + INSTRUCTION *i1; + INSTRUCTION *i2; + INSTRUCTION *i3; + + /* + * Optimize assignment statements array[subs] = x; var = x; $n = x; + * string concatenation of the form s = s t. + * + * 1) Array element assignment array[subs] = x: + * Replaces Op_push_array + Op_subscript_lhs + Op_assign + Op_pop + * with single instruction Op_store_sub. + * Limitation (FIXME): 1 dimension and sub is simple var/value. + * + * 2) Simple variable assignment var = x: + * Replaces Op_push_lhs + Op_assign + Op_pop with Op_store_var. + * + * 3) Field assignment $n = x: + * Replaces Op_field_spec_lhs + Op_assign + Op_field_assign + Op_pop + * with Op_store_field. + * + * 4) Optimization for string concatenation: + * For cases like x = x y, uses realloc to include y in x; + * also eliminates instructions Op_push_lhs and Op_pop. + */ + + /* + * N.B.: do not append Op_pop instruction to the returned + * instruction list if optimized. None of these + * optimized instructions push the r-value of assignment + * onto the runtime stack. + */ + + i2 = NULL; + i1 = exp->lasti; + + if ( ! do_optimize + || ( i1->opcode != Op_assign + && i1->opcode != Op_field_assign) + ) + return list_append(exp, instruction(Op_pop)); + + for (i2 = exp->nexti; i2 != i1; i2 = i2->nexti) { + switch (i2->opcode) { + case Op_concat: + if (i2->nexti->opcode == Op_push_lhs /* l.h.s is a simple variable */ + && (i2->concat_flag & CSVAR) /* 1st exp in r.h.s is a simple variable; + * see Op_concat in the grammer above. + */ + && i2->nexti->memory == exp->nexti->memory /* and the same as in l.h.s */ + && i2->nexti->nexti == i1 + && i1->opcode == Op_assign + ) { + /* s = s ... optimization */ + + /* avoid stuff like x = x (x = y) or x = x gsub(/./, "b", x); + * check for l-value reference to this variable in the r.h.s. + * Also avoid function calls in general, to guard against + * global variable assignment. + */ + + for (i3 = exp->nexti->nexti; i3 != i2; i3 = i3->nexti) { + if ((i3->opcode == Op_push_lhs && i3->memory == i2->nexti->memory) + || i3->opcode == Op_func_call) + return list_append(exp, instruction(Op_pop)); /* no optimization */ + } + + /* remove the variable from r.h.s */ + i3 = exp->nexti; + exp->nexti = i3->nexti; + bcfree(i3); + + if (--i2->expr_count == 1) /* one less expression in Op_concat */ + i2->opcode = Op_no_op; + + i3 = i2->nexti; + assert(i3->opcode == Op_push_lhs); + i3->opcode = Op_assign_concat; /* change Op_push_lhs to Op_assign_concat */ + i3->nexti = NULL; + bcfree(i1); /* Op_assign */ + exp->lasti = i3; /* update Op_list */ + return exp; + } + break; + + case Op_field_spec_lhs: + if (i2->nexti->opcode == Op_assign + && i2->nexti->nexti == i1 + && i1->opcode == Op_field_assign + ) { + /* $n = .. */ + i2->opcode = Op_store_field; + bcfree(i2->nexti); /* Op_assign */ + i2->nexti = NULL; + bcfree(i1); /* Op_field_assign */ + exp->lasti = i2; /* update Op_list */ + return exp; + } + break; + + case Op_push_array: + if (i2->nexti->nexti->opcode == Op_subscript_lhs) { + i3 = i2->nexti->nexti; + if (i3->sub_count == 1 + && i3->nexti == i1 + && i1->opcode == Op_assign + ) { + /* array[sub] = .. */ + i3->opcode = Op_store_sub; + i3->memory = i2->memory; + i3->expr_count = 1; /* sub_count shadows memory, + * so use expr_count instead. + */ + i3->nexti = NULL; + i2->opcode = Op_no_op; + bcfree(i1); /* Op_assign */ + exp->lasti = i3; /* update Op_list */ + return exp; + } + } + break; + + case Op_push_lhs: + if (i2->nexti == i1 + && i1->opcode == Op_assign + ) { + /* var = .. */ + i2->opcode = Op_store_var; + i2->nexti = NULL; + bcfree(i1); /* Op_assign */ + exp->lasti = i2; /* update Op_list */ + return exp; + } + break; + + default: + break; + } + } + + /* no optimization */ + return list_append(exp, instruction(Op_pop)); +} + + +/* mk_getline --- make instructions for getline */ + +static INSTRUCTION * +mk_getline(INSTRUCTION *op, INSTRUCTION *var, INSTRUCTION *redir, OPCODE redirtype) +{ + INSTRUCTION *ip; + INSTRUCTION *tp; + INSTRUCTION *asgn = NULL; + + /* + * getline [var] < [file] + * + * [ file (simp_exp)] + * [ [ var ] ] + * [ Op_K_getline_redir|NULL|redir_type|into_var] + * [ [var_assign] ] + * + */ + + if (redir == NULL) { + int sline = op->source_line; + bcfree(op); + op = bcalloc(Op_K_getline, 2, sline); + (op + 1)->target_endfile = ip_endfile; + (op + 1)->target_beginfile = ip_beginfile; + } + + if (var != NULL) { + tp = make_assignable(var->lasti); + assert(tp != NULL); + + /* check if we need after_assign bytecode */ + if (tp->opcode == Op_push_lhs + && tp->memory->type == Node_var + && tp->memory->var_assign + ) { + asgn = instruction(Op_var_assign); + asgn->memory = tp->memory; + } else if (tp->opcode == Op_field_spec_lhs) { + asgn = instruction(Op_field_assign); + asgn->field_assign = (Func_ptr) 0; /* determined at run time */ + tp->target_assign = asgn; + } + if (redir != NULL) { + ip = list_merge(redir, var); + (void) list_append(ip, op); + } else + ip = list_append(var, op); + } else if (redir != NULL) + ip = list_append(redir, op); + else + ip = list_create(op); + op->into_var = (var != NULL); + op->redir_type = (redir != NULL) ? redirtype : 0; + + return (asgn == NULL ? ip : list_append(ip, asgn)); +} + + +/* mk_for_loop --- for loop bytecodes */ + +static INSTRUCTION * +mk_for_loop(INSTRUCTION *forp, INSTRUCTION *init, INSTRUCTION *cond, + INSTRUCTION *incr, INSTRUCTION *body) +{ + /* + * [ Op_push_loop | z| y] <-- continue | break + * ------------------------ + * init (may be NULL) + * ------------------------ + * x: + * cond (Op_no_op if NULL) + * ------------------------ + * [ Op_jmp_false y ] + * ------------------------ + * body (may be NULL) + * ------------------------ + * z: + * incr (may be NULL) + * [ Op_jmp x ] + * ------------------------ + * y:[ Op_pop_loop ] + */ + + INSTRUCTION *ip; + INSTRUCTION *cp; + INSTRUCTION *jmp; + INSTRUCTION *pp_cond; + INSTRUCTION *ret; + + cp = instruction(Op_pop_loop); + + forp->opcode = Op_push_loop; + forp->target_break = cp; + ip = list_create(forp); + + if (init != NULL) + (void) list_merge(ip, init); + + if (cond != NULL) { + add_lint(cond, LINT_assign_in_cond); + pp_cond = cond->nexti; + (void) list_merge(ip, cond); + (void) list_append(ip, instruction(Op_jmp_false)); + ip->lasti->target_jmp = cp; + } else { + pp_cond = instruction(Op_no_op); + (void) list_append(ip, pp_cond); + } + + if (do_profiling) { + (void) list_append(ip, instruction(Op_exec_count)); + (forp + 1)->opcode = Op_K_for; + (forp + 1)->forloop_cond = pp_cond; + (forp + 1)->forloop_body = ip->lasti; + } + + if (body != NULL) + (void) list_merge(ip, body); + + if (incr != NULL) { + forp->target_continue = incr->nexti; + (void) list_merge(ip, incr); + } + jmp = instruction(Op_jmp); + jmp->target_jmp = pp_cond; + if (incr == NULL) + forp->target_continue = jmp; + (void) list_append(ip, jmp); + + ret = list_append(ip, cp); + + fix_break_continue(forp, cp, TRUE); + + return ret; +} + +/* add_lint --- add lint warning bytecode if needed */ + +static void +add_lint(INSTRUCTION *list, LINTTYPE linttype) +{ +#ifndef NO_LINT + INSTRUCTION *ip; + + switch (linttype) { + case LINT_assign_in_cond: + ip = list->lasti; + if (ip->opcode == Op_var_assign || ip->opcode == Op_field_assign) { + assert(ip != list->nexti); + for (ip = list->nexti; ip->nexti != list->lasti; ip = ip->nexti) + ; + } + + if (ip->opcode == Op_assign || ip->opcode == Op_assign_concat) { + list_append(list, instruction(Op_lint)); + list->lasti->lint_type = linttype; + } + break; + + case LINT_no_effect: + if (list->lasti->opcode == Op_pop && list->nexti != list->lasti) { + for (ip = list->nexti; ip->nexti != list->lasti; ip = ip->nexti) + ; + + if (do_lint) { /* compile-time warning */ + if (isnoeffect(ip->opcode)) + lintwarn(_("statement may have no effect")); + } + + if (ip->opcode == Op_push) { /* run-time warning */ + list_append(list, instruction(Op_lint)); + list->lasti->lint_type = linttype; + } + } + break; + + default: + break; + } +#endif +} + +/* mk_expression_list --- list of bytecode lists */ + +static INSTRUCTION * +mk_expression_list(INSTRUCTION *list, INSTRUCTION *s1) +{ + INSTRUCTION *r; + + /* we can't just combine all bytecodes, since we need to + * process individual expressions for a few builtins in snode() (-: + */ + + /* -- list of lists */ + /* [Op_list| ... ]------ + * | + * [Op_list| ... ] -- | + * ... | | + * ... <------- | + * [Op_list| ... ] -- | + * ... | | + * ... | | + * ... <------- -- + */ + + assert(s1 != NULL && s1->opcode == Op_list); + if (list == NULL) { + list = instruction(Op_list); + list->nexti = s1; + list->lasti = s1->lasti; + return list; + } + + /* append expression to the end of the list */ + + r = list->lasti; + r->nexti = s1; + list->lasti = s1->lasti; + return list; +} + +/* count_expressions --- fixup expression_list from mk_expression_list. + * returns no of expressions in list. isarg is true + * for function arguments. + */ + +static int +count_expressions(INSTRUCTION **list, int isarg) +{ + INSTRUCTION *expr; + INSTRUCTION *r = NULL; + int count = 0; + + if (*list == NULL) /* error earlier */ + return 0; + + for (expr = (*list)->nexti; expr; ) { + INSTRUCTION *t1, *t2; + t1 = expr->nexti; + t2 = expr->lasti; + if (isarg && t1 == t2 && t1->opcode == Op_push) + t1->opcode = Op_push_param; + if (++count == 1) + r = expr; + else + (void) list_merge(r, expr); + expr = t2->nexti; + } + + assert(count > 0); + if (! isarg && count > max_args) + max_args = count; + bcfree(*list); + *list = r; + return count; +} + +/* fix_break_continue --- fix up break & continue nodes in loop bodies */ + +static void +fix_break_continue(INSTRUCTION *start, INSTRUCTION *end, int check_continue) +{ + INSTRUCTION *ip, *b_target, *c_target; + + assert(start->opcode == Op_push_loop); + assert(end->opcode == Op_pop_loop); + + b_target = start->target_break; + c_target = start->target_continue; + + for (ip = start; ip != end; ip = ip->nexti) { + switch (ip->opcode) { + case Op_K_break: + if (ip->target_jmp == NULL) + ip->target_jmp = b_target; + break; + + case Op_K_continue: + if (check_continue && ip->target_jmp == NULL) + ip->target_jmp = c_target; + break; + + default: + /* this is to keep the compiler happy. sheesh. */ + break; + } + } +} + + +/* append_symbol --- append symbol to the list of symbols + * installed in the symbol table. + */ + +void +append_symbol(char *name) +{ + NODE *hp; + + /* N.B.: func_install removes func name and reinstalls it; + * and we get two entries for it here!. destroy_symbol() + * will find and destroy the Node_func which is what we want. + */ + + getnode(hp); + hp->hname = name; /* shallow copy */ + hp->hnext = symbol_list->hnext; + symbol_list->hnext = hp; +} + +void +release_symbols(NODE *symlist, int keep_globals) +{ + NODE *hp, *n; + + for (hp = symlist->hnext; hp != NULL; hp = n) { + if (! keep_globals) { + /* destroys globals, function, and params + * if still in symbol table and not removed by func_install + * due to syntax error. + */ + destroy_symbol(hp->hname); + } + n = hp->hnext; + freenode(hp); + } + symlist->hnext = NULL; +} + +/* destroy_symbol --- remove a symbol from symbol table +* and free all associated memory. +*/ + + +void +destroy_symbol(char *name) +{ + NODE *symbol, *hp; + + symbol = lookup(name); + if (symbol == NULL) + return; + + if (symbol->type == Node_func) { + char **varnames; + NODE *func, *n; + + func = symbol; + varnames = func->parmlist; + if (varnames != NULL) + efree(varnames); + + /* function parameters of type Node_param_list */ + for (n = func->lnode->rnode; n != NULL; ) { + NODE *np; + np = n->rnode; + efree(n->param); + freenode(n); + n = np; + } + freenode(func->lnode); + func_count--; + + } else if (symbol->type == Node_var_array) + assoc_clear(symbol); + else if (symbol->type == Node_var) + unref(symbol->var_value); + + /* remove from symbol table */ + hp = remove_symbol(name); + efree(hp->hname); + freenode(hp->hvalue); + freenode(hp); +} + +#define pool_size d.dl +#define freei x.xi +static INSTRUCTION *pool_list; +static CONTEXT *curr_ctxt = NULL; + + +CONTEXT * +new_context() +{ + CONTEXT *ctxt; + + emalloc(ctxt, CONTEXT *, sizeof(CONTEXT), "new_context"); + memset(ctxt, 0, sizeof(CONTEXT)); + ctxt->srcfiles.next = ctxt->srcfiles.prev = &ctxt->srcfiles; + ctxt->rule_list.opcode = Op_list; + ctxt->rule_list.lasti = &ctxt->rule_list; + if (curr_ctxt == NULL) { + ctxt->level = 0; + pool_list = &ctxt->pools; + symbol_list = &ctxt->symbols; + srcfiles = &ctxt->srcfiles; + rule_list = &ctxt->rule_list; + install_func = ctxt->install_func; + curr_ctxt = ctxt; + } else + ctxt->level = curr_ctxt->level + 1; /* this assumes contexts don't overlap each other ? */ + + return ctxt; +} + + +/* N.B.: new context (level > 0) inherits all command line options; + * probably should restore defaults for lint etc. + */ + +CONTEXT * +set_context(CONTEXT *ctxt) +{ + assert(curr_ctxt != NULL); + if (curr_ctxt == ctxt) + goto update; + + /* save current source and sourceline */ + curr_ctxt->sourceline = sourceline; + curr_ctxt->source = source; + + if (ctxt == NULL) { + assert(curr_ctxt->prev != NULL); + ctxt = curr_ctxt->prev; + } else + ctxt->prev = curr_ctxt; + + /* restore source and sourceline */ + sourceline = ctxt->sourceline; + source = ctxt->source; + +update: + pool_list = &ctxt->pools; + symbol_list = &ctxt->symbols; + srcfiles = &ctxt->srcfiles; + rule_list = &ctxt->rule_list; + install_func = ctxt->install_func; + curr_ctxt = ctxt; + return curr_ctxt; +} + +CONTEXT * +get_context() +{ + assert(curr_ctxt != NULL); + return curr_ctxt; +} + +void +free_context(CONTEXT *ctxt, int keep_globals) +{ + SRCFILE *s, *sn; + + if (ctxt == NULL) + return; + + assert(curr_ctxt != ctxt); + + /* free all code including function codes */ + free_bcpool(&ctxt->pools); + /* free symbols */ + release_symbols(&ctxt->symbols, keep_globals); + /* free srcfiles */ + for (s = &ctxt->srcfiles; s != &ctxt->srcfiles; s = sn) { + sn = s->next; + if (s->stype != SRC_CMDLINE && s->stype != SRC_STDIN) + efree(s->fullpath); + efree(s->src); + efree(s); + } + efree(ctxt); +} + +static void +free_bc_internal(INSTRUCTION *cp) +{ + INSTRUCTION *curr; + NODE *m; + + switch(cp->opcode) { + case Op_func_call: + if (cp->func_name != NULL + && cp->func_name != builtin_func + ) + efree(cp->func_name); + break; + case Op_K_switch: + for (curr = cp->case_val; curr != NULL; curr = curr->nexti) { + if (curr->opcode == Op_K_case && + curr->memory->type != Node_val + ) { + m = curr->memory; + if (m->re_text != NULL) + unref(m->re_text); + if (m->re_reg != NULL) + refree(m->re_reg); + if (m->re_exp != NULL) + unref(m->re_exp); + freenode(m); + } + } + break; + case Op_push_re: + case Op_match_rec: + case Op_match: + case Op_nomatch: + m = cp->memory; + if (m->re_reg != NULL) + refree(m->re_reg); + if (m->re_exp != NULL) + unref(m->re_exp); + if (m->re_text != NULL) + unref(m->re_text); + freenode(m); + break; + case Op_token: /* token lost during error recovery in yyparse */ + if (cp->lextok != NULL) + efree(cp->lextok); + break; + case Op_illegal: + cant_happen(); + default: + break; + } +} + + +/* INSTR_CHUNK must be > largest code size (3) */ +#define INSTR_CHUNK 127 + +/* bcfree --- deallocate instruction */ + +void +bcfree(INSTRUCTION *cp) +{ + cp->opcode = 0; + cp->nexti = pool_list->freei; + pool_list->freei = cp; +} + + +/* bcalloc --- allocate a new instruction */ + +INSTRUCTION * +bcalloc(OPCODE op, int size, int srcline) +{ + INSTRUCTION *cp; + + if (size > 1) { + /* wide instructions Op_rule, Op_func_call .. */ + emalloc(cp, INSTRUCTION *, (size + 1) * sizeof(INSTRUCTION), "bcalloc"); + cp->pool_size = size; + cp->nexti = pool_list->nexti; + pool_list->nexti = cp++; + } else { + INSTRUCTION *pool; + + pool = pool_list->freei; + if (pool == NULL) { + INSTRUCTION *last; + emalloc(cp, INSTRUCTION *, (INSTR_CHUNK + 1) * sizeof(INSTRUCTION), "bcalloc"); + + cp->pool_size = INSTR_CHUNK; + cp->nexti = pool_list->nexti; + pool_list->nexti = cp; + pool = ++cp; + last = &pool[INSTR_CHUNK - 1]; + for (; cp <= last; cp++) { + cp->opcode = 0; + cp->nexti = cp + 1; + } + --cp; + cp->nexti = NULL; + } + cp = pool; + pool_list->freei = cp->nexti; + } + + memset(cp, 0, size * sizeof(INSTRUCTION)); + cp->opcode = op; + cp->source_line = srcline; + return cp; +} + + +static void +free_bcpool(INSTRUCTION *pl) +{ + INSTRUCTION *pool, *tmp; + + for (pool = pl->nexti; pool != NULL; pool = tmp) { + INSTRUCTION *cp, *last; + long psiz; + psiz = pool->pool_size; + if (psiz == INSTR_CHUNK) + last = pool + psiz; + else + last = pool + 1; + for (cp = pool + 1; cp <= last ; cp++) { + if (cp->opcode != 0) + free_bc_internal(cp); + } + tmp = pool->nexti; + efree(pool); + } + memset(pl, 0, sizeof(INSTRUCTION)); +} + + +static inline INSTRUCTION * +list_create(INSTRUCTION *x) +{ + INSTRUCTION *l; + + l = instruction(Op_list); + l->nexti = x; + l->lasti = x; + return l; +} + +static inline INSTRUCTION * +list_append(INSTRUCTION *l, INSTRUCTION *x) +{ +#ifdef GAWKDEBUG + if (l->opcode != Op_list) + cant_happen(); +#endif + l->lasti->nexti = x; + l->lasti = x; + return l; +} + +static inline INSTRUCTION * +list_prepend(INSTRUCTION *l, INSTRUCTION *x) +{ +#ifdef GAWKDEBUG + if (l->opcode != Op_list) + cant_happen(); +#endif + x->nexti = l->nexti; + l->nexti = x; + return l; +} + +static inline INSTRUCTION * +list_merge(INSTRUCTION *l1, INSTRUCTION *l2) +{ +#ifdef GAWKDEBUG + if (l1->opcode != Op_list) + cant_happen(); + if (l2->opcode != Op_list) + cant_happen(); +#endif + l1->lasti->nexti = l2->nexti; + l1->lasti = l2->lasti; + bcfree(l2); + return l1; +} + /* See if name is a special token. */ int @@ -6136,7 +8490,6 @@ check_special(const char *name) } #endif - low = 0; high = (sizeof(tokentab) / sizeof(tokentab[0])) - 1; while (low <= high) { @@ -6175,7 +8528,7 @@ read_one_line(int fd, void *buffer, size_t count) fp = fdopen(fd, "r"); if (fp == NULL) { fprintf(stderr, "ugh. fdopen: %s\n", strerror(errno)); - exit(EXIT_FAILURE); + gawk_exit(EXIT_FAILURE); } } @@ -6201,162 +8554,4 @@ one_line_close(int fd) return ret; } -/* constant_fold --- try to fold constant operations */ - -static NODE * -constant_fold(NODE *left, NODETYPE op, NODE *right) -{ - AWKNUM result; - extern double fmod P((double x, double y)); - - if (! do_optimize) - return node(left, op, right); - - /* Unary not */ - if (right == NULL) { - if (op == Node_not && left->type == Node_val) { - if ((left->flags & (STRCUR|STRING)) != 0) { - NODE *ret; - if (left->stlen == 0) { - ret = make_number((AWKNUM) 1.0); - } else { - ret = make_number((AWKNUM) 0.0); - } - unref(left); - - return ret; - } else { - if (left->numbr == 0) { - left->numbr = 1.0; - } else { - left->numbr = 0.0; - } - - return left; - } - } - - return node(left, op, right); - } - - /* String concatentation of two string constants */ - if (op == Node_concat - && left->type == Node_val - && (left->flags & (STRCUR|STRING)) != 0 - && right->type == Node_val - && (right->flags & (STRCUR|STRING)) != 0) { - size_t newlen = left->stlen + right->stlen + 2; - - erealloc(left->stptr, char *, newlen, "constant_fold"); - memcpy(left->stptr + left->stlen, right->stptr, right->stlen); - left->stptr[left->stlen + right->stlen] = '\0'; - left->stlen += right->stlen; - - unref(right); - return left; - } - - /* - * From here down, numeric operations. - * Check for string and bail out if have them. - */ - if (left->type != Node_val - || (left->flags & (STRCUR|STRING)) != 0 - || right->type != Node_val - || (right->flags & (STRCUR|STRING)) != 0) { - return node(left, op, right); - } - - /* Numeric operations: */ - switch (op) { - case Node_not: - case Node_exp: - case Node_times: - case Node_quotient: - case Node_mod: - case Node_plus: - case Node_minus: - break; - default: - return node(left, op, right); - } - - left->numbr = force_number(left); - right->numbr = force_number(right); - - result = left->numbr; - switch (op) { - case Node_exp: - result = calc_exp(left->numbr, right->numbr); - break; - case Node_times: - result *= right->numbr; - break; - case Node_quotient: - if (right->numbr == 0) - fatal(_("division by zero attempted in `/'")); - result /= right->numbr; - break; - case Node_mod: - if (right->numbr == 0) - fatal(_("division by zero attempted in `%%'")); -#ifdef HAVE_FMOD - result = fmod(result, right->numbr); -#else /* ! HAVE_FMOD */ - (void) modf(left->numbr / right->numbr, &result); - result = left->numbr - result * right->numbr; -#endif /* ! HAVE_FMOD */ - break; - case Node_plus: - result += right->numbr; - break; - case Node_minus: - result -= right->numbr; - break; - default: - /* Shut up compiler warnings */ - fatal("can't happen"); - break; - } - - unref(right); - left->numbr = result; - - return left; -} - -/* optimize_concat --- optimize the general "x = x y z a" case */ - -static NODE * -optimize_concat(NODE *left, NODETYPE op, NODE *right) -{ - NODE *top, *leftmost; - - if (op != Node_assign) - return node(left, op, right); - - /* - * optimization of `x = x y'. can save lots of time - * if done a lot. - */ - if (( left->type == Node_var - || left->type == Node_var_new - || left->type == Node_param_list) - && right->type == Node_concat) { - /* find bottom of tree, save it */ - for (top = right; top->lnode != NULL && top->type == Node_concat; top = top->lnode) { - leftmost = top->lnode; - if (leftmost->type == Node_concat) - continue; - - /* at this point, we've run out of concatentation */ - if (leftmost != left) - return node(left, op, right); - - top->lnode = Nnull_string; - return node(left, Node_assign_concat, right); - } - } - return node(left, op, right); -} |