static int quoted_term; #define quoted_term_char ((unsigned char)quoted_term) #define WHEN_QUOTED_TERM(x) ((quoted_term >= 0) && (x)) #define QUOTED_TERM_P(c) WHEN_QUOTED_TERM((c) == quoted_term_char) #define STR_FUNC_ESCAPE 0x01 #define STR_FUNC_EXPAND 0x02 #define STR_FUNC_REGEXP 0x04 #define STR_FUNC_QWORDS 0x08 #define STR_FUNC_INDENT 0x20 enum string_type { str_squote = (0), str_dquote = (STR_FUNC_EXPAND), str_xquote = (STR_FUNC_ESCAPE|STR_FUNC_EXPAND), str_regexp = (STR_FUNC_REGEXP|STR_FUNC_ESCAPE|STR_FUNC_EXPAND), str_sword = (STR_FUNC_QWORDS), str_dword = (STR_FUNC_QWORDS|STR_FUNC_EXPAND), }; #define NEW_STRTERM(func, term, paren) \ rb_node_newnode(NODE_STRTERM, (func), (term), (paren)) static int parse_string(quote) NODE *quote; { int func = quote->nd_func; int term = quote->nd_term; int paren = quote->nd_paren; int c, space = 0; c = nextc(); if (ISSPACE(c)) { do {c = nextc();} while (ISSPACE(c)); space = 1; } if (c == term) { if (!lex_strnest) { eos: quote->nd_func = -1; return ' '; } } if (c == '\\' && WHEN_QUOTED_TERM(peek(quoted_term_char))) { if ((c = nextc()) == term) goto eos; } if (space) { pushback(c); return ' '; } newtok(); if (c == '#') { switch (c = nextc()) { case '$': case '@': pushback(c); return tSTRING_DVAR; case '{': return tSTRING_DBEG; } tokadd('#'); } pushback(c); if (tokadd_string(func, term, paren) == -1) { ruby_sourceline = nd_line(quote); rb_compile_error("unterminated string meets end of file"); return tSTRING_END; } tokfix(); yylval.node = NEW_STR(rb_str_new(tok(), toklen())); return tSTRING_CONTENT; } static int tokadd_string(func, term, paren) int func, term, paren; { int c; while ((c = nextc()) != -1) { if (paren && c == paren) { lex_strnest++; } else if (c == term) { if (!lex_strnest) { pushback(c); break; } --lex_strnest; } else if (c == '#' && lex_p < lex_pend) { int c2 = *lex_p; if (c2 == '$' || c2 == '@' || c2 == '{') { pushback(c); break; } } else if (c == '\\') { c = nextc(); if (QUOTED_TERM_P(c)) { pushback(c); return c; } switch (c) { case '\n': continue; case '\\': break; default: pushback(c); } } else if (ismbchar(c)) { int i, len = mbclen(c)-1; for (i = 0; i < len; i++) { tokadd(c); c = nextc(); } } else if (ISSPACE(c)) { pushback(c); break; } tokadd(c); } return c; }