diff options
Diffstat (limited to 'awkgram.y')
-rw-r--r-- | awkgram.y | 1944 |
1 files changed, 756 insertions, 1188 deletions
@@ -42,20 +42,17 @@ 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 char **check_params(char *fname, int pcount, INSTRUCTION *list); +static int install_function(char *fname, INSTRUCTION *fi, INSTRUCTION *plist); static NODE *mk_rexp(INSTRUCTION *exp); -static void append_param(char *pname); -static int dup_parms(INSTRUCTION *fp, 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(INSTRUCTION *file); +static int load_library(INSTRUCTION *file); static void next_sourcefile(void); static char *tokexpand(void); @@ -63,6 +60,7 @@ static char *tokexpand(void); static INSTRUCTION *mk_program(void); static INSTRUCTION *append_rule(INSTRUCTION *pattern, INSTRUCTION *action); +static INSTRUCTION *mk_function(INSTRUCTION *fi, INSTRUCTION *def); 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); @@ -74,23 +72,23 @@ static INSTRUCTION *mk_boolean(INSTRUCTION *left, INSTRUCTION *right, INSTRUCTIO static INSTRUCTION *mk_assignment(INSTRUCTION *lhs, INSTRUCTION *rhs, INSTRUCTION *op); static INSTRUCTION *mk_getline(INSTRUCTION *op, INSTRUCTION *opt_var, INSTRUCTION *redir, int redirtype); static NODE *make_regnode(int type, NODE *exp); -static int count_expressions(INSTRUCTION **list, int isarg); +static int count_expressions(INSTRUCTION **list, bool isarg); static INSTRUCTION *optimize_assignment(INSTRUCTION *exp); static void add_lint(INSTRUCTION *list, LINTTYPE linttype); -enum defref { FUNC_DEFINE, FUNC_USE }; +static void process_deferred(); + +enum defref { FUNC_DEFINE, FUNC_USE, FUNC_EXT }; 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(int fd, void *buffer, size_t count); static int one_line_close(int fd); -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 bool want_source = false; +static bool want_regexp = false; /* lexical scanning kludge */ +static char *in_function; /* parsing kludge */ +static bool symtab_used = false; /* program used SYMTAB */ static int rule = 0; const char *const ruletab[] = { @@ -102,50 +100,39 @@ const char *const ruletab[] = { "ENDFILE", }; -static int in_print = FALSE; /* lexical scanning kludge for print */ +static bool in_print = false; /* lexical scanning kludge for print */ static int in_parens = 0; /* lexical scanning kludge for print */ 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 bool 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 bool 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 */ - -#define HASHSIZE 1021 /* this constant only used here */ -NODE *variables[HASHSIZE]; -static int var_count; /* total number of global variables */ - extern char *source; extern int sourceline; extern SRCFILE *srcfiles; extern INSTRUCTION *rule_list; extern int max_args; +extern NODE **args_array; static INSTRUCTION *rule_block[sizeof(ruletab)]; @@ -162,16 +149,6 @@ 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 - * uniform, but if it's seen, don't install the function. - * e.g. - * function split(x) { return x } - * function x(a) { return a } - * should only produce one error message, and not core dump. - */ -static char builtin_func[] = "@builtin"; #define YYSTYPE INSTRUCTION * %} @@ -190,7 +167,7 @@ static char builtin_func[] = "@builtin"; %token LEX_AND LEX_OR INCREMENT DECREMENT %token LEX_BUILTIN LEX_LENGTH %token LEX_EOF -%token LEX_INCLUDE LEX_EVAL +%token LEX_INCLUDE LEX_EVAL LEX_LOAD %token NEWLINE /* Lowest to highest */ @@ -226,6 +203,8 @@ program | program LEX_EOF { next_sourcefile(); + if (sourcefile == srcfiles) + process_deferred(); } | program error { @@ -256,15 +235,18 @@ rule } | function_prologue action { - can_return = FALSE; - if ($1 && func_install($1, $2) < 0) - YYABORT; - func_params = NULL; + in_function = NULL; + (void) mk_function($1, $2); yyerrok; } | '@' LEX_INCLUDE source statement_term { - want_source = FALSE; + want_source = false; + yyerrok; + } + | '@' LEX_LOAD library statement_term + { + want_source = false; yyerrok; } ; @@ -284,6 +266,21 @@ source { $$ = NULL; } ; +library + : FILENAME + { + if (load_library($1) < 0) + YYABORT; + efree($1->lextok); + bcfree($1); + $$ = NULL; + } + | FILENAME error + { $$ = NULL; } + | error + { $$ = NULL; } + ; + pattern : /* empty */ { $$ = NULL; rule = Rule; } @@ -297,8 +294,8 @@ pattern add_lint($4, LINT_assign_in_cond); tp = instruction(Op_no_op); - list_prepend($1, bcalloc(Op_line_range, !!do_profiling + 1, 0)); - $1->nexti->triggered = FALSE; + list_prepend($1, bcalloc(Op_line_range, !!do_pretty_print + 1, 0)); + $1->nexti->triggered = false; $1->nexti->target_jmp = $4->nexti; list_append($1, instruction(Op_cond_pair)); @@ -308,7 +305,7 @@ pattern list_append($4, instruction(Op_cond_pair)); $4->lasti->line_range = $1->nexti; $4->lasti->target_jmp = tp; - if (do_profiling) { + if (do_pretty_print) { ($1->nexti + 1)->condpair_left = $1->lasti; ($1->nexti + 1)->condpair_right = $4->lasti; } @@ -369,13 +366,8 @@ func_name | lex_builtin { yyerror(_("`%s' is a built-in function, it cannot be redefined"), - tokstart); - $1->opcode = Op_symbol; /* Op_symbol instead of Op_token so that - * free_bc_internal does not try to free it - */ - $1->lextok = builtin_func; - $$ = $1; - /* yyerrok; */ + tokstart); + YYABORT; } | '@' LEX_EVAL { $$ = $2; } @@ -387,28 +379,17 @@ lex_builtin ; function_prologue - : LEX_FUNCTION + : LEX_FUNCTION func_name '(' opt_param_list r_paren opt_nls { - param_counter = 0; - func_params = NULL; + $1->source_file = source; + if (install_function($2->lextok, $1, $4) < 0) + YYABORT; + in_function = $2->lextok; + $2->lextok = NULL; + bcfree($2); + /* $4 already free'd in install_function */ + $$ = $1; } - func_name '(' opt_param_list r_paren opt_nls - { - NODE *t; - - $1->source_file = source; - t = make_param($3->lextok); - $3->lextok = NULL; - bcfree($3); - t->flags |= FUNC; - t->rnode = func_params; - func_params = t; - $$ = $1; - can_return = TRUE; - /* check for duplicate parameter names */ - if (dup_parms($1, t)) - errcount++; - } ; regexp @@ -417,7 +398,7 @@ regexp * is a regexp so it should read up to the closing slash. */ : a_slash - { ++want_regexp; } + { want_regexp = true; } REGEXP /* The terminating '/' is consumed by yylex(). */ { NODE *n, *exp; @@ -425,12 +406,13 @@ regexp size_t len; re = $3->lextok; + $3->lextok = NULL; len = strlen(re); if (do_lint) { if (len == 0) lintwarn_ln($3->source_line, _("regexp constant `//' looks like a C++ comment, but is not")); - else if ((re)[0] == '*' && (re)[len-1] == '*') + else if (re[0] == '*' && re[len-1] == '*') /* possible C comment */ lintwarn_ln($3->source_line, _("regexp constant `/%s/' looks like a C comment, but is not"), re); @@ -486,7 +468,7 @@ statement { $$ = $2; } | if_statement { - if (do_profiling) + if (do_pretty_print) $$ = list_prepend($1, instruction(Op_exec_count)); else $$ = $1; @@ -537,7 +519,7 @@ statement case_values[case_count++] = caseval; } else { /* match a constant regex against switch expression. */ - (curr + 1)->match_exp = TRUE; + (curr + 1)->match_exp = true; } curr->stmt_start = casestmt->nexti; curr->stmt_end = casestmt->lasti; @@ -550,7 +532,7 @@ statement else dflt->target_jmp = casestmt->nexti; - if (do_profiling) { + if (do_pretty_print) { curr->stmt_start = casestmt->nexti; curr->stmt_end = casestmt->lasti; (void) list_prepend(cexp, curr); @@ -565,7 +547,7 @@ statement efree(case_values); ip = $3; - if (do_profiling) { + if (do_pretty_print) { (void) list_prepend(ip, $1); (void) list_prepend(ip, instruction(Op_exec_count)); $1->target_break = tbreak; @@ -604,7 +586,7 @@ statement ip = list_append($3, instruction(Op_jmp_false)); ip->lasti->target_jmp = tbreak; - if (do_profiling) { + if (do_pretty_print) { (void) list_append(ip, instruction(Op_exec_count)); $1->target_break = tbreak; $1->target_continue = tcont; @@ -646,7 +628,7 @@ statement ip = list_merge($3, $6); else ip = list_prepend($6, instruction(Op_no_op)); - if (do_profiling) + if (do_pretty_print) (void) list_prepend(ip, instruction(Op_exec_count)); (void) list_append(ip, instruction(Op_jmp_true)); ip->lasti->target_jmp = ip->nexti; @@ -656,7 +638,7 @@ statement continue_allowed--; fix_break_continue(ip, tbreak, tcont); - if (do_profiling) { + if (do_pretty_print) { $1->target_break = tbreak; $1->target_continue = tcont; ($1 + 1)->doloop_cond = tcont; @@ -716,30 +698,30 @@ statement } else { INSTRUCTION *tbreak, *tcont; - /* [ Op_push_array a ] - * [ Op_arrayfor_init | ib ] - * ic:[ Op_arrayfor_incr | ib ] - * [ Op_var_assign if any ] - * - * body - * - * [Op_jmp | ic ] - * ib:[Op_arrayfor_final ] - */ + /* [ Op_push_array a ] + * [ Op_arrayfor_init | ib ] + * ic:[ Op_arrayfor_incr | ib ] + * [ Op_var_assign if any ] + * + * body + * + * [Op_jmp | ic ] + * ib:[Op_arrayfor_final ] + */ regular_loop: ip = $5; ip->nexti->opcode = Op_push_array; tbreak = instruction(Op_arrayfor_final); $4->opcode = Op_arrayfor_incr; - $4->array_var = variable(var_name, Node_var); + $4->array_var = variable($3->source_line, var_name, Node_var); $4->target_jmp = tbreak; tcont = $4; $3->opcode = Op_arrayfor_init; $3->target_jmp = tbreak; (void) list_append(ip, $3); - if (do_profiling) { + if (do_pretty_print) { $1->opcode = Op_K_arrayfor; $1->target_continue = tcont; $1->target_break = tbreak; @@ -760,7 +742,7 @@ regular_loop: ip->lasti->assign_var = $4->array_var->var_assign; } - if (do_profiling) { + if (do_pretty_print) { (void) list_append(ip, instruction(Op_exec_count)); ($1 + 1)->forloop_cond = $4; ($1 + 1)->forloop_body = ip->lasti; @@ -794,7 +776,7 @@ regular_loop: } | non_compound_stmt { - if (do_profiling) + if (do_pretty_print) $$ = list_prepend($1, instruction(Op_exec_count)); else $$ = $1; @@ -851,21 +833,33 @@ non_compound_stmt if ($2 == NULL) { $$ = list_create($1); (void) list_prepend($$, instruction(Op_push_i)); - $$->nexti->memory = Nnull_string; + $$->nexti->memory = dupnode(Nnull_string); } else $$ = list_append($2, $1); } | LEX_RETURN { - if (! can_return) + if (! in_function) yyerror(_("`return' used outside function context")); } opt_exp statement_term { if ($3 == NULL) { $$ = list_create($1); (void) list_prepend($$, instruction(Op_push_i)); - $$->nexti->memory = Nnull_string; - } else + $$->nexti->memory = dupnode(Nnull_string); + } else { + if (do_optimize > 1 + && $3->lasti->opcode == Op_func_call + && strcmp($3->lasti->func_name, in_function) == 0 + ) { + /* Do tail recursion optimization. Tail + * call without a return value is recognized + * in mk_function(). + */ + ($3->lasti + 1)->tail_call = true; + } + $$ = list_append($3, $1); + } } | simple_stmt statement_term ; @@ -879,7 +873,7 @@ non_compound_stmt * We don't bother to document it though. So there. */ simple_stmt - : print { in_print = TRUE; in_parens = 0; } print_expression_list output_redir + : print { in_print = true; in_parens = 0; } print_expression_list output_redir { /* * Optimization: plain `print' has no expression list, so $3 is null. @@ -888,15 +882,14 @@ simple_stmt */ if ($1->opcode == Op_K_print && - ($3 == NULL - || ($3->lasti->opcode == Op_field_spec - && $3->nexti->nexti->nexti == $3->lasti - && $3->nexti->nexti->opcode == Op_push_i - && $3->nexti->nexti->memory->type == Node_val - && $3->nexti->nexti->memory->numbr == 0.0) - ) + ($3 == NULL + || ($3->lasti->opcode == Op_field_spec + && $3->nexti->nexti->nexti == $3->lasti + && $3->nexti->nexti->opcode == Op_push_i + && $3->nexti->nexti->memory->type == Node_val) + ) ) { - static short warned = FALSE; + static bool warned = false; /* ----------------- * output_redir * [ redirect exp ] @@ -907,16 +900,19 @@ simple_stmt */ if ($3 != NULL) { - bcfree($3->lasti); /* Op_field_spec */ - $3->nexti->nexti->memory->flags &= ~PERM; - $3->nexti->nexti->memory->flags |= MALLOC; - unref($3->nexti->nexti->memory); /* Node_val */ + NODE *n = $3->nexti->nexti->memory; + + if (! iszero(n)) + goto regular_print; + + bcfree($3->lasti); /* Op_field_spec */ + unref(n); /* Node_val */ bcfree($3->nexti->nexti); /* Op_push_i */ - bcfree($3->nexti); /* Op_list */ - bcfree($3); /* Op_list */ + bcfree($3->nexti); /* Op_list */ + bcfree($3); /* Op_list */ } else { if (do_lint && (rule == BEGIN || rule == END) && ! warned) { - warned = TRUE; + warned = true; lintwarn_ln($1->source_line, _("plain `print' in BEGIN or END rule should probably be `print \"\"'")); } @@ -925,7 +921,7 @@ simple_stmt $1->expr_count = 0; $1->opcode = Op_K_print_rec; if ($4 == NULL) { /* no redircetion */ - $1->redir_type = 0; + $1->redir_type = redirect_none; $$ = list_create($1); } else { INSTRUCTION *ip; @@ -945,16 +941,16 @@ simple_stmt * [$1 | NULL | redir_type | expr_count] * */ - +regular_print: if ($4 == NULL) { /* no redirection */ if ($3 == NULL) { /* printf without arg */ $1->expr_count = 0; - $1->redir_type = 0; + $1->redir_type = redirect_none; $$ = list_create($1); } else { INSTRUCTION *t = $3; - $1->expr_count = count_expressions(&t, FALSE); - $1->redir_type = 0; + $1->expr_count = count_expressions(&t, false); + $1->redir_type = redirect_none; $$ = list_append(t, $1); } } else { @@ -968,7 +964,7 @@ simple_stmt $$ = list_append($4, $1); } else { INSTRUCTION *t = $3; - $1->expr_count = count_expressions(&t, FALSE); + $1->expr_count = count_expressions(&t, false); $$ = list_append(list_merge($4, t), $1); } } @@ -980,7 +976,14 @@ simple_stmt char *arr = $2->lextok; $2->opcode = Op_push_array; - $2->memory = variable(arr, Node_var_new); + $2->memory = variable($2->source_line, arr, Node_var_new); + + if (! do_posix && ! do_traditional) { + if ($2->memory == symbol_table) + fatal(_("`delete' is not allowed with SYMTAB")); + else if ($2->memory == func_table) + fatal(_("`delete' is not allowed with FUNCTAB")); + } if ($4 == NULL) { /* @@ -1007,11 +1010,11 @@ simple_stmt * should always be done. */ { - static short warned = FALSE; + static bool warned = false; char *arr = $3->lextok; if (do_lint && ! warned) { - warned = TRUE; + warned = true; lintwarn_ln($1->source_line, _("`delete(array)' is a non-portable tawk extension")); } @@ -1019,10 +1022,17 @@ simple_stmt error_ln($1->source_line, _("`delete(array)' is a non-portable tawk extension")); } - $3->memory = variable(arr, Node_var_new); + $3->memory = variable($3->source_line, arr, Node_var_new); $3->opcode = Op_push_array; $1->expr_count = 0; $$ = list_append(list_create($3), $1); + + if (! do_posix && ! do_traditional) { + if ($3->memory == symbol_table) + fatal(_("`delete' is not allowed with SYMTAB")); + else if ($3->memory == func_table) + fatal(_("`delete' is not allowed with FUNCTAB")); + } } | exp { $$ = optimize_assignment($1); } @@ -1055,7 +1065,7 @@ case_statement INSTRUCTION *casestmt = $5; if ($5 == NULL) casestmt = list_create(instruction(Op_no_op)); - if (do_profiling) + if (do_pretty_print) (void) list_prepend(casestmt, instruction(Op_exec_count)); $1->case_exp = $2; $1->case_stmt = casestmt; @@ -1067,7 +1077,7 @@ case_statement INSTRUCTION *casestmt = $4; if ($4 == NULL) casestmt = list_create(instruction(Op_no_op)); - if (do_profiling) + if (do_pretty_print) (void) list_prepend(casestmt, instruction(Op_exec_count)); bcfree($2); $1->case_stmt = casestmt; @@ -1080,7 +1090,9 @@ case_value { $$ = $1; } | '-' YNUMBER %prec UNARY { - $2->memory->numbr = -(force_number($2->memory)); + NODE *n = $2->memory; + (void) force_number(n); + negate_num(n); bcfree($1); $$ = $2; } @@ -1120,11 +1132,11 @@ print_expression_list output_redir : /* empty */ { - in_print = FALSE; + in_print = false; in_parens = 0; $$ = NULL; } - | IO_OUT { in_print = FALSE; in_parens = 0; } common_exp + | IO_OUT { in_print = false; in_parens = 0; } common_exp { if ($1->redir_type == redirect_twoway && $3->lasti->opcode == Op_K_getline_redir @@ -1168,29 +1180,29 @@ input_redir opt_param_list : /* empty */ + { $$ = NULL; } | param_list + { $$ = $1 ; } ; param_list : NAME { - append_param($1->lextok); - $1->lextok = NULL; - bcfree($1); + $1->param_count = 0; + $$ = list_create($1); } | param_list comma NAME { - append_param($3->lextok); - $3->lextok = NULL; - bcfree($3); + $3->param_count = $1->lasti->param_count + 1; + $$ = list_append($1, $3); yyerrok; } | error - { /* func_params = NULL; */ } + { $$ = NULL; } | param_list error - { /* func_params = NULL; */ } + { $$ = $1; } | param_list comma error - { /* func_params = NULL; */ } + { $$ = $1; } ; /* optional expression, as in for loop */ @@ -1258,7 +1270,7 @@ exp | exp LEX_IN simple_variable { if (do_lint_old) - warning_ln($2->source_line, + warning_ln($2->source_line, _("old awk does not support the keyword `in' except after `for'")); $3->nexti->opcode = Op_push_array; $2->opcode = Op_in_array; @@ -1312,7 +1324,7 @@ common_exp | common_exp simp_exp %prec CONCAT_OP { int count = 2; - int is_simple_var = FALSE; + bool is_simple_var = false; if ($1->lasti->opcode == Op_concat) { /* multiple (> 2) adjacent strings optimization */ @@ -1321,32 +1333,29 @@ common_exp $1->lasti->opcode = Op_no_op; } else { is_simple_var = ($1->nexti->opcode == Op_push - && $1->lasti == $1->nexti); /* first exp. is a simple - * variable?; kludge for use - * in Op_assign_concat. - */ + && $1->lasti == $1->nexti); /* first exp. is a simple + * variable?; kludge for use + * in Op_assign_concat. + */ } if (do_optimize > 1 - && $1->nexti == $1->lasti && $1->nexti->opcode == Op_push_i - && $2->nexti == $2->lasti && $2->nexti->opcode == Op_push_i + && $1->nexti == $1->lasti && $1->nexti->opcode == Op_push_i + && $2->nexti == $2->lasti && $2->nexti->opcode == Op_push_i ) { NODE *n1 = $1->nexti->memory; NODE *n2 = $2->nexti->memory; size_t nlen; - (void) force_string(n1); - (void) force_string(n2); + n1 = force_string(n1); + n2 = force_string(n2); nlen = n1->stlen + n2->stlen; erealloc(n1->stptr, char *, nlen + 2, "constant fold"); memcpy(n1->stptr + n1->stlen, n2->stptr, n2->stlen); n1->stlen = nlen; n1->stptr[nlen] = '\0'; - n1->flags &= ~(NUMCUR|NUMBER); + n1->flags &= ~(NUMCUR|NUMBER|NUMINT); n1->flags |= (STRING|STRCUR); - - n2->flags &= ~PERM; - n2->flags |= MALLOC; unref(n2); bcfree($2->nexti); bcfree($2); @@ -1425,7 +1434,7 @@ simp_exp $$ = list_merge($5, $4); } else { INSTRUCTION *t = $2; - $4->expr_count = count_expressions(&t, FALSE); + $4->expr_count = count_expressions(&t, false); $$ = list_append(list_merge(t, $5), $4); } } @@ -1464,12 +1473,13 @@ non_post_simp_exp if ($2->opcode == Op_match_rec) { $2->opcode = Op_nomatch; $1->opcode = Op_push_i; - $1->memory = mk_number(0.0, (PERM|NUMCUR|NUMBER)); + $1->memory = make_number(0.0); $$ = list_append(list_append(list_create($1), - instruction(Op_field_spec)), $2); + instruction(Op_field_spec)), $2); } else { if (do_optimize > 1 && $2->nexti == $2->lasti - && $2->nexti->opcode == Op_push_i + && $2->nexti->opcode == Op_push_i + && ($2->nexti->memory->flags & (MPFN|MPZN)) == 0 ) { NODE *n = $2->nexti->memory; if ((n->flags & (STRCUR|STRING)) != 0) { @@ -1506,10 +1516,10 @@ non_post_simp_exp } | LEX_LENGTH { - static short warned1 = FALSE; + static bool warned = false; - if (do_lint && ! warned1) { - warned1 = TRUE; + if (do_lint && ! warned) { + warned = true; lintwarn_ln($1->source_line, _("call of `length' without parentheses is not portable")); } @@ -1540,8 +1550,11 @@ non_post_simp_exp | '-' simp_exp %prec UNARY { if ($2->lasti->opcode == Op_push_i - && ($2->lasti->memory->flags & (STRCUR|STRING)) == 0) { - $2->lasti->memory->numbr = -(force_number($2->lasti->memory)); + && ($2->lasti->memory->flags & (STRCUR|STRING)) == 0 + ) { + NODE *n = $2->lasti->memory; + (void) force_number(n); + negate_num(n); $$ = $2; bcfree($1); } else { @@ -1556,7 +1569,7 @@ non_post_simp_exp * POSIX semantics: force a conversion to numeric type */ $1->opcode = Op_plus_i; - $1->memory = mk_number((AWKNUM) 0.0, (PERM|NUMCUR|NUMBER)); + $1->memory = make_number(0.0); $$ = list_append($2, $1); } ; @@ -1573,13 +1586,13 @@ func_call INSTRUCTION *f, *t; char *name; NODE *indirect_var; - static short warned = FALSE; + static bool warned = false; const char *msg = _("indirect function calls are a gawk extension"); if (do_traditional || do_posix) yyerror("%s", msg); else if (do_lint && ! warned) { - warned = TRUE; + warned = true; lintwarn("%s", msg); } @@ -1588,7 +1601,7 @@ func_call name = estrdup(f->func_name, strlen(f->func_name)); if (is_std_var(name)) yyerror(_("can not use special variable `%s' for indirect function call"), name); - indirect_var = variable(name, Node_var_new); + indirect_var = variable(f->source_line, name, Node_var_new); t = instruction(Op_push); t->memory = indirect_var; @@ -1613,7 +1626,7 @@ direct_func_call $$ = list_create($1); } else { INSTRUCTION *t = $3; - ($1 + 1)->expr_count = count_expressions(&t, TRUE); + ($1 + 1)->expr_count = count_expressions(&t, true); $$ = list_append(t, $1); } } @@ -1668,10 +1681,10 @@ bracketed_exp_list _("invalid subscript expression")); /* install Null string as subscript. */ t = list_create(instruction(Op_push_i)); - t->nexti->memory = Nnull_string; + t->nexti->memory = dupnode(Nnull_string); $3->sub_count = 1; } else - $3->sub_count = count_expressions(&t, FALSE); + $3->sub_count = count_expressions(&t, false); $$ = list_append(t, $3); } ; @@ -1696,17 +1709,13 @@ simple_variable char *var_name = $1->lextok; $1->opcode = Op_push; - $1->memory = variable(var_name, Node_var_new); + $1->memory = variable($1->source_line, var_name, Node_var_new); $$ = list_create($1); } | NAME subscript_list { - NODE *n; - char *arr = $1->lextok; - if ((n = lookup(arr)) != NULL && ! isarray(n)) - yyerror(_("use of non-array as array")); - $1->memory = variable(arr, Node_var_new); + $1->memory = variable($1->source_line, arr, Node_var_new); $1->opcode = Op_push_array; $$ = list_prepend($2, $1); } @@ -1717,8 +1726,8 @@ variable { INSTRUCTION *ip = $1->nexti; if (ip->opcode == Op_push - && ip->memory->type == Node_var - && ip->memory->var_update + && ip->memory->type == Node_var + && ip->memory->var_update ) { $$ = list_prepend($1, instruction(Op_var_update)); $$->nexti->update_var = ip->memory->var_update; @@ -1729,7 +1738,7 @@ variable { $$ = list_append($2, $1); if ($3 != NULL) - mk_assignment($2, NULL, $3); + mk_assignment($2, NULL, $3); } ; @@ -1790,6 +1799,7 @@ struct token { # define CONTINUE 0x1000 /* continue allowed inside */ NODE *(*ptr)(int); /* function that implements this keyword */ + NODE *(*ptr2)(int); /* alternate arbitrary-precision function */ }; #if 'a' == 0x81 /* it's EBCDIC */ @@ -1813,81 +1823,87 @@ tokcompare(const void *l, const void *r) * Function pointers come from declarations in awk.h. */ +#ifdef HAVE_MPFR +#define MPF(F) do_mpfr_##F +#else +#define MPF(F) 0 +#endif + static const struct token tokentab[] = { -{"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}, +{"BEGIN", Op_rule, LEX_BEGIN, 0, 0, 0}, +{"BEGINFILE", Op_rule, LEX_BEGINFILE, GAWKX, 0, 0}, +{"END", Op_rule, LEX_END, 0, 0, 0}, +{"ENDFILE", Op_rule, LEX_ENDFILE, GAWKX, 0, 0}, #ifdef ARRAYDEBUG -{"adump", Op_builtin, LEX_BUILTIN, GAWKX|A(1), do_adump}, +{"adump", Op_builtin, LEX_BUILTIN, GAWKX|A(1)|A(2), do_adump, 0}, #endif -{"and", Op_builtin, LEX_BUILTIN, GAWKX|A(2), do_and}, -{"asort", Op_builtin, LEX_BUILTIN, GAWKX|A(1)|A(2)|A(3), do_asort}, -{"asorti", Op_builtin, LEX_BUILTIN, GAWKX|A(1)|A(2)|A(3), 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_K_do, 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, A(0)|A(1), do_fflush}, -{"for", Op_K_for, 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_sub_builtin, LEX_BUILTIN, GAWKX|A(3)|A(4), 0}, -{"getline", Op_K_getline_redir, LEX_GETLINE, NOT_OLD, 0}, -{"gsub", Op_sub_builtin, LEX_BUILTIN, NOT_OLD|A(2)|A(3), 0}, -{"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}, -{"isarray", Op_builtin, LEX_BUILTIN, GAWKX|A(1), do_isarray}, -{"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, 0, 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}, +{"and", Op_builtin, LEX_BUILTIN, GAWKX, do_and, MPF(and)}, +{"asort", Op_builtin, LEX_BUILTIN, GAWKX|A(1)|A(2)|A(3), do_asort, 0}, +{"asorti", Op_builtin, LEX_BUILTIN, GAWKX|A(1)|A(2)|A(3), do_asorti, 0}, +{"atan2", Op_builtin, LEX_BUILTIN, NOT_OLD|A(2), do_atan2, MPF(atan2)}, +{"bindtextdomain", Op_builtin, LEX_BUILTIN, GAWKX|A(1)|A(2), do_bindtextdomain, 0}, +{"break", Op_K_break, LEX_BREAK, 0, 0, 0}, +{"case", Op_K_case, LEX_CASE, GAWKX, 0, 0}, +{"close", Op_builtin, LEX_BUILTIN, NOT_OLD|A(1)|A(2), do_close, 0}, +{"compl", Op_builtin, LEX_BUILTIN, GAWKX|A(1), do_compl, MPF(compl)}, +{"continue", Op_K_continue, LEX_CONTINUE, 0, 0, 0}, +{"cos", Op_builtin, LEX_BUILTIN, NOT_OLD|A(1), do_cos, MPF(cos)}, +{"dcgettext", Op_builtin, LEX_BUILTIN, GAWKX|A(1)|A(2)|A(3), do_dcgettext, 0}, +{"dcngettext", Op_builtin, LEX_BUILTIN, GAWKX|A(1)|A(2)|A(3)|A(4)|A(5), do_dcngettext, 0}, +{"default", Op_K_default, LEX_DEFAULT, GAWKX, 0, 0}, +{"delete", Op_K_delete, LEX_DELETE, NOT_OLD, 0, 0}, +{"do", Op_K_do, LEX_DO, NOT_OLD|BREAK|CONTINUE, 0, 0}, +{"else", Op_K_else, LEX_ELSE, 0, 0, 0}, +{"eval", Op_symbol, LEX_EVAL, 0, 0, 0}, +{"exit", Op_K_exit, LEX_EXIT, 0, 0, 0}, +{"exp", Op_builtin, LEX_BUILTIN, A(1), do_exp, MPF(exp)}, +{"fflush", Op_builtin, LEX_BUILTIN, A(0)|A(1), do_fflush, 0}, +{"for", Op_K_for, LEX_FOR, BREAK|CONTINUE, 0, 0}, +{"func", Op_func, LEX_FUNCTION, NOT_POSIX|NOT_OLD, 0, 0}, +{"function",Op_func, LEX_FUNCTION, NOT_OLD, 0, 0}, +{"gensub", Op_sub_builtin, LEX_BUILTIN, GAWKX|A(3)|A(4), 0, 0}, +{"getline", Op_K_getline_redir, LEX_GETLINE, NOT_OLD, 0, 0}, +{"gsub", Op_sub_builtin, LEX_BUILTIN, NOT_OLD|A(2)|A(3), 0, 0}, +{"if", Op_K_if, LEX_IF, 0, 0, 0}, +{"in", Op_symbol, LEX_IN, 0, 0, 0}, +{"include", Op_symbol, LEX_INCLUDE, GAWKX, 0, 0}, +{"index", Op_builtin, LEX_BUILTIN, A(2), do_index, 0}, +{"int", Op_builtin, LEX_BUILTIN, A(1), do_int, MPF(int)}, +{"isarray", Op_builtin, LEX_BUILTIN, GAWKX|A(1), do_isarray, 0}, +{"length", Op_builtin, LEX_LENGTH, A(0)|A(1), do_length, 0}, +{"load", Op_symbol, LEX_LOAD, GAWKX, 0, 0}, +{"log", Op_builtin, LEX_BUILTIN, A(1), do_log, MPF(log)}, +{"lshift", Op_builtin, LEX_BUILTIN, GAWKX|A(2), do_lshift, MPF(lshift)}, +{"match", Op_builtin, LEX_BUILTIN, NOT_OLD|A(2)|A(3), do_match, 0}, +{"mktime", Op_builtin, LEX_BUILTIN, GAWKX|A(1), do_mktime, 0}, +{"next", Op_K_next, LEX_NEXT, 0, 0, 0}, +{"nextfile", Op_K_nextfile, LEX_NEXTFILE, 0, 0, 0}, +{"or", Op_builtin, LEX_BUILTIN, GAWKX, do_or, MPF(or)}, +{"patsplit", Op_builtin, LEX_BUILTIN, GAWKX|A(2)|A(3)|A(4), do_patsplit, 0}, +{"print", Op_K_print, LEX_PRINT, 0, 0, 0}, +{"printf", Op_K_printf, LEX_PRINTF, 0, 0, 0}, +{"rand", Op_builtin, LEX_BUILTIN, NOT_OLD|A(0), do_rand, MPF(rand)}, +{"return", Op_K_return, LEX_RETURN, NOT_OLD, 0, 0}, +{"rshift", Op_builtin, LEX_BUILTIN, GAWKX|A(2), do_rshift, MPF(rhift)}, +{"sin", Op_builtin, LEX_BUILTIN, NOT_OLD|A(1), do_sin, MPF(sin)}, +{"split", Op_builtin, LEX_BUILTIN, A(2)|A(3)|A(4), do_split, 0}, +{"sprintf", Op_builtin, LEX_BUILTIN, 0, do_sprintf, 0}, +{"sqrt", Op_builtin, LEX_BUILTIN, A(1), do_sqrt, MPF(sqrt)}, +{"srand", Op_builtin, LEX_BUILTIN, NOT_OLD|A(0)|A(1), do_srand, MPF(srand)}, #if defined(GAWKDEBUG) || defined(ARRAYDEBUG) /* || ... */ -{"stopme", Op_builtin, LEX_BUILTIN, GAWKX|A(0), stopme}, +{"stopme", Op_builtin, LEX_BUILTIN, GAWKX|A(0), stopme, 0}, #endif -{"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_sub_builtin, LEX_BUILTIN, NOT_OLD|A(2)|A(3), 0}, -{"substr", Op_builtin, LEX_BUILTIN, A(2)|A(3), do_substr}, -{"switch", Op_K_switch, 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_K_while, LEX_WHILE, BREAK|CONTINUE, 0}, -{"xor", Op_builtin, LEX_BUILTIN, GAWKX|A(2), do_xor}, +{"strftime", Op_builtin, LEX_BUILTIN, GAWKX|A(0)|A(1)|A(2)|A(3), do_strftime, 0}, +{"strtonum", Op_builtin, LEX_BUILTIN, GAWKX|A(1), do_strtonum, MPF(strtonum)}, +{"sub", Op_sub_builtin, LEX_BUILTIN, NOT_OLD|A(2)|A(3), 0, 0}, +{"substr", Op_builtin, LEX_BUILTIN, A(2)|A(3), do_substr, 0}, +{"switch", Op_K_switch, LEX_SWITCH, GAWKX|BREAK, 0, 0}, +{"system", Op_builtin, LEX_BUILTIN, NOT_OLD|A(1), do_system, 0}, +{"systime", Op_builtin, LEX_BUILTIN, GAWKX|A(0), do_systime, 0}, +{"tolower", Op_builtin, LEX_BUILTIN, NOT_OLD|A(1), do_tolower, 0}, +{"toupper", Op_builtin, LEX_BUILTIN, NOT_OLD|A(1), do_toupper, 0}, +{"while", Op_K_while, LEX_WHILE, BREAK|CONTINUE, 0, 0}, +{"xor", Op_builtin, LEX_BUILTIN, GAWKX, do_xor, MPF(xor)}, }; #if MBS_SUPPORT @@ -1923,6 +1939,23 @@ getfname(NODE *(*fptr)(int)) return NULL; } +/* negate_num --- negate a number in NODE */ + +void +negate_num(NODE *n) +{ +#ifdef HAVE_MPFR + if (is_mpg_float(n)) { + int tval; + tval = mpfr_neg(n->mpg_numbr, n->mpg_numbr, ROUND_MODE); + IEEE_FMT(n->mpg_numbr, tval); + } else if (is_mpg_integer(n)) { + mpz_neg(n->mpg_i, n->mpg_i); + } else +#endif + n->numbr = -n->numbr; +} + /* print_included_from --- print `Included from ..' file names and locations */ static void @@ -1946,7 +1979,7 @@ print_included_from() line--; msg("%s %s:%d%c", s->prev == sourcefile ? "In file included from" - : " from", + : " from", (s->stype == SRC_INC || s->stype == SRC_FILE) ? s->src : "cmd. line", line, @@ -1968,7 +2001,7 @@ warning_ln(int line, const char *mesg, ...) sourceline = line; print_included_from(); va_start(args, mesg); - err(_("warning: "), mesg, args); + err(false, _("warning: "), mesg, args); va_end(args); sourceline = saveline; } @@ -1986,9 +2019,9 @@ lintwarn_ln(int line, const char *mesg, ...) print_included_from(); va_start(args, mesg); if (lintfunc == r_fatal) - err(_("fatal: "), mesg, args); + err(true, _("fatal: "), mesg, args); else - err(_("warning: "), mesg, args); + err(false, _("warning: "), mesg, args); va_end(args); sourceline = saveline; if (lintfunc == r_fatal) @@ -2008,7 +2041,7 @@ error_ln(int line, const char *m, ...) print_included_from(); errcount++; va_start(args, m); - err("error: ", m, args); + err(false, "error: ", m, args); va_end(args); sourceline = saveline; } @@ -2086,7 +2119,7 @@ yyerror(const char *m, ...) *bp++ = ' '; } strcpy(bp, mesg); - err("", buf, args); + err(false, "", buf, args); va_end(args); efree(buf); } @@ -2127,7 +2160,7 @@ mk_program() if (endfile_block == NULL) endfile_block = list_create(ip_endfile); else { - ip_rec->has_endfile = TRUE; + ip_rec->has_endfile = true; (void) list_prepend(endfile_block, ip_endfile); } @@ -2228,8 +2261,11 @@ parse_program(INSTRUCTION **pcode) ip_atexit = instruction(Op_atexit); /* target for `exit' in END block */ } - sourcefile = srcfiles->next; - lexeof = FALSE; + for (sourcefile = srcfiles->next; sourcefile->stype == SRC_EXTLIB; + sourcefile = sourcefile->next) + ; + + lexeof = false; lexptr = NULL; lasttok = 0; memset(rule_block, 0, sizeof(ruletab) * sizeof(INSTRUCTION *)); @@ -2245,6 +2281,11 @@ parse_program(INSTRUCTION **pcode) if (ret == 0) /* avoid spurious warning if parser aborted with YYABORT */ check_funcs(); + if (args_array == NULL) + emalloc(args_array, NODE **, (max_args + 2) * sizeof(NODE *), "parse_program"); + else + erealloc(args_array, NODE **, (max_args + 2) * sizeof(NODE *), "parse_program"); + return (ret || errcount); } @@ -2273,7 +2314,7 @@ do_add_srcfile(int stype, char *src, char *path, SRCFILE *thisfile) */ SRCFILE * -add_srcfile(int stype, char *src, SRCFILE *thisfile, int *already_included, int *errcode) +add_srcfile(int stype, char *src, SRCFILE *thisfile, bool *already_included, int *errcode) { SRCFILE *s; struct stat sbuf; @@ -2281,41 +2322,61 @@ add_srcfile(int stype, char *src, SRCFILE *thisfile, int *already_included, int int errno_val = 0; if (already_included) - *already_included = FALSE; + *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); + path = find_source(src, & sbuf, &errno_val, stype == SRC_EXTLIB); 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")); + /* use full messages to ease translation */ + fatal(stype != SRC_EXTLIB + ? _("can't open source file `%s' for reading (%s)") + : _("can't open shared library `%s' for reading (%s)"), + src, + errno_val ? strerror(errno_val) : _("reason unknown")); } + /* N.B. We do not eliminate duplicate SRC_FILE (-f) programs. */ for (s = srcfiles->next; s != srcfiles; s = s->next) { - if ((s->stype == SRC_FILE || s->stype == SRC_INC) - && files_are_same(path, s) - ) { - if (do_lint) { - int line = sourceline; - /* Kludge: the line number may be off for `@include file'. - * Since, this function is also used for '-f file' in main.c, - * sourceline > 1 check ensures that the call is at - * parse time. - */ - if (sourceline > 1 && lasttok == NEWLINE) - line--; - lintwarn_ln(line, _("already included source file `%s'"), src); + if ((s->stype == SRC_FILE || s->stype == SRC_INC || s->stype == SRC_EXTLIB) && files_are_same(path, s)) { + if (stype == SRC_INC || stype == SRC_EXTLIB) { + /* eliminate duplicates */ + if ((stype == SRC_INC) && (s->stype == SRC_FILE)) + fatal(_("can't include `%s' and use it as a program file"), src); + + if (do_lint) { + int line = sourceline; + /* Kludge: the line number may be off for `@include file'. + * Since, this function is also used for '-f file' in main.c, + * sourceline > 1 check ensures that the call is at + * parse time. + */ + if (sourceline > 1 && lasttok == NEWLINE) + line--; + lintwarn_ln(line, + stype != SRC_EXTLIB + ? _("already included source file `%s'") + : _("already loaded shared library `%s'"), + src); + } + efree(path); + if (already_included) + *already_included = true; + return NULL; + } else { + /* duplicates are allowed for -f */ + if (s->stype == SRC_INC) + fatal(_("can't include `%s' and use it as a program file"), src); + /* no need to scan for further matches, since + * they must be of homogeneous type */ + break; } - efree(path); - if (already_included) - *already_included = TRUE; - return NULL; } } @@ -2333,7 +2394,7 @@ include_source(INSTRUCTION *file) SRCFILE *s; char *src = file->lextok; int errcode; - int already_included; + bool already_included; if (do_traditional || do_posix) { error_ln(file->source_line, _("@include is a gawk extension")); @@ -2370,8 +2431,43 @@ include_source(INSTRUCTION *file) sourceline = 0; source = NULL; lasttok = 0; - lexeof = FALSE; - eof_warned = FALSE; + lexeof = false; + eof_warned = false; + return 0; +} + +/* load_library --- load a shared library */ + +static int +load_library(INSTRUCTION *file) +{ + SRCFILE *s; + char *src = file->lextok; + int errcode; + bool already_included; + + if (do_traditional || do_posix) { + error_ln(file->source_line, _("@load is a gawk extension")); + return -1; + } + + if (strlen(src) == 0) { + if (do_lint) + lintwarn_ln(file->source_line, _("empty filename after @load")); + return 0; + } + + s = add_srcfile(SRC_EXTLIB, src, sourcefile, &already_included, &errcode); + if (s == NULL) { + if (already_included) + return 0; + error_ln(file->source_line, + _("can't open shared library `%s' for reading (%s)"), + src, errcode ? strerror(errcode) : _("reason unknown")); + return -1; + } + + load_ext(s->fullpath); return 0; } @@ -2398,10 +2494,11 @@ next_sourcefile() * Previous versions of gawk did not core dump in such a * case. * - * assert(lexeof == TRUE); + * assert(lexeof == true); */ - lexeof = FALSE; - eof_warned = FALSE; + + 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 */ @@ -2414,9 +2511,12 @@ next_sourcefile() sourcefile->lexptr_begin = NULL; } - sourcefile = sourcefile->next; - if (sourcefile == srcfiles) - return; + while ((sourcefile = sourcefile->next) != NULL) { + if (sourcefile == srcfiles) + return; + if (sourcefile->stype != SRC_EXTLIB) + break; + } if (sourcefile->lexptr_begin != NULL) { /* resume reading from already opened file (postponed to process '@include') */ @@ -2442,7 +2542,7 @@ get_src_buf() { int n; char *scan; - int newfile; + bool newfile; int savelen; struct stat sbuf; @@ -2467,7 +2567,7 @@ get_src_buf() readfunc = read_one_line; } - newfile = FALSE; + newfile = false; if (sourcefile == srcfiles) return NULL; @@ -2483,13 +2583,13 @@ get_src_buf() * gawk '' /path/name * Sigh. */ - static short warned = FALSE; + static bool warned = false; if (do_lint && ! warned) { - warned = TRUE; + warned = true; lintwarn(_("empty program text on command line")); } - lexeof = TRUE; + lexeof = true; } } else if (sourcefile->buf == NULL && *(lexptr-1) != '\n') { /* @@ -2517,7 +2617,7 @@ get_src_buf() lexend = lexptr + 1; sourcefile->buf = buf; } else - lexeof = TRUE; + lexeof = true; return lexptr; } @@ -2538,7 +2638,7 @@ get_src_buf() error(_("can't open source file `%s' for reading (%s)"), in, strerror(errno)); errcount++; - lexeof = TRUE; + lexeof = true; return sourcefile->src; } @@ -2554,7 +2654,7 @@ get_src_buf() l = A_DECENT_BUFFER_SIZE; #undef A_DECENT_BUFFER_SIZE sourcefile->bufsize = l; - newfile = TRUE; + newfile = true; emalloc(sourcefile->buf, char *, sourcefile->bufsize, "get_src_buf"); lexptr = lexptr_begin = lexeme = sourcefile->buf; savelen = 0; @@ -2605,17 +2705,17 @@ get_src_buf() error(_("can't read sourcefile `%s' (%s)"), source, strerror(errno)); errcount++; - lexeof = TRUE; + lexeof = true; } else { lexend = lexptr + n; if (n == 0) { - static short warned = FALSE; + static bool warned = false; if (do_lint && newfile && ! warned){ - warned = TRUE; + warned = true; sourceline = 0; lintwarn(_("source file `%s' is empty"), source); } - lexeof = TRUE; + lexeof = true; } } return sourcefile->buf; @@ -2791,14 +2891,14 @@ static int newline_eof() pushback(); if (do_lint && ! eof_warned) { lintwarn(_("source file does not end in newline")); - eof_warned = TRUE; + eof_warned = true; } sourceline++; return NEWLINE; } sourceline--; - eof_warned = FALSE; + eof_warned = false; return LEX_EOF; } @@ -2808,14 +2908,16 @@ static int yylex(void) { int c; - int seen_e = FALSE; /* These are for numbers */ - int seen_point = FALSE; - int esc_seen; /* for literal strings */ + bool seen_e = false; /* These are for numbers */ + bool seen_point = false; + bool esc_seen; /* for literal strings */ int mid; - static int did_newline = FALSE; + int base; + static bool did_newline = false; char *tokkey; - int inhex = FALSE; - int intlstr = FALSE; + bool inhex = false; + bool intlstr = false; + AWKNUM d; #define GET_INSTRUCTION(op) bcalloc(op, 1, sourceline) @@ -2869,7 +2971,7 @@ yylex(void) * The code for \ handles \[ and \]. */ - want_regexp = FALSE; + want_regexp = false; tok = tokstart; for (;;) { c = nextc(); @@ -2986,10 +3088,10 @@ retry: while ((c = nextc()) == ' ' || c == '\t' || c == '\r') continue; if (c == '#') { - static short warned = FALSE; + static bool warned = false; if (do_lint && ! warned) { - warned = TRUE; + warned = true; lintwarn( _("use of `\\ #...' line continuation is not portable")); } @@ -3062,11 +3164,11 @@ retry: return lasttok = '*'; } else if (c == '*') { /* make ** and **= aliases for ^ and ^= */ - static int did_warn_op = FALSE, did_warn_assgn = FALSE; + static bool did_warn_op = false, did_warn_assgn = false; if (nextc() == '=') { if (! did_warn_assgn) { - did_warn_assgn = TRUE; + did_warn_assgn = true; if (do_lint) lintwarn(_("POSIX does not allow operator `**='")); if (do_lint_old) @@ -3077,7 +3179,7 @@ retry: } else { pushback(); if (! did_warn_op) { - did_warn_op = TRUE; + did_warn_op = true; if (do_lint) lintwarn(_("POSIX does not allow operator `**'")); if (do_lint_old) @@ -3111,11 +3213,11 @@ retry: case '^': { - static int did_warn_op = FALSE, did_warn_assgn = FALSE; + static bool did_warn_op = false, did_warn_assgn = false; if (nextc() == '=') { if (do_lint_old && ! did_warn_assgn) { - did_warn_assgn = TRUE; + did_warn_assgn = true; warning(_("operator `^=' is not supported in old awk")); } yylval = GET_INSTRUCTION(Op_assign_exp); @@ -3123,7 +3225,7 @@ retry: } pushback(); if (do_lint_old && ! did_warn_op) { - did_warn_op = TRUE; + did_warn_op = true; warning(_("operator `^' is not supported in old awk")); } yylval = GET_INSTRUCTION(Op_exp); @@ -3202,7 +3304,7 @@ retry: * hacking the grammar. */ if (did_newline) { - did_newline = FALSE; + did_newline = false; if (--in_braces == 0) lastline = sourceline; return lasttok = c; @@ -3213,7 +3315,7 @@ retry: case '"': string: - esc_seen = FALSE; + esc_seen = false; while ((c = nextc()) != '"') { if (c == '\n') { pushback(); @@ -3227,7 +3329,7 @@ retry: sourceline++; continue; } - esc_seen = TRUE; + esc_seen = true; if (! want_source || c != '"') tokadd('\\'); } @@ -3246,12 +3348,10 @@ retry: 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; + tok - tokstart, esc_seen ? SCAN : 0); if (intlstr) { yylval->memory->flags |= INTLSTR; - intlstr = FALSE; + intlstr = false; if (do_intl) dumpintlstr(yylval->memory->stptr, yylval->memory->stlen); } @@ -3290,7 +3390,7 @@ retry: case '9': /* It's a number */ for (;;) { - int gotnumber = FALSE; + bool gotnumber = false; tokadd(c); switch (c) { @@ -3302,7 +3402,7 @@ retry: int peek = nextc(); if (isxdigit(peek)) { - inhex = TRUE; + inhex = true; pushback(); /* following digit */ } else { pushback(); /* x or X */ @@ -3313,20 +3413,20 @@ retry: case '.': /* period ends exponent part of floating point number */ if (seen_point || seen_e) { - gotnumber = TRUE; + gotnumber = true; break; } - seen_point = TRUE; + seen_point = true; break; case 'e': case 'E': if (inhex) break; if (seen_e) { - gotnumber = TRUE; + gotnumber = true; break; } - seen_e = TRUE; + seen_e = true; if ((c = nextc()) == '-' || c == '+') { int c2 = nextc(); @@ -3371,7 +3471,7 @@ retry: break; default: done: - gotnumber = TRUE; + gotnumber = true; } if (gotnumber) break; @@ -3381,19 +3481,46 @@ retry: tokadd('\0'); yylval = GET_INSTRUCTION(Op_push_i); - if (! do_traditional && isnondecimal(tokstart, FALSE)) { + + base = 10; + if (! do_traditional) { + base = get_numbase(tokstart, false); if (do_lint) { - if (isdigit((unsigned char) tokstart[1])) /* not an 'x' or 'X' */ + if (base == 8) lintwarn("numeric constant `%.*s' treated as octal", (int) strlen(tokstart)-1, tokstart); - else if (tokstart[1] == 'x' || tokstart[1] == 'X') + else if (base == 16) lintwarn("numeric constant `%.*s' treated as hexadecimal", (int) strlen(tokstart)-1, tokstart); } - yylval->memory = mk_number(nondec2awknum(tokstart, strlen(tokstart)), - PERM|NUMCUR|NUMBER); - } else - yylval->memory = mk_number(atof(tokstart), PERM|NUMCUR|NUMBER); + } + +#ifdef HAVE_MPFR + if (do_mpfr) { + NODE *r; + + if (! seen_point && ! seen_e) { + r = mpg_integer(); + mpg_strtoui(r->mpg_i, tokstart, strlen(tokstart), NULL, base); + errno = 0; + } else { + int tval; + r = mpg_float(); + tval = mpfr_strtofr(r->mpg_numbr, tokstart, NULL, base, ROUND_MODE); + errno = 0; + IEEE_FMT(r->mpg_numbr, tval); + } + yylval->memory = r; + return lasttok = YNUMBER; + } +#endif + if (base != 10) + d = nondec2awknum(tokstart, strlen(tokstart)); + else + d = atof(tokstart); + yylval->memory = make_number(d); + if (d <= INT32_MAX && d >= INT32_MIN && d == (int32_t) d) + yylval->memory->flags |= NUMINT; return lasttok = YNUMBER; case '&': @@ -3449,7 +3576,7 @@ retry: */ if (! do_traditional && c == '_' && lasttok != '$') { if ((c = nextc()) == '"') { - intlstr = TRUE; + intlstr = true; goto string; } pushback(); @@ -3470,7 +3597,7 @@ retry: static int warntab[sizeof(tokentab) / sizeof(tokentab[0])]; int class = tokentab[mid].class; - if ((class == LEX_INCLUDE || class == LEX_EVAL) + if ((class == LEX_INCLUDE || class == LEX_LOAD || class == LEX_EVAL) && lasttok != '@') goto out; @@ -3501,7 +3628,8 @@ retry: switch (class) { case LEX_INCLUDE: - want_source = TRUE; + case LEX_LOAD: + want_source = true; break; case LEX_EVAL: if (in_main_context()) @@ -3525,14 +3653,36 @@ retry: case LEX_WHILE: case LEX_DO: case LEX_SWITCH: - if (! do_profiling) + if (! do_pretty_print) return lasttok = class; /* fall through */ case LEX_CASE: yylval = bcalloc(tokentab[mid].value, 2, sourceline); break; + /* + * These must be checked here, due to the LALR nature of the parser, + * the rules for continue and break may not be reduced until after + * a token that increments the xxx_allowed varibles is seen. Bleah. + */ + case LEX_CONTINUE: + if (! continue_allowed) { + error_ln(sourceline, + _("`continue' is not allowed outside a loop")); + errcount++; + } + goto make_instruction; + + case LEX_BREAK: + if (! break_allowed) { + error_ln(sourceline, + _("`break' is not allowed outside a loop or switch")); + errcount++; + } + goto make_instruction; + default: +make_instruction: yylval = GET_INSTRUCTION(tokentab[mid].value); if (class == LEX_BUILTIN || class == LEX_LENGTH) yylval->builtin_idx = mid; @@ -3547,7 +3697,7 @@ out: yylval->lextok = tokkey; return lasttok = FUNC_CALL; } else { - static short goto_warned = FALSE; + static bool goto_warned = false; yylval = GET_INSTRUCTION(Op_token); yylval->lextok = tokkey; @@ -3555,7 +3705,7 @@ out: #define SMART_ALECK 1 if (SMART_ALECK && do_lint && ! goto_warned && strcasecmp(tokkey, "goto") == 0) { - goto_warned = TRUE; + goto_warned = true; lintwarn(_("`goto' considered harmful!\n")); } return lasttok = NAME; @@ -3565,23 +3715,6 @@ out: #undef NEWLINE_EOF } -/* mk_symbol --- allocates a symbol for the symbol table. */ - -NODE * -mk_symbol(NODETYPE type, NODE *value) -{ - NODE *r; - - getnode(r); - r->type = type; - r->flags = MALLOC; - r->lnode = value; - r->rnode = NULL; - r->parent_array = NULL; - r->var_assign = (Func_ptr) 0; - return r; -} - /* snode --- instructions for builtin functions. Checks for arg. count and supplies defaults where possible. */ @@ -3633,7 +3766,7 @@ snode(INSTRUCTION *subn, INSTRUCTION *r) INSTRUCTION *expr; expr = list_create(instruction(Op_push_i)); - expr->nexti->memory = mk_number((AWKNUM) 0.0, (PERM|NUMCUR|NUMBER)); + expr->nexti->memory = make_number(0.0); (void) mk_expression_list(subn, list_append(expr, instruction(Op_field_spec))); } @@ -3650,10 +3783,10 @@ snode(INSTRUCTION *subn, INSTRUCTION *r) yyerror(_("%s third parameter is not a changeable object"), operator); else - ip->do_reference = TRUE; + ip->do_reference = true; } - r->expr_count = count_expressions(&subn, FALSE); + r->expr_count = count_expressions(&subn, false); ip = subn->lasti; (void) list_append(subn, r); @@ -3677,17 +3810,23 @@ snode(INSTRUCTION *subn, INSTRUCTION *r) r->sub_flags |= GENSUB; if (nexp == 3) { ip = instruction(Op_push_i); - ip->memory = mk_number((AWKNUM) 0.0, (PERM|NUMCUR|NUMBER)); + ip->memory = make_number(0.0); (void) mk_expression_list(subn, list_append(list_create(ip), instruction(Op_field_spec))); } - r->expr_count = count_expressions(&subn, FALSE); + r->expr_count = count_expressions(&subn, false); return list_append(subn, r); } } - r->builtin = tokentab[idx].ptr; +#ifdef HAVE_MPFR + /* N.B.: There isn't any special processing for an alternate function below */ + if (do_mpfr && tokentab[idx].ptr2) + r->builtin = tokentab[idx].ptr2; + else +#endif + r->builtin = tokentab[idx].ptr; /* special case processing for a few builtins */ @@ -3700,7 +3839,7 @@ snode(INSTRUCTION *subn, INSTRUCTION *r) 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)); + list->nexti->memory = make_number(0.0); return list; } else { arg = subn->nexti; @@ -3712,14 +3851,14 @@ snode(INSTRUCTION *subn, INSTRUCTION *r) if (arg->nexti == arg->lasti && arg->nexti->opcode == Op_push) arg->nexti->opcode = Op_push_arg; /* argument may be array */ } else if (r->builtin == do_match) { - static short warned = FALSE; + static bool warned = false; arg = subn->nexti->lasti->nexti; /* 2nd arg list */ (void) mk_rexp(arg); if (nexp == 3) { /* 3rd argument there */ if (do_lint && ! warned) { - warned = TRUE; + warned = true; lintwarn(_("match: third argument is a gawk extension")); } if (do_traditional) { @@ -3773,10 +3912,10 @@ snode(INSTRUCTION *subn, INSTRUCTION *r) ip->opcode = Op_push_array; } } else if (r->builtin == do_close) { - static short warned = FALSE; + static bool warned = false; if (nexp == 2) { if (do_lint && ! warned) { - warned = TRUE; + warned = true; lintwarn(_("close: second argument is a gawk extension")); } if (do_traditional) { @@ -3828,10 +3967,10 @@ snode(INSTRUCTION *subn, INSTRUCTION *r) if (ip->opcode == Op_push) ip->opcode = Op_push_array; } -#endif +#endif if (subn != NULL) { - r->expr_count = count_expressions(&subn, FALSE); + r->expr_count = count_expressions(&subn, false); return list_append(subn, r); } @@ -3839,75 +3978,6 @@ snode(INSTRUCTION *subn, INSTRUCTION *r) return list_create(r); } -/* append_param --- append PNAME to the list of parameters - * for the current function. - */ - -static void -append_param(char *pname) -{ - static NODE *savetail = NULL; - NODE *p; - - 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 */ - -static int -dup_parms(INSTRUCTION *fp, NODE *func) -{ - NODE *np; - const char *fname, **names; - int count, i, j, dups; - NODE *params; - - if (func == NULL) /* error earlier */ - return TRUE; - - fname = func->param; - count = func->param_cnt; - params = func->rnode; - - if (count == 0) /* no args, no problem */ - return FALSE; - - if (params == NULL) /* error earlier */ - return TRUE; - - emalloc(names, const char **, count * sizeof(char *), "dup_parms"); - - i = 0; - for (np = params; np != NULL; np = np->rnode) { - if (np->param == NULL) { /* error earlier, give up, go home */ - efree(names); - return TRUE; - } - names[i++] = np->param; - } - - dups = 0; - for (i = 1; i < count; i++) { - for (j = 0; j < i; j++) { - if (strcmp(names[i], names[j]) == 0) { - dups++; - error_ln(fp->source_line, - _("function `%s': parameter #%d, `%s', duplicates parameter #%d"), - fname, i + 1, names[j], j+1); - } - } - } - - efree(names); - return (dups > 0 ? TRUE : FALSE); -} /* parms_shadow --- check if parameters shadow globals */ @@ -3915,19 +3985,20 @@ static int parms_shadow(INSTRUCTION *pc, int *shadow) { int pcount, i; - int ret = FALSE; - NODE *func; + bool ret = false; + NODE *func, *fp; char *fname; func = pc->func_body; - fname = func->lnode->param; - + fname = func->vname; + fp = func->fparms; + #if 0 /* can't happen, already exited if error ? */ if (fname == NULL || func == NULL) /* error earlier */ - return FALSE; + return false; #endif - pcount = func->lnode->param_cnt; + pcount = func->param_cnt; if (pcount == 0) /* no args, no problem */ return 0; @@ -3939,11 +4010,11 @@ parms_shadow(INSTRUCTION *pc, int *shadow) * about all shadowed parameters. */ for (i = 0; i < pcount; i++) { - if (lookup(func->parmlist[i]) != NULL) { + if (lookup(fp[i].param) != NULL) { warning( _("function `%s': parameter `%s' shadows global variable"), - fname, func->parmlist[i]); - ret = TRUE; + fname, fp[i].param); + ret = true; } } @@ -3951,143 +4022,41 @@ parms_shadow(INSTRUCTION *pc, int *shadow) return 0; } - -/* - * 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_symbol(char *name, NODE *value) -{ - NODE *hp; - size_t len; - int bucket; - - if (install_func) - (*install_func)(name); - - var_count++; - len = strlen(name); - bucket = hash(name, len, (unsigned long) HASHSIZE, NULL); - getnode(hp); - hp->type = Node_hashnode; - hp->hnext = variables[bucket]; - variables[bucket] = hp; - hp->hlength = len; - hp->hvalue = value; - hp->hname = name; - hp->hvalue->vname = name; - return hp->hvalue; -} - -/* lookup --- find the most recent hash node for name installed by install_symbol */ - -NODE * -lookup(const char *name) -{ - 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 && strncmp(bucket->hname, name, len) == 0) - return bucket->hvalue; - return NULL; -} - -/* sym_comp --- compare two symbol (variable or function) names */ - -static int -sym_comp(const void *v1, const void *v2) -{ - const NODE *const *npp1, *const *npp2; - const NODE *n1, *n2; - int minlen; - - npp1 = (const NODE *const *) v1; - npp2 = (const NODE *const *) v2; - n1 = *npp1; - n2 = *npp2; - - if (n1->hlength > n2->hlength) - minlen = n1->hlength; - else - minlen = n2->hlength; - - return strncmp(n1->hname, n2->hname, minlen); -} - /* valinfo --- dump var info */ void -valinfo(NODE *n, int (*print_func)(FILE *, const char *, ...), FILE *fp) +valinfo(NODE *n, Func_print print_func, FILE *fp) { 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); + pp_string_fp(print_func, fp, n->stptr, n->stlen, '"', false); print_func(fp, "\n"); - } else if (n->flags & NUMBER) + } else if (n->flags & NUMBER) { +#ifdef HAVE_MPFR + if (is_mpg_float(n)) + print_func(fp, "%s\n", mpg_fmt("%.17R*g", ROUND_MODE, n->mpg_numbr)); + else if (is_mpg_integer(n)) + print_func(fp, "%s\n", mpg_fmt("%Zd", n->mpg_i)); + else +#endif print_func(fp, "%.17g\n", n->numbr); - else if (n->flags & STRCUR) { - pp_string_fp(print_func, fp, n->stptr, n->stlen, '"', FALSE); + } else if (n->flags & STRCUR) { + pp_string_fp(print_func, fp, n->stptr, n->stlen, '"', false); print_func(fp, "\n"); - } else if (n->flags & NUMCUR) + } else if (n->flags & NUMCUR) { +#ifdef HAVE_MPFR + if (is_mpg_float(n)) + print_func(fp, "%s\n", mpg_fmt("%.17R*g", ROUND_MODE, n->mpg_numbr)); + else if (is_mpg_integer(n)) + print_func(fp, "%s\n", mpg_fmt("%Zd", n->mpg_i)); + else +#endif print_func(fp, "%.17g\n", n->numbr); - else + } else print_func(fp, "?? flags %s\n", flags2str(n->flags)); } -/* get_varlist --- list of global variables */ - -NODE ** -get_varlist() -{ - int i, j; - NODE **table; - NODE *p; - - 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 *), sym_comp); - - table[j] = NULL; - return table; -} - -/* 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; - print_func(fp, "%.*s: ", (int) p->hlength, p->hname); - if (p->hvalue->type == Node_var_array) - print_func(fp, "array, %ld elements\n", p->hvalue->table_size); - else if (p->hvalue->type == Node_var_new) - print_func(fp, "untyped variable\n"); - else if (p->hvalue->type == Node_var) - valinfo(p->hvalue->var_value, print_func, fp); - } - efree(table); -} /* dump_vars --- dump the symbol table */ @@ -4095,6 +4064,7 @@ void dump_vars(const char *fname) { FILE *fp; + NODE **vars; if (fname == NULL) fp = stderr; @@ -4104,228 +4074,195 @@ dump_vars(const char *fname) fp = stderr; } - print_vars(fprintf, fp); + vars = variable_list(); + print_vars(vars, fprintf, fp); + efree(vars); if (fp != stderr && fclose(fp) != 0) warning(_("%s: close failed (%s)"), fname, strerror(errno)); } -/* release_all_vars --- free all variable memory */ - -void -release_all_vars() -{ - int i; - NODE *p, *next; - - for (i = 0; i < HASHSIZE; i++) { - for (p = variables[i]; p != NULL; p = next) { - next = p->hnext; - - if (p->hvalue->type == Node_func) - continue; - else if (p->hvalue->type == Node_var_array) - assoc_clear(p->hvalue); - else if (p->hvalue->type != Node_var_new) - unref(p->hvalue->var_value); - - efree(p->hname); - freenode(p->hvalue); - freenode(p); - } - } -} - /* dump_funcs --- print all functions */ void dump_funcs() { - if (func_count <= 0) - return; - - (void) foreach_func((int (*)(INSTRUCTION *, void *)) pp_func, TRUE, (void *) 0); + NODE **funcs; + funcs = function_list(true); + (void) foreach_func(funcs, (int (*)(INSTRUCTION *, void *)) pp_func, (void *) 0); + efree(funcs); } + /* shadow_funcs --- check all functions for parameters that shadow globals */ void shadow_funcs() { static int calls = 0; - int shadow = FALSE; - - if (func_count <= 0) - return; + bool shadow = false; + NODE **funcs; if (calls++ != 0) fatal(_("shadow_funcs() called twice!")); - (void) foreach_func((int (*)(INSTRUCTION *, void *)) parms_shadow, TRUE, &shadow); + funcs = function_list(true); + (void) foreach_func(funcs, (int (*)(INSTRUCTION *, void *)) parms_shadow, & shadow); + efree(funcs); /* End with fatal if the user requested it. */ if (shadow && lintfunc != warning) lintwarn(_("there were shadowed variables.")); } -/* - * 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 - * as value. - * - * Extra work, build up and save a list of the parameter names in a table - * and hang it off params->parmlist. This is used to set the `vname' field - * of each function parameter during a function call. See eval.c. + +/* mk_function --- finalize function definition node; remove parameters + * out of the symbol table. */ -static int -func_install(INSTRUCTION *func, INSTRUCTION *def) +static INSTRUCTION * +mk_function(INSTRUCTION *fi, INSTRUCTION *def) { - NODE *params; - NODE *r, *n, *thisfunc, *hp; - char **pnames = NULL; - char *fname; - int pcount = 0; - int i; + NODE *thisfunc; - params = func_params; + thisfunc = fi->func_body; + assert(thisfunc != NULL); - /* check for function foo(foo) { ... }. bleah. */ - for (n = params->rnode; n != NULL; n = n->rnode) { - if (strcmp(n->param, params->param) == 0) { - error_ln(func->source_line, - _("function `%s': can't use function name as parameter name"), params->param); - return -1; - } else if (is_std_var(n->param)) { - error_ln(func->source_line, - _("function `%s': can't use special variable `%s' as a function parameter"), - params->param, n->param); - return -1; - } - } + if (do_optimize > 1 && def->lasti->opcode == Op_pop) { + /* tail call which does not return any value. */ - thisfunc = NULL; /* turn off warnings */ + INSTRUCTION *t; - 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) { - error_ln(func->source_line, - _("function name `%s' previously defined"), fname); - return -1; - } else if (fname == builtin_func) /* not a valid function name */ - goto remove_params; + for (t = def->nexti; t->nexti != def->lasti; t = t->nexti) + ; + if (t->opcode == Op_func_call + && strcmp(t->func_name, thisfunc->vname) == 0) + (t + 1)->tail_call = true; + } /* 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; + def->lasti->memory = dupnode(Nnull_string); (void) list_append(def, instruction(Op_K_return)); - if (do_profiling) + if (do_pretty_print) (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; + /* fi->opcode = Op_func */ + (fi + 1)->firsti = def->nexti; + (fi + 1)->lasti = def->lasti; + (fi + 2)->first_line = fi->source_line; + (fi + 2)->last_line = lastline; + fi->nexti = def->nexti; bcfree(def); - (void) list_append(rule_list, func + 1); /* debugging */ - - /* install the function */ - thisfunc = mk_symbol(Node_func, params); - (void) install_symbol(fname, thisfunc); - thisfunc->code_ptr = func; - func->func_body = thisfunc; - - for (n = params->rnode; n != NULL; n = n->rnode) - pcount++; - - if (pcount != 0) { - 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; + (void) list_append(rule_list, fi + 1); /* debugging */ /* update lint table info */ - func_use(fname, FUNC_DEFINE); + func_use(thisfunc->vname, FUNC_DEFINE); - func_count++; /* used in profiler / pretty printer */ - -remove_params: /* remove params from symbol table */ - pop_params(params->rnode); - return 0; + remove_params(thisfunc); + return fi; } -/* remove_symbol --- remove a variable from the symbol table */ +/* + * install_function: + * install function name in the symbol table. + * Extra work, build up and install a list of the parameter names. + */ -NODE * -remove_symbol(char *name) +static int +install_function(char *fname, INSTRUCTION *fi, INSTRUCTION *plist) { - NODE *bucket, **save; - size_t len; + NODE *r, *f; + int pcount = 0; - len = strlen(name); - save = &(variables[hash(name, len, (unsigned long) HASHSIZE, NULL)]); - for (bucket = *save; bucket != NULL; bucket = bucket->hnext) { - if (len == bucket->hlength && strncmp(bucket->hname, name, len) == 0) { - var_count--; - *save = bucket->hnext; - return bucket; - } - save = &(bucket->hnext); + r = lookup(fname); + if (r != NULL) { + error_ln(fi->source_line, _("function name `%s' previously defined"), fname); + return -1; } - return NULL; + + if (plist != NULL) + pcount = plist->lasti->param_count + 1; + f = install_symbol(fname, Node_func); + fi->func_body = f; + f->param_cnt = pcount; + f->code_ptr = fi; + f->fparms = NULL; + if (pcount > 0) { + char **pnames; + pnames = check_params(fname, pcount, plist); /* frees plist */ + f->fparms = make_params(pnames, pcount); + efree(pnames); + install_params(f); + } + return 0; } -/* pop_params --- remove list of function parameters from symbol table */ -/* - * pop parameters out of the symbol table. do this in reverse order to - * avoid reading freed memory if there were duplicated parameters. +/* check_params --- build a list of function parameter names after + * making sure that the names are valid and there are no duplicates. */ -static void -pop_params(NODE *params) + +static char ** +check_params(char *fname, int pcount, INSTRUCTION *list) { - NODE *hp; - if (params == NULL) - return; - pop_params(params->rnode); - hp = remove_symbol(params->param); - if (hp != NULL) - freenode(hp); -} + INSTRUCTION *p, *np; + int i, j; + char *name; + char **pnames; -/* make_param --- make NAME into a function parameter */ + assert(pcount > 0); -static NODE * -make_param(char *name) -{ - NODE *r; + emalloc(pnames, char **, pcount * sizeof(char *), "check_params"); + + for (i = 0, p = list->nexti; p != NULL; i++, p = np) { + np = p->nexti; + name = p->lextok; + p->lextok = NULL; + + if (strcmp(name, fname) == 0) { + /* check for function foo(foo) { ... }. bleah. */ + error_ln(p->source_line, + _("function `%s': can't use function name as parameter name"), fname); + } else if (is_std_var(name)) { + error_ln(p->source_line, + _("function `%s': can't use special variable `%s' as a function parameter"), + fname, name); + } + + /* check for duplicate parameters */ + for (j = 0; j < i; j++) { + if (strcmp(name, pnames[j]) == 0) { + error_ln(p->source_line, + _("function `%s': parameter #%d, `%s', duplicates parameter #%d"), + fname, i + 1, name, j + 1); + } + } + + pnames[i] = name; + bcfree(p); + } + bcfree(list); - getnode(r); - r->type = Node_param_list; - r->rnode = NULL; - r->param_cnt = param_counter++; - return (install_symbol(name, r)); + return pnames; } + +#ifdef HASHSIZE +undef HASHSIZE +#endif +#define HASHSIZE 1021 + static struct fdesc { char *name; short used; short defined; + short extension; struct fdesc *next; } *ftable[HASHSIZE]; @@ -4345,7 +4282,10 @@ func_use(const char *name, enum defref how) if (strcmp(fp->name, name) == 0) { if (how == FUNC_DEFINE) fp->defined++; - else + else if (how == FUNC_EXT) { + fp->defined++; + fp->extension++; + } else fp->used++; return; } @@ -4359,12 +4299,23 @@ func_use(const char *name, enum defref how) strcpy(fp->name, name); if (how == FUNC_DEFINE) fp->defined++; - else + else if (how == FUNC_EXT) { + fp->defined++; + fp->extension++; + } else fp->used++; fp->next = ftable[ind]; ftable[ind] = fp; } +/* track_ext_func --- add an extension function to the table */ + +void +track_ext_func(const char *name) +{ + func_use(name, FUNC_EXT); +} + /* check_funcs --- verify functions that are called but not defined */ static void @@ -4378,19 +4329,19 @@ check_funcs() for (i = 0; i < HASHSIZE; i++) { for (fp = ftable[i]; fp != NULL; fp = fp->next) { + if (fp->defined == 0 && ! fp->extension) { #ifdef REALLYMEAN - /* making this the default breaks old code. sigh. */ - if (fp->defined == 0) { + /* making this the default breaks old code. sigh. */ error( _("function `%s' called but never defined"), fp->name); errcount++; - } #else - if (do_lint && fp->defined == 0) lintwarn( _("function `%s' called but never defined"), fp->name); #endif - if (do_lint && fp->used == 0) { + } + + if (do_lint && fp->used == 0 && ! fp->extension) { lintwarn(_("function `%s' defined but never called directly"), fp->name); } @@ -4429,69 +4380,6 @@ param_sanity(INSTRUCTION *arglist) } } -/* 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. */ /* @@ -4526,31 +4414,26 @@ register_deferred_variable(const char *name, NODE *(*load_func)(void)) /* variable --- make sure NAME is in the symbol table */ NODE * -variable(char *name, NODETYPE type) +variable(int location, char *name, NODETYPE type) { NODE *r; if ((r = lookup(name)) != NULL) { - if (r->type == Node_func) { - error(_("function `%s' called with space between name and `(',\nor used as a variable or an array"), + if (r->type == Node_func || r->type == Node_ext_func ) + error_ln(location, _("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 */ - } + if (r == symbol_table) + symtab_used = true; } else { /* not found */ struct deferred_variable *dv; - for (dv = deferred_variables; TRUE; dv = dv->next) { + for (dv = deferred_variables; true; dv = dv->next) { if (dv == 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 - r = mk_symbol(type, (NODE *) NULL); - return install_symbol(name, r); + /* + * This is the only case in which we may not free the string. + */ + return install_symbol(name, type); } if (strcmp(name, dv->name) == 0) { r = (*dv->load_func)(); @@ -4562,6 +4445,21 @@ variable(char *name, NODETYPE type) return r; } +/* process_deferred --- if the program uses SYMTAB, load deferred variables */ + +static void +process_deferred() +{ + struct deferred_variable *dv; + + if (! symtab_used) + return; + + for (dv = deferred_variables; dv != NULL; dv = dv->next) { + (void) dv->load_func(); + } +} + /* make_regnode --- make a regular expression node */ static NODE * @@ -4575,7 +4473,7 @@ make_regnode(int type, NODE *exp) n->re_cnt = 1; if (type == Node_regex) { - n->re_reg = make_regexp(exp->stptr, exp->stlen, FALSE, TRUE, FALSE); + n->re_reg = make_regexp(exp->stptr, exp->stlen, false, true, false); if (n->re_reg == NULL) { freenode(n); return NULL; @@ -4642,12 +4540,12 @@ isnoeffect(OPCODE type) case Op_match_rec: case Op_not: case Op_in_array: - return TRUE; + return true; default: break; /* keeps gcc -Wall happy */ } - return FALSE; + return false; } /* make_assignable --- make this operand an assignable one if posiible */ @@ -4657,9 +4555,6 @@ make_assignable(INSTRUCTION *ip) { 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: @@ -4679,7 +4574,7 @@ make_assignable(INSTRUCTION *ip) NODE * stopme(int nargs ATTRIBUTE_UNUSED) { - return (NODE *) 0; + return make_number(0.0); } /* dumpintlstr --- write out an initial .po file entry for the string */ @@ -4699,7 +4594,7 @@ dumpintlstr(const char *str, size_t len) } printf("msgid "); - pp_string_fp(fprintf, stdout, str, len, '"', TRUE); + pp_string_fp(fprintf, stdout, str, len, '"', true); putchar('\n'); printf("msgstr \"\"\n\n"); fflush(stdout); @@ -4722,36 +4617,15 @@ dumpintlstr2(const char *str1, size_t len1, const char *str2, size_t len2) } printf("msgid "); - pp_string_fp(fprintf, stdout, str1, len1, '"', TRUE); + pp_string_fp(fprintf, stdout, str1, len1, '"', true); putchar('\n'); printf("msgid_plural "); - pp_string_fp(fprintf, stdout, str2, len2, '"', TRUE); + pp_string_fp(fprintf, stdout, str2, len2, '"', true); putchar('\n'); printf("msgstr[0] \"\"\nmsgstr[1] \"\"\n\n"); fflush(stdout); } -/* isarray --- can this type be subscripted? */ - -static int -isarray(NODE *n) -{ - switch (n->type) { - case Node_var_new: - case Node_var_array: - return TRUE; - case Node_param_list: - return (n->flags & FUNC) == 0; - case Node_array_ref: - cant_happen(); - break; - default: - break; /* keeps gcc -Wall happy */ - } - - return FALSE; -} - /* mk_binary --- instructions for binary operators */ static INSTRUCTION * @@ -4766,11 +4640,11 @@ mk_binary(INSTRUCTION *s1, INSTRUCTION *s2, INSTRUCTION *op) ip1 = s1->nexti; if (do_optimize > 1 && ip1 == s1->lasti && ip1->opcode == Op_push_i - && (ip1->memory->flags & (STRCUR|STRING)) == 0 - && (ip2->memory->flags & (STRCUR|STRING)) == 0 + && (ip1->memory->flags & (MPFN|MPZN|STRCUR|STRING)) == 0 + && (ip2->memory->flags & (MPFN|MPZN|STRCUR|STRING)) == 0 ) { NODE *n1 = ip1->memory, *n2 = ip2->memory; - res = force_number(n1); + res = force_number(n1)->numbr; (void) force_number(n2); switch (op->opcode) { case Op_times: @@ -4812,11 +4686,7 @@ mk_binary(INSTRUCTION *s1, INSTRUCTION *s2, INSTRUCTION *op) } op->opcode = Op_push_i; - op->memory = mk_number(res, (PERM|NUMCUR|NUMBER)); - n1->flags &= ~PERM; - n1->flags |= MALLOC; - n2->flags &= ~PERM; - n2->flags |= MALLOC; + op->memory = make_number(res); unref(n1); unref(n2); bcfree(ip1); @@ -4942,7 +4812,7 @@ mk_condition(INSTRUCTION *cond, INSTRUCTION *ifp, INSTRUCTION *true_branch, if (false_branch == NULL) { false_branch = list_create(instruction(Op_no_op)); if (elsep != NULL) { /* else { } */ - if (do_profiling) + if (do_pretty_print) (void) list_prepend(false_branch, elsep); else bcfree(elsep); @@ -4953,7 +4823,7 @@ mk_condition(INSTRUCTION *cond, INSTRUCTION *ifp, INSTRUCTION *true_branch, /* 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)); - if (do_profiling) { + if (do_pretty_print) { (void) list_prepend(false_branch, elsep); false_branch->nexti->branch_end = false_branch->lasti; (void) list_prepend(false_branch, instruction(Op_exec_count)); @@ -4968,7 +4838,7 @@ mk_condition(INSTRUCTION *cond, INSTRUCTION *ifp, INSTRUCTION *true_branch, ip = list_append(cond, instruction(Op_jmp_false)); ip->lasti->target_jmp = false_branch->nexti->nexti; - if (do_profiling) { + if (do_pretty_print) { (void) list_prepend(ip, ifp); (void) list_append(ip, instruction(Op_exec_count)); ip->nexti->branch_if = ip->lasti; @@ -5030,7 +4900,7 @@ append_rule(INSTRUCTION *pattern, INSTRUCTION *action) if (rule != Rule) { rp = pattern; - if (do_profiling) + if (do_pretty_print) (void) list_append(action, instruction(Op_no_op)); (rp + 1)->firsti = action->nexti; (rp + 1)->lasti = action->lasti; @@ -5046,7 +4916,7 @@ append_rule(INSTRUCTION *pattern, INSTRUCTION *action) if (pattern == NULL) { /* assert(action != NULL); */ - if (do_profiling) + if (do_pretty_print) (void) list_prepend(action, instruction(Op_exec_count)); (rp + 1)->firsti = action->nexti; (rp + 1)->lasti = tp; @@ -5062,12 +4932,12 @@ append_rule(INSTRUCTION *pattern, INSTRUCTION *action) if (action == NULL) { (rp + 2)->last_line = find_line(pattern, LAST_LINE); action = list_create(instruction(Op_K_print_rec)); - if (do_profiling) + if (do_pretty_print) (void) list_prepend(action, instruction(Op_exec_count)); } else (rp + 2)->last_line = lastline; - if (do_profiling) { + if (do_pretty_print) { (void) list_prepend(pattern, instruction(Op_exec_count)); (void) list_prepend(action, instruction(Op_exec_count)); } @@ -5128,7 +4998,7 @@ mk_assignment(INSTRUCTION *lhs, INSTRUCTION *rhs, INSTRUCTION *op) && tp->memory->type == Node_var && tp->memory->var_assign ) { - tp->do_reference = FALSE; /* no uninitialized reference checking + tp->do_reference = false; /* no uninitialized reference checking * for a special variable. */ (void) list_append(ip, instruction(Op_var_assign)); @@ -5147,9 +5017,7 @@ mk_assignment(INSTRUCTION *lhs, INSTRUCTION *rhs, INSTRUCTION *op) static INSTRUCTION * optimize_assignment(INSTRUCTION *exp) { - INSTRUCTION *i1; - INSTRUCTION *i2; - INSTRUCTION *i3; + INSTRUCTION *i1, *i2, *i3; /* * Optimize assignment statements array[subs] = x; var = x; $n = x; @@ -5185,7 +5053,7 @@ optimize_assignment(INSTRUCTION *exp) 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) { @@ -5270,13 +5138,26 @@ optimize_assignment(INSTRUCTION *exp) case Op_push_lhs: if (i2->nexti == i1 - && i1->opcode == Op_assign + && i1->opcode == Op_assign ) { /* var = .. */ i2->opcode = Op_store_var; i2->nexti = NULL; bcfree(i1); /* Op_assign */ exp->lasti = i2; /* update Op_list */ + + i3 = exp->nexti; + if (i3->opcode == Op_push_i + && (i3->memory->flags & INTLSTR) == 0 + && i3->nexti == i2 + ) { + /* constant initializer */ + i2->initval = i3->memory; + bcfree(i3); + exp->nexti = i2; + } else + i2->initval = NULL; + return exp; } break; @@ -5346,7 +5227,7 @@ mk_getline(INSTRUCTION *op, INSTRUCTION *var, INSTRUCTION *redir, int redirtype) else ip = list_create(op); op->into_var = (var != NULL); - op->redir_type = (redir != NULL) ? redirtype : 0; + op->redir_type = (redir != NULL) ? redirtype : redirect_none; return (asgn == NULL ? ip : list_append(ip, asgn)); } @@ -5397,7 +5278,7 @@ mk_for_loop(INSTRUCTION *forp, INSTRUCTION *init, INSTRUCTION *cond, if (init != NULL) ip = list_merge(init, ip); - if (do_profiling) { + if (do_pretty_print) { (void) list_append(ip, instruction(Op_exec_count)); (forp + 1)->forloop_cond = pp_cond; (forp + 1)->forloop_body = ip->lasti; @@ -5419,7 +5300,7 @@ mk_for_loop(INSTRUCTION *forp, INSTRUCTION *init, INSTRUCTION *cond, ret = list_append(ip, tbreak); fix_break_continue(ret, tbreak, tcont); - if (do_profiling) { + if (do_pretty_print) { forp->target_break = tbreak; forp->target_continue = tcont; ret = list_prepend(ret, forp); @@ -5520,7 +5401,7 @@ mk_expression_list(INSTRUCTION *list, INSTRUCTION *s1) */ static int -count_expressions(INSTRUCTION **list, int isarg) +count_expressions(INSTRUCTION **list, bool isarg) { INSTRUCTION *expr; INSTRUCTION *r = NULL; @@ -5578,320 +5459,6 @@ fix_break_continue(INSTRUCTION *list, INSTRUCTION *b_target, INSTRUCTION *c_targ } } - -/* 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; -} - -/* release_symbol --- free symbol list and optionally remove symbol from symbol table */ - -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 parse 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 AWK_CONTEXT *curr_ctxt = NULL; - -/* new_context --- create a new execution context. */ - -AWK_CONTEXT * -new_context() -{ - AWK_CONTEXT *ctxt; - - emalloc(ctxt, AWK_CONTEXT *, sizeof(AWK_CONTEXT), "new_context"); - memset(ctxt, 0, sizeof(AWK_CONTEXT)); - ctxt->srcfiles.next = ctxt->srcfiles.prev = &ctxt->srcfiles; - ctxt->rule_list.opcode = Op_list; - ctxt->rule_list.lasti = &ctxt->rule_list; - return ctxt; -} - -/* set_context --- change current execution context. */ - -static void -set_context(AWK_CONTEXT *ctxt) -{ - pool_list = &ctxt->pools; - symbol_list = &ctxt->symbols; - srcfiles = &ctxt->srcfiles; - rule_list = &ctxt->rule_list; - install_func = ctxt->install_func; - curr_ctxt = ctxt; -} - -/* - * push_context: - * - * Switch to the given context after saving the current one. The set - * of active execution contexts forms a stack; the global or main context - * is at the bottom of the stack. - */ - -void -push_context(AWK_CONTEXT *ctxt) -{ - ctxt->prev = curr_ctxt; - /* save current source and sourceline */ - if (curr_ctxt != NULL) { - curr_ctxt->sourceline = sourceline; - curr_ctxt->source = source; - } - sourceline = 0; - source = NULL; - set_context(ctxt); -} - -/* pop_context --- switch to previous execution context. */ - -void -pop_context() -{ - AWK_CONTEXT *ctxt; - - assert(curr_ctxt != NULL); - ctxt = curr_ctxt->prev; - /* restore source and sourceline */ - sourceline = ctxt->sourceline; - source = ctxt->source; - set_context(ctxt); -} - -/* in_main_context --- are we in the main context ? */ - -int -in_main_context() -{ - assert(curr_ctxt != NULL); - return (curr_ctxt->prev == NULL); -} - -/* free_context --- free context structure and related data. */ - -void -free_context(AWK_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); -} - -/* free_bc_internal --- free internal memory of an instruction. */ - -static void -free_bc_internal(INSTRUCTION *cp) -{ - 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_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; -} - -/* free_bcpool --- free list of instruction memory pools */ - -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) { @@ -5950,13 +5517,13 @@ check_special(const char *name) int low, high, mid; int i; #if 'a' == 0x81 /* it's EBCDIC */ - static int did_sort = FALSE; + static bool did_sort = false; if (! did_sort) { qsort((void *) tokentab, sizeof(tokentab) / sizeof(tokentab[0]), sizeof(tokentab[0]), tokcompare); - did_sort = TRUE; + did_sort = true; } #endif @@ -6028,3 +5595,4 @@ one_line_close(int fd) return ret; } + |