summaryrefslogtreecommitdiff
path: root/parse.y
diff options
context:
space:
mode:
Diffstat (limited to 'parse.y')
-rw-r--r--parse.y228
1 files changed, 171 insertions, 57 deletions
diff --git a/parse.y b/parse.y
index 4bf13cf398..e9f0a51e26 100644
--- a/parse.y
+++ b/parse.y
@@ -6,7 +6,7 @@
$Date$
created at: Fri May 28 18:02:42 JST 1993
- Copyright (C) 1993-1996 Yukihiro Matsumoto
+ Copyright (C) 1993-1998 Yukihiro Matsumoto
************************************************/
@@ -58,8 +58,9 @@ static enum lex_state {
EXPR_MID, /* newline significant, +/- is a sign. */
EXPR_END, /* newline significant, +/- is a operator. */
EXPR_ARG, /* newline significant, +/- may be a sign. */
- EXPR_FNAME, /* ignore newline, +/- is a operator. */
- EXPR_CLASS, /* immediate after `class' no here document. */
+ EXPR_FNAME, /* ignore newline, +/- is a operator, no reserved words. */
+ EXPR_DOT, /* immediate after `.', no reserved words. */
+ EXPR_CLASS, /* immediate after `class', no here document. */
} lex_state;
static int class_nest = 0;
@@ -158,6 +159,8 @@ static void top_local_setup();
kDEFINED
klBEGIN
klEND
+ k__LINE__
+ k__FILE__
%token <id> IDENTIFIER FID GVAR IVAR CONSTANT
%token <val> INTEGER FLOAT STRING XSTRING REGEXP
@@ -175,8 +178,8 @@ static void top_local_setup();
%type <id> variable symbol operation assoc_kw
%type <id> cname fname op rest_arg
%type <num> f_arg
-%token oUPLUS /* unary+ */
-%token MINUS /* unary- */
+%token UPLUS /* unary+ */
+%token UMINUS /* unary- */
%token POW /* ** */
%token CMP /* <=> */
%token EQ /* == */
@@ -190,6 +193,7 @@ static void top_local_setup();
%token AREF ASET /* [] and []= */
%token LSHFT RSHFT /* << and >> */
%token COLON2 /* :: */
+%token COLON3 /* :: at EXPR_BEG */
%token <id> OP_ASGN /* +=, -= etc. */
%token ASSOC /* => */
%token KW_ASSOC /* -> */
@@ -208,6 +212,7 @@ static void top_local_setup();
%right kNOT
%nonassoc kDEFINED
%right '=' OP_ASGN
+%right '?' ':'
%nonassoc DOT2 DOT3
%left OROP
%left ANDOP
@@ -299,12 +304,14 @@ stmt : iterator iter_do_block
| stmt kIF_MOD expr
{
value_expr($3);
- $$ = node_newnode(NODE_AND, cond($3), $1);
+ $$ = NEW_IF(cond($3), $1, 0);
+ fixpos($$, $3);
}
| stmt kUNLESS_MOD expr
{
value_expr($3);
- $$ = node_newnode(NODE_OR, cond($3), $1);
+ $$ = NEW_UNLESS(cond($3), $1, 0);
+ fixpos($$, $3);
}
| stmt kWHILE_MOD expr
{
@@ -458,10 +465,6 @@ lhs : variable
{
$$ = attrset($1, $3, 0);
}
- | primary '.' CONSTANT
- {
- $$ = attrset($1, $3, 0);
- }
| backref
{
backref_error($1);
@@ -482,6 +485,11 @@ fname : IDENTIFIER
lex_state = EXPR_END;
$$ = $1;
}
+ | reswords
+ {
+ lex_state = EXPR_END;
+ $$ = $<id>1;
+ }
undef_list : fname
{
@@ -520,6 +528,14 @@ op : DOT2 { $$ = DOT2; }
| ASET { $$ = ASET; }
| '`' { $$ = '`'; }
+reswords : k__LINE__ | k__FILE__ | klBEGIN | klEND
+ | kALIAS | kAND | kBEGIN | kBREAK | kCASE | kCLASS | kDEF
+ | kDEFINED | kDO | kELSE | kELSIF | kEND | kENSURE | kFALSE
+ | kFOR | kIF_MOD | kIN | kMODULE | kNEXT | kNIL | kNOT
+ | kOR | kREDO | kRESCUE | kRETRY | kRETURN | kSELF | kSUPER
+ | kTHEN | kTRUE | kUNDEF | kUNLESS_MOD | kUNTIL_MOD | kWHEN
+ | kWHILE_MOD | kYIELD
+
arg : variable '=' arg
{
value_expr($3);
@@ -696,6 +712,12 @@ arg : variable '=' arg
in_defined = 0;
$$ = NEW_DEFINED($4);
}
+ | arg '?' arg ':' arg
+ {
+ value_expr($1);
+ $$ = NEW_IF(cond($1), $3, $5);
+ fixpos($$, $1);
+ }
| primary
{
$$ = $1;
@@ -803,8 +825,13 @@ primary : literal
}
| primary COLON2 cname
{
+ value_expr($1);
$$ = NEW_COLON2($1, $3);
}
+ | COLON3 cname
+ {
+ $$ = NEW_COLON3($2);
+ }
| STRING
{
$$ = NEW_STR($1);
@@ -977,9 +1004,6 @@ primary : literal
}
| kCLASS LSHFT expr term
{
- if (cur_mid || in_single)
- yyerror("class definition in method body");
-
class_nest++;
cref_push();
local_push();
@@ -1236,6 +1260,8 @@ variable : IDENTIFIER
| kSELF {$$ = kSELF;}
| kTRUE {$$ = kTRUE;}
| kFALSE {$$ = kFALSE;}
+ | k__FILE__ {$$ = k__FILE__;}
+ | k__LINE__ {$$ = k__LINE__;}
var_ref : variable
{
@@ -1257,7 +1283,7 @@ superclass : term
{
$$ = $3;
}
- | error term {yyerrok;}
+ | error term {yyerrok; $$ = 0;}
f_arglist : '(' f_args ')'
{
@@ -1552,6 +1578,14 @@ nextc()
VALUE v = io_gets(lex_input);
if (NIL_P(v)) return -1;
+ while (RSTRING(v)->ptr[RSTRING(v)->len-1] == '\n' &&
+ RSTRING(v)->ptr[RSTRING(v)->len-2] == '\\') {
+ VALUE v2 = io_gets(lex_input);
+
+ if (!NIL_P(v2)) {
+ str_cat(v, RSTRING(v2)->ptr, RSTRING(v2)->len);
+ }
+ }
lex_pbeg = lex_p = RSTRING(v)->ptr;
lex_pend = lex_p + RSTRING(v)->len;
if (RSTRING(v)->len == 8 &&
@@ -1680,6 +1714,9 @@ read_escape()
case 'b': /* backspace */
return '\b';
+ case 's': /* space */
+ return ' ';
+
case 'M':
if ((c = nextc()) != '-') {
yyerror("Invalid escape character syntax");
@@ -1763,8 +1800,10 @@ parse_regx(term)
break;
case '\\':
+ case '^': /* no \^ escape in regexp */
+ case 's':
tokadd('\\');
- tokadd('\\');
+ tokadd(c);
break;
case '1': case '2': case '3':
@@ -1775,11 +1814,6 @@ parse_regx(term)
tokadd(c);
break;
- case '^': /* no \^ escape in regexp */
- tokadd('\\');
- tokadd('^');
- break;
-
case 'b':
if (!in_brack) {
tokadd('\\');
@@ -1988,6 +2022,15 @@ parse_qstring(term)
return STRING;
}
+static int
+parse_quotedword(term)
+ int term;
+{
+ if (parse_qstring(term) == 0) return 0;
+ yylval.node = NEW_CALL(NEW_STR(yylval.val), rb_intern("split"), 0);
+ return DSTRING;
+}
+
char *strdup();
static int
@@ -2041,6 +2084,7 @@ here_document(term)
free(eos);
return 0;
}
+ sourceline++;
if (strncmp(eos, RSTRING(line)->ptr, len) == 0 &&
(RSTRING(line)->ptr[len] == '\n' ||
RSTRING(line)->ptr[len] == '\r')) {
@@ -2049,7 +2093,6 @@ here_document(term)
lex_pbeg = lex_p = RSTRING(line)->ptr;
lex_pend = lex_p + RSTRING(line)->len;
- sourceline++;
switch (parse_string(term, '\n')) {
case STRING:
case XSTRING:
@@ -2079,6 +2122,7 @@ here_document(term)
lex_p = save_lexp;
lex_pbeg = save_beg;
lex_pend = save_end;
+ lex_state = EXPR_END;
if (list) {
yylval.node = list;
@@ -2298,7 +2342,20 @@ retry:
return parse_qstring(c);
case '?':
- if ((c = nextc()) == '\\') {
+ if (lex_state == EXPR_END) {
+ Warning("a?b:c is undocumented feature ^^;;;");
+ lex_state = EXPR_BEG;
+ return '?';
+ }
+ c = nextc();
+ if (lex_state == EXPR_ARG && isspace(c)){
+ pushback(c);
+ arg_ambiguous();
+ lex_state = EXPR_BEG;
+ Warning("a?b:c is undocumented feature ^^;;;");
+ return '?';
+ }
+ if (c == '\\') {
c = read_escape();
}
c &= 0xff;
@@ -2379,6 +2436,7 @@ retry:
return OP_ASGN;
}
if (c == '>') {
+ Warning("-> is undocumented feature ^^;;;");
lex_state = EXPR_BEG;
return KW_ASSOC;
}
@@ -2415,6 +2473,7 @@ retry:
}
pushback(c);
if (!isdigit(c)) {
+ lex_state = EXPR_DOT;
return '.';
}
c = '.';
@@ -2540,12 +2599,23 @@ retry:
case ':':
c = nextc();
if (c == ':') {
- lex_state = EXPR_BEG;
+ if (lex_state == EXPR_BEG) {
+ lex_state = EXPR_BEG;
+ return COLON3;
+ }
+ if (lex_state == EXPR_ARG && space_seen) {
+ arg_ambiguous();
+ lex_state = EXPR_BEG;
+ return COLON3;
+ }
+ lex_state = EXPR_DOT;
return COLON2;
}
pushback(c);
- if (isspace(c))
+ if (lex_state == EXPR_END || isspace(c)) {
+ lex_state = EXPR_BEG;
return ':';
+ }
lex_state = EXPR_FNAME;
return SYMBEG;
@@ -2579,9 +2649,6 @@ retry:
return c;
case ',':
- lex_state = EXPR_BEG;
- return c;
-
case ';':
lex_state = EXPR_BEG;
return c;
@@ -2600,11 +2667,6 @@ retry:
c = LPAREN;
lex_state = EXPR_BEG;
}
- else if (lex_state == EXPR_ARG && space_seen) {
- arg_ambiguous();
- c = LPAREN;
- lex_state = EXPR_BEG;
- }
else {
lex_state = EXPR_BEG;
}
@@ -2686,6 +2748,9 @@ retry:
case 'q':
return parse_qstring(term);
+ case 'w':
+ return parse_quotedword(term);
+
case 'x':
return parse_string('`', term);
@@ -2693,7 +2758,7 @@ retry:
return parse_regx(term);
default:
- yyerror("unknown type of string `%c'", c);
+ yyerror("unknown type of %string");
return 0;
}
}
@@ -2829,12 +2894,17 @@ retry:
result = IVAR;
break;
default:
- /* See if it is a reserved word. */
- kw = rb_reserved_word(tok(), toklen());
- if (kw) {
- enum lex_state state = lex_state;
- lex_state = kw->state;
- return kw->id[state != EXPR_BEG];
+ if (lex_state != EXPR_DOT) {
+ /* See if it is a reserved word. */
+ kw = rb_reserved_word(tok(), toklen());
+ if (kw) {
+ enum lex_state state = lex_state;
+ if (lex_state == EXPR_FNAME) {
+ yylval.id = rb_intern(kw->name);
+ }
+ lex_state = kw->state;
+ return kw->id[state != EXPR_BEG];
+ }
}
if (lex_state == EXPR_FNAME) {
@@ -2846,7 +2916,7 @@ retry:
pushback(c);
}
}
- else if (lex_state == EXPR_BEG){
+ else if (lex_state == EXPR_BEG || lex_state == EXPR_DOT){
lex_state = EXPR_ARG;
}
else {
@@ -3219,6 +3289,12 @@ gettable(id)
else if (id == kFALSE) {
return NEW_FALSE();
}
+ else if (id == k__FILE__) {
+ return NEW_STR(str_new2(sourcefile));
+ }
+ else if (id == k__LINE__) {
+ return NEW_LIT(INT2FIX(sourceline));
+ }
else if (is_local_id(id)) {
if (local_id(id)) return NEW_LVAR(id);
if (dyna_var_defined(id)) return NEW_DVAR(id);
@@ -3257,12 +3333,20 @@ assignable(id, val)
else if (id == kFALSE) {
yyerror("Can't assign to false");
}
+ else if (id == k__FILE__) {
+ yyerror("Can't assign to __FILE__");
+ }
+ else if (id == k__LINE__) {
+ yyerror("Can't assign to __LINE__");
+ }
else if (is_local_id(id)) {
if (local_id(id) || !dyna_in_block()) {
lhs = NEW_LASGN(id, val);
}
else{
- dyna_var_asgn(id, TRUE);
+ if (!dyna_var_defined(id)) {
+ dyna_var_asgn(id, TRUE);
+ }
lhs = NEW_DASGN(id, val);
}
}
@@ -3386,12 +3470,55 @@ value_expr(node)
static NODE *cond2();
+int
+assign_in_cond(node)
+ NODE *node;
+{
+ switch (nd_type(node)) {
+ case NODE_MASGN:
+ Error("multiple assignment in conditional");
+ return 0;
+
+ case NODE_LASGN:
+ case NODE_DASGN:
+ case NODE_GASGN:
+ case NODE_IASGN:
+ case NODE_CASGN:
+ break;
+ case NODE_NEWLINE:
+
+ default:
+ return 1;
+ }
+
+ switch (nd_type(node->nd_value)) {
+ case NODE_LIT:
+ case NODE_STR:
+ case NODE_DSTR:
+ case NODE_XSTR:
+ case NODE_DXSTR:
+ case NODE_EVSTR:
+ case NODE_DREGX:
+ case NODE_NIL:
+ case NODE_TRUE:
+ case NODE_FALSE:
+ Error("found = in conditional, should be ==");
+ return 0;
+
+ default:
+ Warning("assignment in condition");
+ break;
+ }
+ if (assign_in_cond(node->nd_value)) return 1;
+}
+
static NODE*
cond0(node)
NODE *node;
{
enum node_type type = nd_type(node);
+ if (assign_in_cond(node) == 0) return 0;
switch (type) {
case NODE_DREGX:
case NODE_DREGX_ONCE:
@@ -3427,24 +3554,11 @@ static NODE*
cond(node)
NODE *node;
{
- enum node_type type = nd_type(node);
-
- switch (type) {
- case NODE_MASGN:
- case NODE_LASGN:
- case NODE_DASGN:
- case NODE_GASGN:
- case NODE_IASGN:
- case NODE_CASGN:
- Warning("assignment in condition");
- break;
- case NODE_NEWLINE:
+ if (node == 0) return 0;
+ if (nd_type(node) == NODE_NEWLINE){
node->nd_next = cond0(node->nd_next);
return node;
- default:
- break;
}
-
return cond0(node);
}