RNode str_extend(RNode list, int term) { int brace = -1; RNode node; int nest; int c = nextc(); switch (c) { case '$': break; case '@': break; case '{': break; default: tokadd('#'); pushback(c); return list; } string ss = tok(); if (list == null) { list = new RNDStr(thread, ruby, ss); } else if (toklen() > 0) { RNode.list_append(thread, list, new RNStr(thread, ruby, ss)); } newtok(); switch (c) { case '$': tokadd('$'); c = nextc(); if (c == -1) return new RNEOF(); switch (c) { case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': while (Char.IsDigit((char)c)) { tokadd(c); c = nextc(); } pushback(c); goto fetch_id; case '&': case '+': case '_': case '~': case '*': case '$': case '?': case '!': case '@': case ',': case '.': case '=': case ':': case '<': case '>': case '\\': refetch: tokadd(c); goto fetch_id; default: if (c == term) { RNode.list_append(thread, list, new RNStr(thread, ruby, "#$")); pushback(c); newtok(); return list; } switch (c) { case '\"': case '/': case '\'': case '`': goto refetch; } if (!is_identchar(c)) { parser.yyerror("bad global variable in string"); newtok(); return list; } break; } while (is_identchar(c)) { tokadd(c); /* if (ismbchar(c)) { int i, len = mbclen(c)-1; for (i = 0; i < len; i++) { c = nextc(); tokadd(c); } } */ c = nextc(); } pushback(c); break; case '@': tokadd(c); c = nextc(); if (c == '@') { tokadd(c); c = nextc(); } while (is_identchar(c)) { tokadd(c); /* if (ismbchar(c)) { int i, len = mbclen(c)-1; for (i = 0; i < len; i++) { c = nextc(); tokadd(c); } } */ c = nextc(); } pushback(c); break; case '{': if (c == '{') brace = '}'; nest = 0; do { loop_again: c = nextc(); switch (c) { case -1: if (nest > 0) { parser.yyerror("bad substitution in string"); newtok(); return list; } return new RNEOF(); case '}': if (c == brace) { if (nest == 0) break; nest--; } tokadd(c); goto loop_again; case '\\': c = nextc(); if (c == -1) return new RNEOF(); if (c == term) { tokadd(c); } else { tokadd('\\'); tokadd(c); } break; case '{': if (brace != -1) nest++; goto case '`'; case '\"': case '/': case '`': if (c == term) { pushback(c); RNode.list_append(thread, list, new RNStr(thread, ruby, "#")); ruby.warn("bad substitution in string"); RNode.list_append(thread, list, new RNStr(thread, ruby, tok())); newtok(); return list; } goto default; default: tokadd(c); break; } } while (c != brace); break; } fetch_id: node = new RNEVStr(thread, ruby, tok()); RNode.list_append(thread, list, node); newtok(); return list; }
int here_document(int term, int indent) { int c; string line = String.Empty; RNode list = null; int linesave = thread.line; newtok(); switch (term) { case '\'': goto case '`'; case '"': goto case '`'; case '`': while ((c = nextc()) != term) { tokadd(c); } if (term == '\'') term = '\0'; break; default: c = term; term = '"'; if (!is_identchar(c)) { ruby.warn("use of bare << to mean <<\"\" is deprecated"); break; } while (is_identchar(c)) { tokadd(c); c = nextc(); } pushback(c); break; } string lastline_save = lastline; int offset_save = pcur - pbeg; string eos = string.Copy(tok()); int len = eos.Length; string str = String.Empty; for (;;) { lastline = line = getline(); if (line == null) { thread.line = linesave; thread.CompileError("can't find string \"" + eos + "\" anywhere before EOF"); return 0; } thread.line++; string p = line; if (indent > 0) { while (p.Length > 0 && (p[0] == ' ' || p[0] == '\t')) { p = p.Substring(1); } } if (String.Compare(eos, 0, p, 0, len) == 0) { if (p[len] == '\n' || p[len] == '\r') break; if (len == line.Length) break; } pbeg = pcur = 0; pend = pcur + line.Length; retry: switch (parse_string(term, '\n', '\n')) { case Token.tSTRING: // fall down to the next case case Token.tXSTRING: { yylval = (string)yylval + "\n"; } if (list == null) { str += (string)yylval; } else { RNode.list_append(thread, list, new RNStr(thread, ruby, (string)yylval)); } break; case Token.tDSTRING: if (list == null) list = new RNDStr(thread, ruby, str); goto case Token.tDXSTRING; case Token.tDXSTRING: if (list == null) list = new RNDXStr(thread, ruby, str); RNode.list_append(thread, (RNode)yylval, new RNStr(thread, ruby, "\n")); RNStr val = new RNStr((RNStr)yylval); yylval = new RNArray(thread, val); ((RNode)yylval).next = ((RNode)yylval).head.next; RNode.list_concat(list, (RNode)yylval); break; case 0: thread.line = linesave; thread.CompileError("can't find string \"" + eos + "\" anywhere before EOF"); return 0; } if (pcur != pend) { goto retry; } } lastline = lastline_save; pbeg = 0; pend = lastline.Length; pcur = offset_save; lex_state = EXPR.END; heredoc_end = thread.line; thread.line = linesave; if (list != null) { list.SetLine(linesave+1); yylval = list; } switch (term) { case '\0': goto case '"'; case '\'': goto case '"'; case '"': if (list != null) return Token.tDSTRING; yylval = str; return Token.tSTRING; case '`': if (list != null) return Token.tDXSTRING; yylval = str; return Token.tXSTRING; } return 0; }