diff options
Diffstat (limited to 'mrbgems/mruby-compiler/core/parse.y')
| -rw-r--r-- | mrbgems/mruby-compiler/core/parse.y | 276 |
1 files changed, 221 insertions, 55 deletions
diff --git a/mrbgems/mruby-compiler/core/parse.y b/mrbgems/mruby-compiler/core/parse.y index d143344c3..b7d47118f 100644 --- a/mrbgems/mruby-compiler/core/parse.y +++ b/mrbgems/mruby-compiler/core/parse.y @@ -220,6 +220,26 @@ parser_strdup(parser_state *p, const char *s) #undef strdup #define strdup(s) parser_strdup(p, s) +static void +dump_int(short i, char *s) +{ + char *p = s; + char *t = s; + + while (i > 0) { + *p++ = (i % 10)+'0'; + i /= 10; + } + if (p == s) *p++ = '0'; + *p = 0; + p--; /* point the last char */ + while (t < p) { + char c = *t; + *t++ = *p; + *p-- = c; + } +} + /* xxx ----------------------------- */ static node* @@ -283,6 +303,20 @@ local_add(parser_state *p, mrb_sym sym) } } +static void +local_add_blk(parser_state *p, mrb_sym blk) +{ + /* allocate register for block */ + local_add_f(p, blk ? blk : mrb_intern_lit(p->mrb, "&")); +} + +static void +local_add_kw(parser_state *p, mrb_sym kwd) +{ + /* allocate register for keywords hash */ + local_add_f(p, kwd ? kwd : mrb_intern_lit(p->mrb, "**")); +} + static node* locals_node(parser_state *p) { @@ -726,13 +760,11 @@ new_args_tail(parser_state *p, node *kws, node *kwrest, mrb_sym blk) { node *k; - /* allocate register for keywords hash */ if (kws || kwrest) { - local_add_f(p, (kwrest && kwrest->cdr)? sym(kwrest->cdr) : mrb_intern_lit(p->mrb, "**")); + local_add_kw(p, (kwrest && kwrest->cdr)? sym(kwrest->cdr) : 0); } - /* allocate register for block */ - local_add_f(p, blk? blk : mrb_intern_lit(p->mrb, "&")); + local_add_blk(p, blk); // allocate register for keywords arguments // order is for Proc#parameters @@ -795,6 +827,13 @@ new_masgn(parser_state *p, node *a, node *b) return cons((node*)NODE_MASGN, cons(a, b)); } +/* (:masgn mlhs mrhs) no check */ +static node* +new_masgn_param(parser_state *p, node *a, node *b) +{ + return cons((node*)NODE_MASGN, cons(a, b)); +} + /* (:asgn lhs rhs) */ static node* new_op_asgn(parser_state *p, node *a, mrb_sym op, node *b) @@ -833,6 +872,86 @@ new_dstr(parser_state *p, node *a) return cons((node*)NODE_DSTR, a); } +static int +string_node_p(node *n) +{ + return (int)((enum node_type)(intptr_t)n->car == NODE_STR); +} + +static node* +composite_string_node(parser_state *p, node *a, node *b) +{ + size_t newlen = (size_t)a->cdr + (size_t)b->cdr; + char *str = (char*)mrb_pool_realloc(p->pool, a->car, (size_t)a->cdr + 1, newlen + 1); + memcpy(str + (size_t)a->cdr, b->car, (size_t)b->cdr); + str[newlen] = '\0'; + a->car = (node*)str; + a->cdr = (node*)newlen; + cons_free(b); + return a; +} + +static node* +concat_string(parser_state *p, node *a, node *b) +{ + if (string_node_p(a)) { + if (string_node_p(b)) { + /* a == NODE_STR && b == NODE_STR */ + composite_string_node(p, a->cdr, b->cdr); + cons_free(b); + return a; + } + else { + /* a == NODE_STR && b == NODE_DSTR */ + + if (string_node_p(b->cdr->car)) { + /* a == NODE_STR && b->[NODE_STR, ...] */ + composite_string_node(p, a->cdr, b->cdr->car->cdr); + cons_free(b->cdr->car); + b->cdr->car = a; + return b; + } + } + } + else { + node *c; /* last node of a */ + for (c = a; c->cdr != NULL; c = c->cdr) ; + + if (string_node_p(b)) { + /* a == NODE_DSTR && b == NODE_STR */ + if (string_node_p(c->car)) { + /* a->[..., NODE_STR] && b == NODE_STR */ + composite_string_node(p, c->car->cdr, b->cdr); + cons_free(b); + return a; + } + + push(a, b); + return a; + } + else { + /* a == NODE_DSTR && b == NODE_DSTR */ + if (string_node_p(c->car) && string_node_p(b->cdr->car)) { + /* a->[..., NODE_STR] && b->[NODE_STR, ...] */ + node *d = b->cdr; + cons_free(b); + composite_string_node(p, c->car->cdr, d->car->cdr); + cons_free(d->car); + c->cdr = d->cdr; + cons_free(d); + return a; + } + else { + c->cdr = b->cdr; + cons_free(b); + return a; + } + } + } + + return new_dstr(p, list2(a, b)); +} + /* (:str . (s . len)) */ static node* new_xstr(parser_state *p, const char *s, int len) @@ -1181,7 +1300,7 @@ heredoc_end(parser_state *p) %token <nd> tNTH_REF tBACK_REF %token <num> tREGEXP_END -%type <nd> singleton string string_rep string_interp xstring regexp +%type <nd> singleton string string_fragment string_rep string_interp xstring regexp %type <nd> literal numeric cpath symbol %type <nd> top_compstmt top_stmts top_stmt %type <nd> bodystmt compstmt stmts stmt expr arg primary command command_call method_call @@ -2560,9 +2679,9 @@ block_param : f_arg ',' f_block_optarg ',' f_rest_arg opt_block_args_tail { $$ = new_args(p, $1, 0, $3, 0, $4); } - | f_arg ',' + | f_arg ',' opt_block_args_tail { - $$ = new_args(p, $1, 0, 0, 0, 0); + $$ = new_args(p, $1, 0, 0, 0, $3); } | f_arg ',' f_rest_arg ',' f_arg opt_block_args_tail { @@ -2603,19 +2722,24 @@ block_param : f_arg ',' f_block_optarg ',' f_rest_arg opt_block_args_tail ; opt_block_param : none - | block_param_def { + local_add_blk(p, 0); + $$ = 0; + } + | block_param_def + { p->cmd_start = TRUE; $$ = $1; } ; -block_param_def : '|' opt_bv_decl '|' +block_param_def : '|' {local_add_blk(p, 0);} opt_bv_decl '|' { $$ = 0; } | tOROP { + local_add_blk(p, 0); $$ = 0; } | '|' block_param opt_bv_decl '|' @@ -2828,7 +2952,14 @@ literal : numeric | symbols ; -string : tCHAR +string : string_fragment + | string string_fragment + { + $$ = concat_string(p, $1, $2); + } + ; + +string_fragment : tCHAR | tSTRING | tSTRING_BEG tSTRING { @@ -3050,7 +3181,7 @@ var_ref : variable } | keyword__FILE__ { - const char *fn = p->filename; + const char *fn = mrb_sym2name_len(p->mrb, p->filename_sym, NULL); if (!fn) { fn = "(null)"; } @@ -3060,7 +3191,7 @@ var_ref : variable { char buf[16]; - snprintf(buf, sizeof(buf), "%d", p->lineno); + dump_int(p->lineno, buf); $$ = new_int(p, buf, 10); } | keyword__ENCODING__ @@ -3302,7 +3433,7 @@ f_arg_item : f_norm_arg } f_margs rparen { - $$ = new_masgn(p, $3, p->locals->car); + $$ = new_masgn_param(p, $3, p->locals->car); local_resume(p, $<nd>2); local_add_f(p, 0); } @@ -3454,7 +3585,7 @@ assoc : arg tASSOC arg void_expr_error(p, $3); $$ = cons(new_sym(p, $1), $3); } - | string tLABEL_TAG arg + | string_fragment tLABEL_TAG arg { void_expr_error(p, $3); if ($1->car == (node*)NODE_DSTR) { @@ -3559,8 +3690,9 @@ yyerror(parser_state *p, const char *s) if (! p->capture_errors) { #ifndef MRB_DISABLE_STDIO - if (p->filename) { - fprintf(stderr, "%s:%d:%d: %s\n", p->filename, p->lineno, p->column, s); + if (p->filename_sym) { + const char *filename = mrb_sym2name_len(p->mrb, p->filename_sym, NULL); + fprintf(stderr, "%s:%d:%d: %s\n", filename, p->lineno, p->column, s); } else { fprintf(stderr, "line %d:%d: %s\n", p->lineno, p->column, s); @@ -3579,11 +3711,13 @@ yyerror(parser_state *p, const char *s) } static void -yyerror_i(parser_state *p, const char *fmt, int i) +yyerror_c(parser_state *p, const char *msg, char c) { char buf[256]; - snprintf(buf, sizeof(buf), fmt, i); + strncpy(buf, msg, sizeof(buf) - 2); + buf[sizeof(buf) - 2] = '\0'; + strncat(buf, &c, 1); yyerror(p, buf); } @@ -3595,11 +3729,12 @@ yywarn(parser_state *p, const char *s) if (! p->capture_errors) { #ifndef MRB_DISABLE_STDIO - if (p->filename) { - fprintf(stderr, "%s:%d:%d: %s\n", p->filename, p->lineno, p->column, s); + if (p->filename_sym) { + const char *filename = mrb_sym2name_len(p->mrb, p->filename_sym, NULL); + fprintf(stderr, "%s:%d:%d: warning: %s\n", filename, p->lineno, p->column, s); } else { - fprintf(stderr, "line %d:%d: %s\n", p->lineno, p->column, s); + fprintf(stderr, "line %d:%d: warning: %s\n", p->lineno, p->column, s); } #endif } @@ -3621,11 +3756,14 @@ yywarning(parser_state *p, const char *s) } static void -yywarning_s(parser_state *p, const char *fmt, const char *s) +yywarning_s(parser_state *p, const char *msg, const char *s) { char buf[256]; - snprintf(buf, sizeof(buf), fmt, s); + strncpy(buf, msg, sizeof(buf) - 1); + buf[sizeof(buf) - 1] = '\0'; + strncat(buf, ": ", sizeof(buf) - strlen(buf) - 1); + strncat(buf, s, sizeof(buf) - strlen(buf) - 1); yywarning(p, buf); } @@ -3637,10 +3775,10 @@ backref_error(parser_state *p, node *n) c = intn(n->car); if (c == NODE_NTH_REF) { - yyerror_i(p, "can't set variable $%" MRB_PRId, intn(n->cdr)); + yyerror_c(p, "can't set variable $", (char)intn(n->cdr)+'0'); } else if (c == NODE_BACK_REF) { - yyerror_i(p, "can't set variable $%c", intn(n->cdr)); + yyerror_c(p, "can't set variable $", (char)intn(n->cdr)); } else { mrb_bug(p->mrb, "Internal error in backref_error() : n=>car == %S", mrb_fixnum_value(c)); @@ -3664,8 +3802,10 @@ void_expr_error(parser_state *p, node *n) break; case NODE_AND: case NODE_OR: - void_expr_error(p, n->cdr->car); - void_expr_error(p, n->cdr->cdr); + if (n->cdr) { + void_expr_error(p, n->cdr->car); + void_expr_error(p, n->cdr->cdr); + } break; case NODE_BEGIN: if (n->cdr) { @@ -4182,8 +4322,17 @@ parse_string(parser_state *p) } if (c < 0) { char buf[256]; - snprintf(buf, sizeof(buf), "can't find heredoc delimiter \"%s\" anywhere before EOF", hinf->term); - yyerror(p, buf); + const char s1[] = "can't find heredoc delimiter \""; + const char s2[] = "\" anywhere before EOF"; + + if (sizeof(s1)+sizeof(s2)+strlen(hinf->term)+1 >= sizeof(buf)) { + yyerror(p, "can't find heredoc delimiter anywhere before EOF"); + } else { + strcpy(buf, s1); + strcat(buf, hinf->term); + strcat(buf, s2); + yyerror(p, buf); + } return 0; } pylval.nd = new_str(p, tok(p), toklen(p)); @@ -4333,9 +4482,14 @@ parse_string(parser_state *p) pushback(p, re_opt); if (toklen(p)) { char msg[128]; + + strcpy(msg, "unknown regexp option"); tokfix(p); - snprintf(msg, sizeof(msg), "unknown regexp option%s - %s", - toklen(p) > 1 ? "s" : "", tok(p)); + if (toklen(p) > 1) { + strcat(msg, "s"); + } + strcat(msg, " - "); + strncat(msg, tok(p), sizeof(msg) - strlen(msg) - 1); yyerror(p, msg); } if (f != 0) { @@ -4542,7 +4696,7 @@ parser_yylex(parser_state *p) } pushback(p, c); if (IS_SPCARG(c)) { - yywarning(p, "`**' interpreted as argument prefix"); + yywarning(p, "'**' interpreted as argument prefix"); c = tDSTAR; } else if (IS_BEG()) { @@ -4763,7 +4917,10 @@ parser_yylex(parser_state *p) } if (c2) { char buf[256]; - snprintf(buf, sizeof(buf), "invalid character syntax; use ?\\%c", c2); + char cc = (char)c2; + + strcpy(buf, "invalid character syntax; use ?\\"); + strncat(buf, &cc, 1); yyerror(p, buf); } } @@ -4774,10 +4931,10 @@ parser_yylex(parser_state *p) } newtok(p); /* need support UTF-8 if configured */ - if ((isalnum(c) || c == '_')) { + if ((ISALNUM(c) || c == '_')) { int c2 = nextc(p); pushback(p, c2); - if ((isalnum(c2) || c2 == '_')) { + if ((ISALNUM(c2) || c2 == '_')) { goto ternary; } } @@ -5136,12 +5293,12 @@ parser_yylex(parser_state *p) pushback(p, c); if (nondigit) { trailing_uc: - yyerror_i(p, "trailing '%c' in number", nondigit); + yyerror_c(p, "trailing non digit in number: ", (char)nondigit); } tokfix(p); if (is_float) { #ifdef MRB_WITHOUT_FLOAT - yywarning_s(p, "floating point numbers are not supported", tok(p)); + yywarning(p, "floating point numbers are not supported"); pylval.nd = new_int(p, "0", 10); return tINTEGER; #else @@ -5151,10 +5308,10 @@ parser_yylex(parser_state *p) errno = 0; d = mrb_float_read(tok(p), &endp); if (d == 0 && endp == tok(p)) { - yywarning_s(p, "corrupted float value %s", tok(p)); + yywarning_s(p, "corrupted float value", tok(p)); } else if (errno == ERANGE) { - yywarning_s(p, "float %s out of range", tok(p)); + yywarning_s(p, "float out of range", tok(p)); errno = 0; } pylval.nd = new_float(p, tok(p)); @@ -5345,7 +5502,7 @@ parser_yylex(parser_state *p) } else { term = nextc(p); - if (isalnum(term)) { + if (ISALNUM(term)) { yyerror(p, "unknown type of %string"); return 0; } @@ -5489,14 +5646,14 @@ parser_yylex(parser_state *p) do { tokadd(p, c); c = nextc(p); - } while (c >= 0 && isdigit(c)); + } while (c >= 0 && ISDIGIT(c)); pushback(p, c); if (last_state == EXPR_FNAME) goto gvar; tokfix(p); { unsigned long n = strtoul(tok(p), NULL, 10); if (n > INT_MAX) { - yyerror_i(p, "capture group index must be <= %d", INT_MAX); + yyerror(p, "capture group index must be <= " MRB_STRINGIZE(INT_MAX)); return 0; } pylval.nd = new_nth_ref(p, (int)n); @@ -5531,12 +5688,12 @@ parser_yylex(parser_state *p) } return 0; } - else if (isdigit(c)) { + else if (ISDIGIT(c)) { if (p->tidx == 1) { - yyerror_i(p, "'@%c' is not allowed as an instance variable name", c); + yyerror_c(p, "wrong instance variable name: @", c); } else { - yyerror_i(p, "'@@%c' is not allowed as a class variable name", c); + yyerror_c(p, "wrong class variable name: @@", c); } return 0; } @@ -5552,7 +5709,15 @@ parser_yylex(parser_state *p) default: if (!identchar(c)) { - yyerror_i(p, "Invalid char '\\x%02X' in expression", c); + char buf[36]; + const char s[] = "Invalid char in expression: 0x"; + const char hexdigits[] = "0123456789ABCDEF"; + + strcpy(buf, s); + buf[sizeof(s)-1] = hexdigits[(c & 0xf0) >> 4]; + buf[sizeof(s)] = hexdigits[(c & 0x0f)]; + buf[sizeof(s)+1] = 0; + yyerror(p, buf); goto retry; } @@ -5688,7 +5853,7 @@ parser_yylex(parser_state *p) mrb_sym ident = intern_cstr(tok(p)); pylval.id = ident; - if (last_state != EXPR_DOT && islower(tok(p)[0]) && local_var_p(p, ident)) { + if (last_state != EXPR_DOT && ISLOWER(tok(p)[0]) && local_var_p(p, ident)) { p->lstate = EXPR_END; } } @@ -5898,7 +6063,7 @@ mrb_parser_set_filename(struct mrb_parser_state *p, const char *f) mrb_sym* new_table; sym = mrb_intern_cstr(p->mrb, f); - p->filename = mrb_sym2name_len(p->mrb, sym, NULL); + p->filename_sym = sym; p->lineno = (p->filename_table_length > 0)? 0 : 1; for (i = 0; i < p->filename_table_length; ++i) { @@ -5922,11 +6087,11 @@ mrb_parser_set_filename(struct mrb_parser_state *p, const char *f) p->filename_table[p->filename_table_length - 1] = sym; } -MRB_API char const* +MRB_API mrb_sym mrb_parser_get_filename(struct mrb_parser_state* p, uint16_t idx) { - if (idx >= p->filename_table_length) return NULL; + if (idx >= p->filename_table_length) return 0; else { - return mrb_sym2name_len(p->mrb, p->filename_table[idx], NULL); + return p->filename_table[idx]; } } @@ -5981,11 +6146,12 @@ mrb_load_exec(mrb_state *mrb, struct mrb_parser_state *p, mrbc_context *c) if (c) c->parser_nerr = p->nerr; if (p->capture_errors) { char buf[256]; - int n; - n = snprintf(buf, sizeof(buf), "line %d: %s\n", - p->error_buffer[0].lineno, p->error_buffer[0].message); - mrb->exc = mrb_obj_ptr(mrb_exc_new(mrb, E_SYNTAX_ERROR, buf, n)); + strcpy(buf, "line "); + dump_int(p->error_buffer[0].lineno, buf+5); + strcat(buf, ": "); + strncat(buf, p->error_buffer[0].message, sizeof(buf) - strlen(buf) - 1); + mrb->exc = mrb_obj_ptr(mrb_exc_new(mrb, E_SYNTAX_ERROR, buf, strlen(buf))); mrb_parser_free(p); return mrb_undef_value(); } |
