/* Resp: A programming language * Copyright (C) 2008-2009 David Robillard * * Resp is free software: you can redistribute it and/or modify it under * the terms of the GNU Affero General Public License as published by the * Free Software Foundation, either version 3 of the License, or (at your * option) any later version. * * Resp 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 Affero General * Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with Resp. If not, see . */ /** @file * @brief Lexing (build a CST from a string). * A CST is a lexeme, or a tuple of CST's. */ #include #include #include "resp.hpp" using namespace std; inline int readChar(Cursor& cur, istream& in) { int ch = in.get(); switch (ch) { case '\n': ++cur.line; cur.col = 0; break; default: ++cur.col; } return ch; } /// Read an expression from @a in AST* readExpression(Cursor& cur, istream& in) { #define PUSH(s, t) { if (t != "") { s.top()->push_back(new ALexeme(loc, t)); t = ""; } } #define YIELD(s, t) { if (s.empty()) { return new ALexeme(loc, t); } else PUSH(s, t) } stack stk; string tok; Cursor loc; // start of tok while (int c = readChar(cur, in)) { switch (c) { case EOF: THROW_IF(!stk.empty(), cur, "unexpected end of file") return new ATuple(cur); case ';': while ((c = readChar(cur, in)) != '\n') {} case '\n': case ' ': case '\t': case '\r': case '\f': if (tok != "") YIELD(stk, tok); break; case '"': loc = cur; tok.push_back(c); // leading quote while ((c = readChar(cur, in)) != '"') { if (c == '\\') { // string escape switch (c = readChar(cur, in)) { case '"': tok.push_back('"'); break; case '\\': tok.push_back('\\'); break; default: cin.putback(c); throw Error(cur, string("unknown string escape `\\") + (char)c + "'"); } } else { // any other character tok.push_back(c); } } tok.push_back(c); // trailing quote YIELD(stk, tok); break; case '(': stk.push(new ATuple(cur)); break; case ')': switch (stk.size()) { case 0: cin.putback(c); throw Error(cur, "unexpected `)'"); case 1: PUSH(stk, tok); return stk.top(); default: PUSH(stk, tok); ATuple* l = stk.top(); stk.pop(); stk.top()->push_back(l); } break; case '#': if (in.peek() == '|') { while (!(readChar(cur, in) == '|' && readChar(cur, in) == '#')) {} break; } default: if (tok == "") loc = cur; tok += c; } } switch (stk.size()) { case 0: return new AString(loc, tok); case 1: return stk.top(); default: throw Error(cur, "missing `)'"); } return new ATuple(cur); }