diff options
Diffstat (limited to 'awkgram.y')
-rw-r--r-- | awkgram.y | 506 |
1 files changed, 332 insertions, 174 deletions
@@ -52,6 +52,7 @@ 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 include_source(INSTRUCTION *file); +static int load_library(INSTRUCTION *file); static void next_sourcefile(void); static char *tokexpand(void); @@ -71,20 +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 ssize_t read_one_line(int fd, void *buffer, size_t count); static int one_line_close(int fd); -static int want_source = FALSE; -static int want_regexp; /* lexical scanning 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[] = { @@ -96,25 +100,24 @@ 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 @@ -164,7 +167,7 @@ extern double fmod(double x, double y); %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 */ @@ -200,6 +203,8 @@ program | program LEX_EOF { next_sourcefile(); + if (sourcefile == srcfiles) + process_deferred(); } | program error { @@ -236,7 +241,12 @@ rule } | '@' LEX_INCLUDE source statement_term { - want_source = FALSE; + want_source = false; + yyerrok; + } + | '@' LEX_LOAD library statement_term + { + want_source = false; yyerrok; } ; @@ -256,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; } @@ -270,7 +295,7 @@ pattern tp = instruction(Op_no_op); list_prepend($1, bcalloc(Op_line_range, !!do_pretty_print + 1, 0)); - $1->nexti->triggered = FALSE; + $1->nexti->triggered = false; $1->nexti->target_jmp = $4->nexti; list_append($1, instruction(Op_cond_pair)); @@ -373,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; @@ -387,7 +412,7 @@ regexp 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); @@ -494,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; @@ -788,10 +813,6 @@ non_compound_stmt } | LEX_NEXTFILE statement_term { - if (do_traditional) - error_ln($1->source_line, - _("`nextfile' is a gawk extension")); - /* if inside function (rule = 0), resolve context at run-time */ if (rule == BEGIN || rule == END || rule == ENDFILE) error_ln($1->source_line, @@ -834,7 +855,7 @@ non_compound_stmt * call without a return value is recognized * in mk_function(). */ - ($3->lasti + 1)->tail_call = TRUE; + ($3->lasti + 1)->tail_call = true; } $$ = list_append($3, $1); @@ -852,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. @@ -868,7 +889,7 @@ simple_stmt && $3->nexti->nexti->memory->type == Node_val) ) ) { - static short warned = FALSE; + static bool warned = false; /* ----------------- * output_redir * [ redirect exp ] @@ -891,7 +912,7 @@ simple_stmt 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 \"\"'")); } @@ -900,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; @@ -924,12 +945,12 @@ 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 { @@ -943,7 +964,7 @@ regular_print: $$ = 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); } } @@ -957,17 +978,25 @@ regular_print: $2->opcode = Op_push_array; $2->memory = variable($2->source_line, arr, Node_var_new); - if ($4 == NULL) { - static short warned = FALSE; + 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 (do_lint && ! warned) { - warned = TRUE; - lintwarn_ln($1->source_line, - _("`delete array' is a gawk extension")); - } - if (do_traditional) - error_ln($1->source_line, - _("`delete array' is a gawk extension")); + if ($4 == NULL) { + /* + * As of September 2012, POSIX has added support + * for `delete array'. See: + * http://austingroupbugs.net/view.php?id=544 + * + * Thanks to Nathan Weeks for the initiative. + * + * Thus we no longer warn or check do_posix. + * Also, since BWK awk supports it, we don't have to + * check do_traditional either. + */ $1->expr_count = 0; $$ = list_append(list_create($2), $1); } else { @@ -981,22 +1010,29 @@ regular_print: * 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")); } if (do_traditional) { error_ln($1->source_line, - _("`delete array' is a gawk extension")); + _("`delete(array)' is a non-portable tawk extension")); } $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); } @@ -1096,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 @@ -1288,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 */ @@ -1398,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); } } @@ -1480,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")); } @@ -1550,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); } @@ -1590,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); } } @@ -1648,7 +1684,7 @@ bracketed_exp_list 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); } ; @@ -1802,7 +1838,7 @@ static const struct token tokentab[] = { #ifdef ARRAYDEBUG {"adump", Op_builtin, LEX_BUILTIN, GAWKX|A(1)|A(2), do_adump, 0}, #endif -{"and", Op_builtin, LEX_BUILTIN, GAWKX|A(2), do_and, MPF(and)}, +{"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)}, @@ -1837,13 +1873,14 @@ static const struct token tokentab[] = { {"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, GAWKX, 0, 0}, -{"or", Op_builtin, LEX_BUILTIN, GAWKX|A(2), do_or, MPF(or)}, +{"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}, @@ -1855,6 +1892,9 @@ static const struct token tokentab[] = { {"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, 0}, +#endif {"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}, @@ -1865,7 +1905,7 @@ static const struct token tokentab[] = { {"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|A(2), do_xor, MPF(xor)}, +{"xor", Op_builtin, LEX_BUILTIN, GAWKX, do_xor, MPF(xor)}, }; #if MBS_SUPPORT @@ -1963,7 +2003,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; } @@ -1981,9 +2021,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) @@ -2003,7 +2043,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; } @@ -2081,7 +2121,7 @@ yyerror(const char *m, ...) *bp++ = ' '; } strcpy(bp, mesg); - err("", buf, args); + err(false, "", buf, args); va_end(args); efree(buf); } @@ -2122,7 +2162,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); } @@ -2227,7 +2267,7 @@ parse_program(INSTRUCTION **pcode) sourcefile = sourcefile->next) ; - lexeof = FALSE; + lexeof = false; lexptr = NULL; lasttok = 0; memset(rule_block, 0, sizeof(ruletab) * sizeof(INSTRUCTION *)); @@ -2276,7 +2316,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; @@ -2284,7 +2324,7 @@ 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) @@ -2296,29 +2336,49 @@ add_srcfile(int stype, char *src, SRCFILE *thisfile, int *already_included, int *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 || s->stype == SRC_EXTLIB) - && 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; } } @@ -2336,7 +2396,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")); @@ -2373,8 +2433,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; } @@ -2401,11 +2496,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 */ @@ -2449,7 +2544,7 @@ get_src_buf() { int n; char *scan; - int newfile; + bool newfile; int savelen; struct stat sbuf; @@ -2474,7 +2569,7 @@ get_src_buf() readfunc = read_one_line; } - newfile = FALSE; + newfile = false; if (sourcefile == srcfiles) return NULL; @@ -2490,13 +2585,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') { /* @@ -2524,7 +2619,7 @@ get_src_buf() lexend = lexptr + 1; sourcefile->buf = buf; } else - lexeof = TRUE; + lexeof = true; return lexptr; } @@ -2545,7 +2640,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; } @@ -2561,7 +2656,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; @@ -2612,17 +2707,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; @@ -2798,14 +2893,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; } @@ -2815,15 +2910,15 @@ 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; int base; - static int did_newline = FALSE; + 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) @@ -2878,7 +2973,7 @@ yylex(void) * The code for \ handles \[ and \]. */ - want_regexp = FALSE; + want_regexp = false; tok = tokstart; for (;;) { c = nextc(); @@ -2995,10 +3090,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")); } @@ -3071,11 +3166,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) @@ -3086,7 +3181,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) @@ -3120,11 +3215,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); @@ -3132,7 +3227,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); @@ -3211,7 +3306,7 @@ retry: * hacking the grammar. */ if (did_newline) { - did_newline = FALSE; + did_newline = false; if (--in_braces == 0) lastline = sourceline; return lasttok = c; @@ -3222,7 +3317,7 @@ retry: case '"': string: - esc_seen = FALSE; + esc_seen = false; while ((c = nextc()) != '"') { if (c == '\n') { pushback(); @@ -3236,7 +3331,7 @@ retry: sourceline++; continue; } - esc_seen = TRUE; + esc_seen = true; if (! want_source || c != '"') tokadd('\\'); } @@ -3258,7 +3353,7 @@ retry: 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); } @@ -3297,7 +3392,7 @@ retry: case '9': /* It's a number */ for (;;) { - int gotnumber = FALSE; + bool gotnumber = false; tokadd(c); switch (c) { @@ -3309,7 +3404,7 @@ retry: int peek = nextc(); if (isxdigit(peek)) { - inhex = TRUE; + inhex = true; pushback(); /* following digit */ } else { pushback(); /* x or X */ @@ -3320,20 +3415,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(); @@ -3378,7 +3473,7 @@ retry: break; default: done: - gotnumber = TRUE; + gotnumber = true; } if (gotnumber) break; @@ -3391,7 +3486,7 @@ retry: base = 10; if (! do_traditional) { - base = get_numbase(tokstart, FALSE); + base = get_numbase(tokstart, false); if (do_lint) { if (base == 8) lintwarn("numeric constant `%.*s' treated as octal", @@ -3483,7 +3578,7 @@ retry: */ if (! do_traditional && c == '_' && lasttok != '$') { if ((c = nextc()) == '"') { - intlstr = TRUE; + intlstr = true; goto string; } pushback(); @@ -3504,7 +3599,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; @@ -3540,7 +3635,8 @@ retry: switch (class) { case LEX_INCLUDE: - want_source = TRUE; + case LEX_LOAD: + want_source = true; break; case LEX_EVAL: if (in_main_context()) @@ -3571,7 +3667,29 @@ retry: 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; @@ -3586,7 +3704,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; @@ -3594,7 +3712,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; @@ -3672,10 +3790,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); @@ -3708,7 +3826,7 @@ snode(INSTRUCTION *subn, INSTRUCTION *r) 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); } } @@ -3744,14 +3862,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) { @@ -3805,10 +3923,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) { @@ -3863,7 +3981,7 @@ snode(INSTRUCTION *subn, INSTRUCTION *r) #endif if (subn != NULL) { - r->expr_count = count_expressions(&subn, FALSE); + r->expr_count = count_expressions(&subn, false); return list_append(subn, r); } @@ -3878,7 +3996,7 @@ static int parms_shadow(INSTRUCTION *pc, int *shadow) { int pcount, i; - int ret = FALSE; + bool ret = false; NODE *func, *fp; char *fname; @@ -3888,7 +4006,7 @@ parms_shadow(INSTRUCTION *pc, int *shadow) #if 0 /* can't happen, already exited if error ? */ if (fname == NULL || func == NULL) /* error earlier */ - return FALSE; + return false; #endif pcount = func->param_cnt; @@ -3907,7 +4025,7 @@ parms_shadow(INSTRUCTION *pc, int *shadow) warning( _("function `%s': parameter `%s' shadows global variable"), fname, fp[i].param); - ret = TRUE; + ret = true; } } @@ -3923,7 +4041,7 @@ 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) { #ifdef HAVE_MPFR @@ -3935,7 +4053,7 @@ valinfo(NODE *n, Func_print print_func, FILE *fp) #endif print_func(fp, "%.17g\n", n->numbr); } else if (n->flags & STRCUR) { - 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 & NUMCUR) { #ifdef HAVE_MPFR @@ -3980,7 +4098,7 @@ void dump_funcs() { NODE **funcs; - funcs = function_list(TRUE); + funcs = function_list(true); (void) foreach_func(funcs, (int (*)(INSTRUCTION *, void *)) pp_func, (void *) 0); efree(funcs); } @@ -3992,13 +4110,13 @@ void shadow_funcs() { static int calls = 0; - int shadow = FALSE; + bool shadow = false; NODE **funcs; if (calls++ != 0) fatal(_("shadow_funcs() called twice!")); - funcs = function_list(TRUE); + funcs = function_list(true); (void) foreach_func(funcs, (int (*)(INSTRUCTION *, void *)) parms_shadow, & shadow); efree(funcs); @@ -4029,7 +4147,7 @@ mk_function(INSTRUCTION *fi, INSTRUCTION *def) ; if (t->opcode == Op_func_call && strcmp(t->func_name, thisfunc->vname) == 0) - (t + 1)->tail_call = TRUE; + (t + 1)->tail_call = true; } /* add an implicit return at end; @@ -4155,6 +4273,7 @@ static struct fdesc { char *name; short used; short defined; + short extension; struct fdesc *next; } *ftable[HASHSIZE]; @@ -4174,7 +4293,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; } @@ -4188,12 +4310,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 @@ -4207,19 +4340,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); } @@ -4300,15 +4433,17 @@ variable(int location, char *name, NODETYPE type) 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); + 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. - */ + /* + * This is the only case in which we may not free the string. + */ return install_symbol(name, type); } if (strcmp(name, dv->name) == 0) { @@ -4321,6 +4456,21 @@ variable(int location, 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 * @@ -4334,7 +4484,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; @@ -4401,12 +4551,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 */ @@ -4430,6 +4580,14 @@ make_assignable(INSTRUCTION *ip) return NULL; } +/* stopme --- for debugging */ + +NODE * +stopme(int nargs ATTRIBUTE_UNUSED) +{ + return make_number(0.0); +} + /* dumpintlstr --- write out an initial .po file entry for the string */ static void @@ -4447,7 +4605,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); @@ -4470,10 +4628,10 @@ 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); @@ -4851,7 +5009,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)); @@ -5086,7 +5244,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)); } @@ -5260,7 +5418,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; @@ -5376,13 +5534,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 |