// // aegis - project change supervisor // Copyright (C) 1991-1996, 1998, 1999, 2001-2008, 2012, 2014 Peter Miller // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 3 of the License, or (at // your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see . // #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // must be last static input::pointer ip; static int error_count; extern aer_report_STYPE aer_report_lval; static nstring_accumulator buffer; static symtab_ty *stp; struct table_ty { const char *name; int token; }; static table_ty table[] = { {"!", NOT_LOGICAL, }, {"!=", NE, }, {"!~", NMATCH, }, {"#", JUNK, }, {"##", JOIN, }, {"##=", ASSIGN_JOIN, }, {"%", MOD, }, {"%=", ASSIGN_MOD, }, {"&", AND_BIT, }, {"&&", AND_LOGICAL, }, {"&=", ASSIGN_AND_BIT, }, {"(", LP, }, {")", RP, }, {"*", MUL, }, {"**", POWER, }, {"**=", ASSIGN_POWER, }, {"*=", ASSIGN_MUL, }, {"+", PLUS, }, {"++", INCR, }, {"+=", ASSIGN_PLUS, }, {",", COMMA, }, {"-", MINUS, }, {"--", DECR, }, {"-=", ASSIGN_MINUS, }, {".", DOT, }, {"/", DIV, }, {"/=", ASSIGN_DIV, }, {":", COLON, }, {";", SEMICOLON, }, {"<", LT, }, {"<<", SHIFT_LEFT, }, {"<<=", ASSIGN_SHIFT_LEFT, }, {"<=", LE, }, {"=", ASSIGN, }, {"==", EQ, }, {">", GT, }, {">=", GE, }, {">>", SHIFT_RIGHT, }, {">>=", ASSIGN_SHIFT_RIGHT, }, {"?", QUESTION, }, {"[", LBB, }, {"]", RBB, }, {"^", XOR_BIT, }, {"^=", ASSIGN_XOR_BIT, }, {"auto", AUTO, }, {"break", BREAK, }, {"case", CASE, }, {"catch", CATCH, }, {"continue", CONTINUE, }, {"default", DEFAULT, }, {"do", DO, }, {"else", ELSE, }, {"for", FOR, }, {"function", FUNCTION, }, {"global", GLOBAL, }, {"goto", GOTO, }, {"if", IF, }, {"in", IN, }, {"return", RETURN, }, {"switch", SWITCH, }, {"throw", THROW, }, {"try", TRY, }, {"while", WHILE, }, {"{", LB, }, {"|", OR_BIT, }, {"|=", ASSIGN_OR_BIT, }, {"||", OR_LOGICAL, }, {"}", RB, }, {"~", NOT_BIT, }, {"~~", MATCH, }, }; static void reserved_init(void) { if (!stp) { stp = new symtab_ty(SIZEOF(table)); for (table_ty *tp = table; tp < ENDOF(table); ++tp) { nstring s(tp->name); stp->assign(s, &tp->token); } } } static int reserved(const nstring &name) { assert(stp); const int *data = (int *)stp->query(name); return (data ? *data : 0); } void rpt_lex_open(string_ty *s) { reserved_init(); ip = input_file::open_text(nstring(s), true); error_count = 0; } void rpt_lex_close(void) { if (error_count) { sub_context_ty *scp; scp = sub_context_new(); sub_var_set_string(scp, "File_Name", ip->name()); sub_var_set_long(scp, "Number", error_count); sub_var_optional(scp, "Number"); fatal_intl(scp, i18n("$filename: has errors")); // NOTREACHED sub_context_delete(scp); } ip.reset(); } static inline void lex_getc_undo(int c) { if (c >= 0) ip->ungetc(c); } int aer_report_lex(void) { int c; long n; nstring s; int term; int tok; for (;;) { c = ip->getch(); switch (c) { case -1: return 0; case ' ': case '\t': case '\f': case '\n': break; case '0': n = 0; c = ip->getch(); if (c == '.') { buffer.clear(); buffer.push_back('0'); goto fraction_part; } if (c == 'x' || c == 'X') { int ndigits; ndigits = 0; for (;;) { ++ndigits; c = ip->getch(); switch (c) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': n = 16 * n + c - '0'; continue; case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': n = 16 * n + c - 'A' + 10; continue; case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': n = 16 * n + c - 'a' + 10; continue; default: --ndigits; lex_getc_undo(c); break; } break; } if (!ndigits) { aer_report_error(i18n("malformed hex constant")); n = 0; } aer_report_lval.lv_value = new rpt_value::pointer(rpt_value_integer::create(n)); return CONSTANT; } for (;;) { switch (c) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': n = 8 * n + c - '0'; c = ip->getch(); continue; default: break; } break; } lex_getc_undo(c); aer_report_lval.lv_value = new rpt_value::pointer(rpt_value_integer::create(n)); return CONSTANT; case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': buffer.clear(); for (;;) { buffer.push_back(c); c = ip->getch(); if (c < 0) break; if (!isdigit((unsigned char)c)) break; } if (c != '.' && c != 'e' && c != 'E') { lex_getc_undo(c); s = buffer.mkstr(); rpt_value::pointer vp = rpt_value_integer::create(atol(s.c_str())); aer_report_lval.lv_value = new rpt_value::pointer(vp); return CONSTANT; } if (c == '.') { fraction_part: for (;;) { buffer.push_back(c); c = ip->getch(); if (c < 0) break; if (!isdigit((unsigned char)c)) break; } } if (c == 'e' || c == 'E') { buffer.push_back(c); c = ip->getch(); if (c == '+' || c == '-') { buffer.push_back(c); c = ip->getch(); } if (c < 0 || !isdigit((unsigned char)c)) { buffer.push_back('0'); aer_report_error(i18n("malformed exponent")); } else { for (;;) { buffer.push_back(c); c = ip->getch(); if (c < 0) break; if (!isdigit((unsigned char)c)) break; } } } lex_getc_undo(c); s = buffer.mkstr(); aer_report_lval.lv_value = new rpt_value::pointer ( rpt_value_real::create(atof(s.c_str())) ); return CONSTANT; case '"': case '\'': term = c; buffer.clear(); for (;;) { c = ip->getch(); if (c < 0) { str_eof: aer_report_error(i18n("end-of-file within string")); break; } if (c == '\n') { aer_report_error(i18n("end-of-line within string")); break; } if (c == term) break; if (c == '\\') { c = ip->getch(); switch (c) { default: { sub_context_ty sc; sc.var_set_format("Name", "\\%c", c); aer_lex_error(sc, i18n("unknown '$name' escape")); } break; case -1: goto str_eof; case 'b': buffer.push_back('\b'); break; case 'n': buffer.push_back('\n'); break; case 'r': buffer.push_back('\r'); break; case 't': buffer.push_back('\t'); break; case 'f': buffer.push_back('\f'); break; case '"': case '\'': case '\\': buffer.push_back(c); break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': { int nc; int v; v = 0; for (nc = 0; nc < 3; ++nc) { v = v * 8 + c - '0'; c = ip->getch(); switch (c) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': continue; default: lex_getc_undo(c); break; } break; } buffer.push_back(v); } break; } } else buffer.push_back(c); } s = buffer.mkstr(); aer_report_lval.lv_value = new rpt_value::pointer(rpt_value_string::create(s)); return CONSTANT; case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z': case '_': case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g': case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n': case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u': case 'v': case 'w': case 'x': case 'y': case 'z': buffer.clear(); for (;;) { buffer.push_back(c); c = ip->getch(); switch (c) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z': case '_': case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g': case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n': case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u': case 'v': case 'w': case 'x': case 'y': case 'z': continue; default: lex_getc_undo(c); break; } break; } s = buffer.mkstr(); tok = reserved(s); if (tok) return tok; aer_report_lval.lv_string = new nstring(s); return NAME; case '/': c = ip->getch(); if (c == '/') { eoln_comment: for (;;) { c = ip->getch(); if (c < 0) goto bad_comment; if (c == '\n') break; } break; } if (c != '*') { lex_getc_undo(c); c = '/'; goto normal; } for (;;) { for (;;) { c = ip->getch(); if (c < 0) { bad_comment: aer_report_error(i18n("end-of-file within comment")); return 0; } if (c == '*') break; } for (;;) { c = ip->getch(); if (c < 0) goto bad_comment; if (c != '*') break; } if (c == '/') break; } break; case '#': c = ip->getch(); if (c == '!') goto eoln_comment; lex_getc_undo(c); c = '#'; goto normal; case '.': c = ip->getch(); lex_getc_undo(c); if (c < 0 || !isdigit((unsigned char)c)) { c = '.'; goto normal; } c = '.'; buffer.clear(); buffer.push_back('0'); goto fraction_part; default: normal: buffer.clear(); for (;;) { buffer.push_back(c); s = buffer.mkstr(); if (!stp->query(s)) { if (buffer.size() > 1) { buffer.pop_back(); lex_getc_undo(c); } break; } c = ip->getch(); } s = buffer.mkstr(); tok = reserved(s); return (tok ? tok : JUNK); } } } void aer_report_error(const char *fmt) { sub_context_ty sc; aer_lex_error(sc, fmt); } void aer_report_error(sub_context_ty &sc, const char *fmt) { aer_lex_error(sc, rpt_lex_pos_get(), fmt); } rpt_position::pointer rpt_lex_pos_get(void) { static rpt_position::pointer curpos; nstring s = ip->name(); if (curpos) { // // The file name includes the line number. // if (curpos->get_file_name() == s) return curpos; curpos.reset(); } curpos = rpt_position::create(s, 0); return curpos; } void aer_lex_error(sub_context_ty &sc, const char *fmt) { aer_lex_error(sc, rpt_lex_pos_get(), fmt); } void aer_lex_error(rpt_position::pointer &pp, const char *fmt) { sub_context_ty sc; aer_lex_error(sc, pp, fmt); } void aer_lex_error(sub_context_ty &sc, const rpt_position::pointer &pp, const char *fmt) { assert(pp); pp->print_error(sc, fmt); if (ip) sc.fatal_intl(i18n("report aborted")); ++error_count; if (error_count >= 20) { sc.var_set_string("File_Name", ip->name()); sc.fatal_intl(i18n("$filename: too many errors")); // NOTREACHED } } void rpt_lex_error(const rpt_position::pointer &pp, const char *fmt) { sub_context_ty sc; assert(pp); pp->print_error(sc, fmt); if (ip) fatal_intl(&sc, i18n("report aborted")); ++error_count; if (error_count >= 20) { sc.var_set_string("File_Name", ip->name()); sc.fatal_intl(i18n("$filename: too many errors")); // NOTREACHED } } // // These are faked, so that the messages in the generated files // will also be translated correctly. // #if 0 static void fake(void) { i18n("parse error"); // bison i18n("parse error; also virtual memory exceeded"); // bison i18n("parse error; also virtual memory exhausted"); // bison i18n("parser stack overflow"); // bison i18n("syntax error"); // yacc i18n("yacc stack overflow"); // yacc } #endif // vim: set ts=8 sw=4 et :