summaryrefslogtreecommitdiff
path: root/parse.y
diff options
context:
space:
mode:
authorYukihiro Matsumoto <matz@ruby-lang.org>1994-08-10 15:54:46 +0900
committerTakashi Kokubun <takashikkbn@gmail.com>2019-08-17 22:09:30 +0900
commit6e3090413652b6592346556149fed1e9aec5495d (patch)
treebac97139bbeedc8cb67cb2e451a22ed4ddb2b2d4 /parse.y
parent200e0ee2fd3c1c006c528874a88f684447215524 (diff)
version 0.50v0_50
http://cache.ruby-lang.org/pub/ruby/1.0/ruby-0.50.tar.gz Wed Aug 10 15:54:46 1994 Yukihiro Matsumoto (matz@ix-02) * variable.c: -vオプションが指定されている時は初期化されていない, 大域変数, インスタンス変数, ローカル変数を参照した時点でwarning を出すようにした. Tue Aug 9 11:50:48 1994 Yukihiro Matsumoto (matz@ix-02) * bignum.c: 冪乗に関しても多倍長演算を行なうように. 特に浮動小数点 数の範囲を越えた時の処理を的確に行なうように. * eval.c: メソッド定義後は構文木から, メソッド定義部分を外す. 無駄 な再定義が起こらないようにするためと2重にfree()されないため. * array.c(Fary_aref): 引数が1つでFixnumの時, Range checkを行なわな いように修正. * eval.c: 引数の数をコンパイル時に計算して若干の高速化. Mon Aug 8 13:06:24 1994 Yukihiro Matsumoto (matz@ix-02) * object.c: nilによる比較連鎖をなくした. * parse.y: bit演算子の優先順位を比較演算子よりも強くした. Cとは異 なることになるが, 直観には合致する. * gc.c: クラスを解放する時, 個々のメソッド毎にキャッシュをクリアす るのではなく, クラス単位でクリアするように. Thu Aug 4 18:45:09 1994 Yukihiro Matsumoto (matz@ix-02) * methods.c(method_free): 解放されたメソッドに関してキャッシュをク リアしておく必要があった. * gc.c: Dataクラスのデータ部分をfree()し忘れていた. Wed Aug 3 09:58:14 1994 Yukihiro Matsumoto (matz@ix-02) * parse.y: def func .. end形式による関数メソッドの定義はなくなった. * methods.c: func形式のメソッドをなくした. あっても, あまり意味が ないので. * eval.c: $0への代入でps(1)の出力が変化するように. * io.c(Fsyscall): syscall()を実現. Mon Aug 1 13:41:11 1994 Yukihiro Matsumoto (matz@ix-02) * parse.y: ダブルクォートで囲まれた文字列や正規表現中で"#{変数名}" または"#変数名"という形式で変数の内容を埋め込むことができるよう になった. * io.c: 関数メソッドsystem2()はなくなった. 今はバッククォートがあ るからね. * parse.y: `cmd`によってコマンドを文字列に展開することができるよう になった. * parse.y: __FILE__, __LINE__を追加. それぞれファイル名(文字列), 行番号(整数)を値とする疑似変数. Fri Jul 29 13:16:07 1994 Yukihiro Matsumoto (matz@ix-02) * methods.h: メソッドをオブジェクトとして扱うのをやめる. メソッド のメモリ管理にはリファレンスカウントを使うことにした. これでオブ ジェクトの数が減ってほんの少しだけGCが速くなる(かな). * purifyによってメモリ関係のバグを検査した(見つかる,見つかる…). * gc.c: GCをプログラマが変数をマークする形式から, スタックとレジス タからマークする方法に変更. 移植性が下がるような気もするが, siod やscmでも採用されているから多分大丈夫だろう. Linux on i486でも動 作を確認した. Wed Jul 27 16:13:13 1994 Yukihiro Matsumoto (matz@ix-02) * eval.c(Eval): トップレベルでは構造木をfreeしないように. どうせ解 放されるから時間の無駄である. * array.c, dict.c: "=="を構造一致に変更. Fri Jul 22 10:14:09 1994 Yukihiro Matsumoto (matz@ix-02) * error.c: 組み込みタイプの名前を登録し忘れていた. Thu Jul 21 14:06:48 1994 Yukihiro Matsumoto (matz@ix-02) * parse.y(freenode),eval.c(Eval): 解析木を解放し忘れていた. Mon Jul 18 10:19:15 1994 Yukihiro Matsumoto (matz@ix-02) * parse.y: 多重代入を処理するルールにバグがあって, 3要素以上の多重 代入に失敗していた. * eval.c(rb_eval): 多重代入で, 右辺が配列でない時には`to_a'メソッ ドで配列に変換して代入するようにした. 今までの仕様だと右辺値が第 1要素にそのまま代入されていたが, structなど配列に変換できるもの は変換した方が嬉しい気がする. * dbm.c,dict.c(delete_if): メソッド追加. * process.c(wait,waitpid): システムコールwaitpidまたはwait4がある 時はそちらを使うように. configureもそれらをチェックするように変更. * dbm.c, dict.c(clear): メソッド追加.
Diffstat (limited to 'parse.y')
-rw-r--r--parse.y388
1 files changed, 296 insertions, 92 deletions
diff --git a/parse.y b/parse.y
index 0f4f640..ff1a7f6 100644
--- a/parse.y
+++ b/parse.y
@@ -17,6 +17,7 @@
#include "env.h"
#include "node.h"
#include "st.h"
+#include <stdio.h>
#include "ident.h"
#define is_id_nonop(id) ((id)>LAST_TOKEN)
@@ -35,6 +36,9 @@ struct op_tbl {
NODE *eval_tree = Qnil;
static int in_regexp;
+char *sourcefile; /* current source file */
+int sourceline; /* current line no. */
+
enum {
KEEP_STATE = 0, /* don't change lex_state. */
EXPR_BEG, /* ignore newline, +/- is a sign. */
@@ -57,6 +61,7 @@ static NODE *list_concat();
static NODE *list_copy();
static NODE *call_op();
+static NODE *gettable();
static NODE *asignable();
static NODE *aryset();
static NODE *attrset();
@@ -82,7 +87,6 @@ static void setup_top_local();
%token CLASS
MODULE
DEF
- FUNC
UNDEF
INCLUDE
IF
@@ -111,16 +115,19 @@ static void setup_top_local();
RETRY
SELF
NIL
+ _FILE_
+ _LINE_
-%token <id> IDENTIFIER GVAR IVAR CONSTANT
-%token <val> INTEGER FLOAT STRING REGEXP
+%token <id> IDENTIFIER GVAR IVAR CONSTANT
+%token <val> INTEGER FLOAT STRING XSTRING REGEXP
+%token <node> STRING2 XSTRING2 DREGEXP
%type <node> singleton inc_list
%type <val> literal numeric
%type <node> compexpr exprs expr expr2 primary var_ref
%type <node> if_tail opt_else cases resque ensure opt_using
%type <node> call_args opt_args args f_arglist f_args f_arg
-%type <node> assoc_list assocs assoc
+%type <node> assoc_list assocs assoc regexp
%type <node> mlhs mlhs_head mlhs_tail lhs
%type <id> superclass variable symbol
%type <id> fname fname0 op rest_arg end_mark
@@ -152,10 +159,10 @@ static void setup_top_local();
%nonassoc DOT2 DOT3
%left OR
%left AND
-%left '|' '^'
-%left '&'
%nonassoc CMP EQ NEQ MATCH NMATCH
%left '>' GEQ '<' LEQ
+%left '|' '^'
+%left '&'
%left LSHFT RSHFT
%left '+' '-'
%left '*' '/' '%'
@@ -241,24 +248,7 @@ expr : CLASS IDENTIFIER superclass
if ($7 && $7 != DEF) {
Error("unmatched end keyword(expected `def')");
}
- $$ = NEW_DEFN($2, NEW_RFUNC($4, $5), MTH_METHOD);
- pop_local();
- cur_mid = Qnil;
- }
- | DEF FUNC fname
- {
- if (cur_mid || in_single)
- Error("nested method definition");
- cur_mid = $3;
- push_local();
- }
- f_arglist compexpr
- END end_mark
- {
- if ($8 && $8 != DEF) {
- Error("unmatched end keyword(expected `def')");
- }
- $$ = NEW_DEFN($3, NEW_RFUNC($5, $6), MTH_FUNC);
+ $$ = NEW_DEFN($2, NEW_RFUNC($4, $5));
pop_local();
cur_mid = Qnil;
}
@@ -421,6 +411,14 @@ op : COLON2 { $$ = COLON2; }
f_arglist : '(' f_args rparen
{
+ if ($2) {
+ NODE *list = $2->nd_frml;
+ int i;
+
+ for (i=0; list; list=list->nd_next, i++)
+ ;
+ $2->nd_cnt = i;
+ }
$$ = $2;
}
| term
@@ -457,7 +455,7 @@ f_arg : IDENTIFIER
{
if (!is_local_id($1))
Error("formal argument must be local variable");
- $$ = NEW_LIST(local_cnt($1));
+ $$ = NEW_QLIST(local_cnt($1));
}
| f_arg comma IDENTIFIER
{
@@ -887,26 +885,32 @@ args : expr2
}
primary : var_ref
- | '(' compexpr rparen
+ | literal
{
- $$ = $2;
+ literalize($1);
+ $$ = NEW_LIT($1);
}
-
| STRING
{
literalize($1);
$$ = NEW_STR($1);
}
+ | STRING2
+ | XSTRING
+ {
+ literalize($1);
+ $$ = NEW_XSTR($1);
+ }
+ | XSTRING2
+ | '/' {in_regexp = 1;} regexp
+ {
+ $$ = $3;
+ }
| primary '[' args rbracket
{
value_expr($1);
$$ = NEW_CALL($1, AREF, $3);
}
- | literal
- {
- literalize($1);
- $$ = NEW_LIT($1);
- }
| '[' opt_args rbracket
{
if ($2 == Qnil)
@@ -949,16 +953,23 @@ primary : var_ref
Error("super called outside of method");
$$ = NEW_ZSUPER();
}
+ | '(' compexpr rparen
+ {
+ $$ = $2;
+ }
literal : numeric
| '\\' symbol
{
$$ = INT2FIX($2);
}
- | '/' {in_regexp = 1;} REGEXP
+
+regexp : REGEXP
{
- $$ = $3;
+ literalize($1);
+ $$ = NEW_LIT($1);
}
+ | DREGEXP
symbol : fname0
| IVAR
@@ -983,27 +994,7 @@ variable : IDENTIFIER
var_ref : variable
{
- if ($1 == SELF) {
- $$ = NEW_SELF();
- }
- else if ($1 == NIL) {
- $$ = NEW_NIL();
- }
- else if (is_local_id($1)) {
- if (local_id($1))
- $$ = NEW_LVAR($1);
- else
- $$ = NEW_MVAR($1);
- }
- else if (is_global_id($1)) {
- $$ = NEW_GVAR($1);
- }
- else if (is_instance_id($1)) {
- $$ = NEW_IVAR($1);
- }
- else if (is_const_id($1)) {
- $$ = NEW_CVAR($1);
- }
+ $$ = gettable($1);
}
assoc_list : /* none */
@@ -1027,7 +1018,6 @@ assoc : expr2 ASSOC expr2
end_mark : CLASS { $$ = CLASS; }
| MODULE { $$ = MODULE; }
| DEF { $$ = DEF; }
- | FUNC { $$ = FUNC; }
| IF { $$ = IF; }
| UNLESS { $$ = UNLESS; }
| CASE { $$ = CASE; }
@@ -1054,7 +1044,6 @@ rbrace : '}' { yyerrok; }
comma : ',' { yyerrok; }
%%
-#include <stdio.h>
#include <ctype.h>
#include <sys/types.h>
#include "regex.h"
@@ -1075,11 +1064,9 @@ char *strdup();
#define EXPAND_B 1
#define LEAVE_BS 2
+static NODE *var_extend();
static void read_escape();
-char *sourcefile; /* current source file */
-int sourceline; /* current line no. */
-
static char *lex_p;
static int lex_len;
@@ -1135,7 +1122,9 @@ static struct kwtable {
int id;
int state;
} kwtable [] = {
- "__END__", 0, KEEP_STATE,
+ "__END__", 0, KEEP_STATE,
+ "__FILE__", _FILE_, EXPR_END,
+ "__LINE__", _LINE_, EXPR_END,
"break", BREAK, EXPR_END,
"case", CASE, KEEP_STATE,
"class", CLASS, KEEP_STATE,
@@ -1147,7 +1136,6 @@ static struct kwtable {
"end", END, EXPR_END,
"ensure", ENSURE, EXPR_BEG,
"for", FOR, KEEP_STATE,
- "func", FUNC, KEEP_STATE,
"if", IF, KEEP_STATE,
"in", IN, EXPR_BEG,
"include", INCLUDE, EXPR_BEG,
@@ -1170,6 +1158,8 @@ static struct kwtable {
"yield", YIELD, EXPR_BEG,
};
+static int strstart;
+
yylex()
{
register int c;
@@ -1179,6 +1169,7 @@ yylex()
if (in_regexp) {
int in_brack = 0;
int re_start = sourceline;
+ NODE *list = Qnil;
in_regexp = 0;
newtok();
@@ -1190,6 +1181,12 @@ yylex()
case ']':
in_brack = 0;
break;
+
+ case '#':
+ list = var_extend(list, '/');
+ if (list == (NODE*)-1) return 0;
+ continue;
+
case '\\':
if ((c = nextc()) == -1) {
sourceline = re_start;
@@ -1213,9 +1210,21 @@ yylex()
break;
tokfix();
- yylval.val = regexp_new(tok(), toklen());
lex_state = EXPR_END;
- return REGEXP;
+ if (list) {
+ if (toklen() > 0) {
+ VALUE ss = str_new(tok(), toklen());
+ literalize(ss);
+ list_append(list, NEW_STR(ss));
+ }
+ list->type = NODE_DREGX;
+ yylval.node = list;
+ return DREGEXP;
+ }
+ else {
+ yylval.val = regexp_new(tok(), toklen());
+ return REGEXP;
+ }
case -1:
Error("unterminated regexp");
@@ -1335,12 +1344,17 @@ retry:
return '>';
case '"':
+ case '`':
{
- int strstart = sourceline;
+ char term = c;
+ NODE *list = Qnil;
+ ID id;
+ strstart = sourceline;
newtok();
- while ((c = nextc()) != '"') {
+ while ((c = nextc()) != term) {
if (c == -1) {
+ unterm_str:
sourceline = strstart;
Error("unterminated string meets end of file");
return 0;
@@ -1352,12 +1366,17 @@ retry:
else if (c == '\n') {
sourceline++;
}
+ else if (c == '#') {
+ list = var_extend(list, term);
+ if (list == (NODE*)-1) return 0;
+ continue;
+ }
else if (c == '\\') {
c = nextc();
if (c == '\n') {
sourceline++;
}
- else if (c == '"') {
+ else if (c == term) {
tokadd(c);
}
else {
@@ -1369,22 +1388,34 @@ retry:
tokadd(c);
}
tokfix();
- yylval.val = str_new(tok(), toklen());
lex_state = EXPR_END;
- return STRING;
+ if (list == Qnil) {
+ yylval.val = str_new(tok(), toklen());
+ return (term == '"') ? STRING : XSTRING;
+ }
+ else {
+ if (toklen() > 0) {
+ VALUE ss = str_new(tok(), toklen());
+ literalize(ss);
+ list_append(list, NEW_STR(ss));
+ }
+ yylval.node = list;
+ if (term == '"') {
+ return STRING2;
+ }
+ else {
+ list->type = NODE_XSTR2;
+ return XSTRING2;
+ }
+ }
}
case '\'':
{
- int strstart = sourceline;
-
- newtok();
+ strstart = sourceline;
+ newtok();
while ((c = nextc()) != '\'') {
- if (c == -1) {
- sourceline = strstart;
- Error("unterminated string meets end of file");
- return 0;
- }
+ if (c == -1) goto unterm_str;
if (ismbchar(c)) {
tokadd(c);
c = nextc();
@@ -1639,7 +1670,6 @@ retry:
case ',':
case ';':
- case '`':
case '[':
case '(':
case '{':
@@ -1765,6 +1795,103 @@ retry:
}
}
+static NODE*
+var_extend(list, term)
+ NODE *list;
+ char term;
+{
+ int c, t;
+ VALUE ss;
+ ID id;
+
+ c = nextc();
+ switch (c) {
+ default:
+ tokadd('#');
+ pushback();
+ return list;
+ case '@': case '%':
+ t = nextc();
+ pushback();
+ if (!is_identchar(t)) {
+ tokadd('#');
+ tokadd(c);
+ return list;
+ }
+ case '$':
+ case '{':
+ break;
+ }
+
+ ss = str_new(tok(), toklen());
+ if (list == Qnil) {
+ literalize(ss);
+ list = NEW_STR2(ss);
+ }
+ else if (toklen() > 0) {
+ literalize(ss);
+ list_append(list, NEW_STR(ss));
+ }
+ newtok();
+ if (c == '{') {
+ while ((c = nextc()) != '}') {
+ if (c == -1) {
+ unterm_str:
+ sourceline = strstart;
+ Error("unterminated string meets end of file");
+ return (NODE*)-1;
+ }
+ if (isspace(c)) {
+ Error("Invalid variable name in string");
+ break;
+ }
+ if (c == term) {
+ Error("Inmature variable name in string");
+ pushback();
+ return list;
+ }
+ tokadd(c);
+ }
+ }
+ else {
+ switch (c) {
+ case '$':
+ tokadd(c);
+ c = nextc();
+ if (c == -1) goto unterm_str;
+ if (!is_identchar(c)) {
+ tokadd(c);
+ goto fetch_id;
+ }
+ /* through */
+ case '@': case '%':
+ tokadd(c);
+ c = nextc();
+ break;
+ }
+ while (is_identchar(c)) {
+ tokadd(c);
+ if (ismbchar(c)) {
+ c = nextc();
+ tokadd(c);
+ }
+ c = nextc();
+ }
+ pushback();
+ }
+ fetch_id:
+ tokfix();
+ if (strcmp("__LINE__", tok()) == 0)
+ id = _LINE_;
+ else if (strcmp("__FILE__", tok()) == 0)
+ id = _FILE_;
+ else
+ id = rb_intern(tok());
+ list_append(list, gettable(id));
+ newtok();
+ return list;
+}
+
static void
read_escape(flag)
int flag;
@@ -1890,6 +2017,7 @@ read_escape(flag)
if (flag & LEAVE_BS) {
tokadd('\\');
}
+ case '#':
tokadd(c);
break;
}
@@ -1957,11 +2085,12 @@ static NODE*
list_append(head, tail)
NODE *head, *tail;
{
- if (head == Qnil) return NEW_ARRAY(tail);
+ if (head == Qnil) return NEW_LIST(tail);
if (head->nd_last == Qnil) head->nd_last = head;
-
- head->nd_last->nd_next = NEW_ARRAY(tail);
+
+ head->nd_last->nd_next =
+ head->type == NODE_QLIST?NEW_QLIST(tail):NEW_LIST(tail);
head->nd_last = head->nd_last->nd_next;
return head;
}
@@ -2007,9 +2136,17 @@ void freenode(node)
case NODE_BLOCK:
case NODE_ARRAY:
freenode(node->nd_head);
+ case NODE_STR2:
+ case NODE_XSTR2:
+ case NODE_DREGX:
+ case NODE_QLIST:
freenode(node->nd_next);
break;
+ case NODE_HASH:
+ freenode(node->nd_head);
+ break;
case NODE_IF:
+ case NODE_UNLESS:
case NODE_WHEN:
case NODE_PROT:
freenode(node->nd_cond);
@@ -2026,57 +2163,85 @@ void freenode(node)
break;
case NODE_DO:
case NODE_FOR:
+ freenode(node->nd_var);
freenode(node->nd_ibdy);
freenode(node->nd_iter);
break;
case NODE_LASGN:
case NODE_GASGN:
case NODE_IASGN:
+ case NODE_CASGN:
freenode(node->nd_value);
break;
+ case NODE_MASGN:
+ freenode(node->nd_value);
+ freenode(node->nd_head);
+ break;
case NODE_CALL:
case NODE_SUPER:
freenode(node->nd_recv);
- case NODE_CALL2:
freenode(node->nd_args);
break;
+ case NODE_CALL2:
+ {
+ NODE *list = node->nd_next, *tmp;
+ while (list) {
+ tmp = list;
+ list = list->nd_next;
+ free(tmp);
+ }
+ }
+ break;
case NODE_DEFS:
freenode(node->nd_recv);
+ case NODE_DEFN:
+ freenode(node->nd_defn);
break;
case NODE_RETURN:
case NODE_YIELD:
freenode(node->nd_stts);
break;
case NODE_STR:
+ case NODE_XSTR:
case NODE_LIT:
unliteralize(node->nd_lit);
break;
- case NODE_CONST:
- unliteralize(node->nd_cval);
- break;
case NODE_ARGS:
freenode(node->nd_frml);
break;
case NODE_SCOPE:
- free(node->nd_tbl);
+ if (node->nd_tbl) free(node->nd_tbl);
freenode(node->nd_body);
break;
- case NODE_DEFN:
+ case NODE_DOT3:
+ freenode(node->nd_beg);
+ freenode(node->nd_end);
+ break;
+ case NODE_CLASS:
+ case NODE_MODULE:
+ freenode(node->nd_body);
+ break;
+ case NODE_ATTRSET:
+ case NODE_CVAR:
+ case NODE_CONST:
+ case NODE_ZSUPER:
case NODE_ZARRAY:
case NODE_CFUNC:
case NODE_BREAK:
case NODE_CONTINUE:
+ case NODE_REDO:
case NODE_RETRY:
case NODE_LVAR:
case NODE_GVAR:
case NODE_IVAR:
case NODE_MVAR:
- case NODE_CLASS:
- case NODE_MODULE:
case NODE_INC:
+ case NODE_UNDEF:
+ case NODE_ALIAS:
case NODE_NIL:
+ case NODE_SELF:
break;
- default:
+ default:
Bug("freenode: unknown node type %d", node->type);
break;
}
@@ -2148,6 +2313,42 @@ call_op(recv, id, narg, arg1)
}
static NODE*
+gettable(id)
+ ID id;
+{
+ if (id == SELF) {
+ return NEW_SELF();
+ }
+ else if (id == NIL) {
+ return NEW_NIL();
+ }
+ else if (id == _LINE_) {
+ return NEW_LIT(INT2FIX(sourceline));
+ }
+ else if (id == _FILE_) {
+ VALUE s = str_new2(sourcefile);
+
+ literalize(s);
+ return NEW_STR(s);
+ }
+ else if (is_local_id(id)) {
+ if (local_id(id))
+ return NEW_LVAR(id);
+ else
+ return NEW_MVAR(id);
+ }
+ else if (is_global_id(id)) {
+ return NEW_GVAR(id);
+ }
+ else if (is_instance_id(id)) {
+ return NEW_IVAR(id);
+ }
+ else if (is_const_id(id)) {
+ return NEW_CVAR(id);
+ }
+}
+
+static NODE*
asignable(id, val)
ID id;
NODE *val;
@@ -2162,6 +2363,9 @@ asignable(id, val)
lhs = Qnil;
Error("Can't asign to nil");
}
+ else if (id == _LINE_ || id == _FILE_) {
+ Error("Can't asign to special identifier");
+ }
else if (is_local_id(id)) {
lhs = NEW_LASGN(id, val);
}
@@ -2348,7 +2552,7 @@ setup_top_local()
the_env->local_vars = ALLOC_N(VALUE, lvtbl->cnt);
bzero(the_env->local_vars, lvtbl->cnt * sizeof(VALUE));
}
- else {
+ else if (lvtbl->tbl[0] < lvtbl->cnt) {
int i;
REALLOC_N(the_env->local_vars, VALUE, lvtbl->cnt);