From 2e7b59ee140e75bb763a90ef10b1d4126822467a Mon Sep 17 00:00:00 2001 From: David Robillard Date: Thu, 5 Mar 2009 21:04:17 +0000 Subject: Proper error reporting for undefined symbols. Fix line/col in error messages to point to start of relevant token. git-svn-id: http://svn.drobilla.net/resp/tuplr@48 ad02d1e2-f140-0410-9f75-f8b11f17cedd --- tuplr.cpp | 87 +++++++++++++++++++++++++++++++++------------------------------ 1 file changed, 46 insertions(+), 41 deletions(-) (limited to 'tuplr.cpp') diff --git a/tuplr.cpp b/tuplr.cpp index 9920172..e3e439f 100644 --- a/tuplr.cpp +++ b/tuplr.cpp @@ -79,35 +79,38 @@ struct Exp { // ::= Atom | (Exp*) typedef Exp SExp; static SExp -readExpression(Cursor& loc, std::istream& in) +readExpression(Cursor& cur, std::istream& in) { #define PUSH(s, t) { if (t != "") { s.top().list.push_back(SExp(loc, t)); t = ""; } } -#define YIELD(s, t) { if (s.empty()) return SExp(loc, t); else PUSH(s, t) } +#define YIELD(s, t) { if (s.empty()) { return SExp(loc, t); } else PUSH(s, t) } stack stk; string tok; + Cursor loc; // start of tok while (char ch = in.get()) { - ++loc.col; + ++cur.col; switch (ch) { case EOF: - if (!stk.empty()) throw Error("unexpected end of file", loc); - return SExp(loc); + if (!stk.empty()) throw Error("unexpected end of file", cur); + return SExp(cur); + case ';': + while ((ch = in.get()) != '\n') {} case '\n': - ++loc.line; - loc.col = 0; + ++cur.line; cur.col = 0; case ' ': case '\t': if (tok != "") YIELD(stk, tok); break; case '"': - do { tok.push_back(ch); ++loc.col; } while ((ch = in.get()) != '"'); + loc = cur; + do { tok.push_back(ch); ++cur.col; } while ((ch = in.get()) != '"'); YIELD(stk, tok + '"'); break; case '(': - stk.push(SExp(loc)); + stk.push(SExp(cur)); break; case ')': switch (stk.size()) { case 0: - throw Error("unexpected `)'", loc); + throw Error("unexpected `)'", cur); case 1: PUSH(stk, tok); return stk.top(); @@ -119,15 +122,16 @@ readExpression(Cursor& loc, std::istream& in) } break; default: + if (tok == "") loc = cur; tok += ch; } } switch (stk.size()) { case 0: return SExp(loc, tok); case 1: return stk.top(); - default: throw Error("missing `)'", loc); + default: throw Error("missing `)'", cur); } - return SExp(loc); + return SExp(cur); } @@ -166,10 +170,11 @@ struct ASTLiteral : public AST { /// Symbol, e.g. "a" struct ASTSymbol : public AST { - ASTSymbol(const string& s) : cppstr(s) {} + ASTSymbol(const string& s, Cursor c=Cursor()) : loc(c), cppstr(s) {} bool operator==(const AST& rhs) const { return this == &rhs; } string str() const { return cppstr; } Value* compile(CEnv& cenv); + Cursor loc; private: const string cppstr; }; @@ -386,11 +391,11 @@ struct PEnv : private map { map::const_iterator i = parsers.find(s); return (i != parsers.end()) ? &i->second : NULL; } - ASTSymbol* sym(const string& s) { + ASTSymbol* sym(const string& s, Cursor c=Cursor()) { const const_iterator i = find(s); return ((i != end()) ? i->second - : insert(make_pair(s, new ASTSymbol(s))).first->second); + : insert(make_pair(s, new ASTSymbol(s, c))).first->second); } }; @@ -428,7 +433,7 @@ parseExpression(PEnv& penv, const SExp& exp) } else if (exp.atom == "false") { return new ASTLiteral(false); } - return penv.sym(exp.atom); + return penv.sym(exp.atom, exp.loc); } // Special forms @@ -825,7 +830,7 @@ Value* ASTSymbol::compile(CEnv& cenv) { AST** c = cenv.code.ref(this); - if (!c) throw Error((string("undefined symbol `") + cppstr + "'").c_str()); + if (!c) throw Error((string("undefined symbol `") + cppstr + "'").c_str(), loc); return cenv.compile(*c); } @@ -1152,34 +1157,34 @@ eval(CEnv& cenv, ExecutionEngine* engine, const string& name, istream& is) if (!resultType || resultType->var()) throw Error("body is undefined/untyped", cursor); + // Create function for top-level of program + ASTTuple prot; + const Type* ctype = resultType->type(); + if (!ctype) { + err << "program body has non-compilable type" << endl; + return 2; + } + assert(ctype); + Function* f = compileFunction(cenv, cenv.gensym("input"), ctype, prot); + BasicBlock* bb = BasicBlock::Create("entry", f); + cenv.builder.SetInsertPoint(bb); + + // Compile all expressions into it + Value* val = NULL; + for (list< pair >::const_iterator i = exprs.begin(); i != exprs.end(); ++i) + val = cenv.compile(i->second); + + // Finish function + cenv.builder.CreateRet(val); + cenv.optimise(*f); + + string resultStr = call(resultType, engine->getPointerToFunction(f)); + out << resultStr << " : " << resultType->str() << endl; + } catch (Error& e) { err << e.what() << endl; return 1; } - - // Create function for top-level of program - ASTTuple prot; - const Type* ctype = resultType->type(); - if (!ctype) { - err << "program body has non-compilable type" << endl; - return 2; - } - assert(ctype); - Function* f = compileFunction(cenv, cenv.gensym("input"), ctype, prot); - BasicBlock* bb = BasicBlock::Create("entry", f); - cenv.builder.SetInsertPoint(bb); - - // Compile all expressions into it - Value* val = NULL; - for (list< pair >::const_iterator i = exprs.begin(); i != exprs.end(); ++i) - val = cenv.compile(i->second); - - // Finish function - cenv.builder.CreateRet(val); - cenv.optimise(*f); - - string resultStr = call(resultType, engine->getPointerToFunction(f)); - out << resultStr << " : " << resultType->str() << endl; return 0; } -- cgit v1.2.1