From 69f54847b4932c353b59af98df959d192526ca86 Mon Sep 17 00:00:00 2001 From: Stefano Sanfilippo Date: Thu, 12 Mar 2015 18:59:45 +0100 Subject: [PATCH 1/4] Fixing typo in HEXDIGIT regex. --- src/Monicelli.lpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Monicelli.lpp b/src/Monicelli.lpp index 3b46f1f..e29a6bf 100644 --- a/src/Monicelli.lpp +++ b/src/Monicelli.lpp @@ -40,7 +40,7 @@ bool in(const char *sub, const std::string &str) { %option yyclass="Scanner" DIGIT [0-9] -HEXDIGIT [0-9a-zA-Z] +HEXDIGIT [0-9a-fA-F] CHAR [a-zA-Z_] %x shift From 7c5b760a94753fbd00d3d7cc4826fa26dced9700 Mon Sep 17 00:00:00 2001 From: Stefano Sanfilippo Date: Thu, 26 Mar 2015 14:43:42 +0100 Subject: [PATCH 2/4] Add location traits to AST nodes. This way, we keep trace of the exact source location where a statement or symbol was defined and we are able to emit more precise error messages in LLVM mode. --- src/Nodes.hpp | 30 +++++++++++++++++++++++------- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/src/Nodes.hpp b/src/Nodes.hpp index f4b43d9..997852f 100644 --- a/src/Nodes.hpp +++ b/src/Nodes.hpp @@ -23,6 +23,8 @@ #include "Emitter.hpp" #include "Pointers.hpp" +#include "location.hh" + #include #include #include @@ -52,20 +54,34 @@ enum class Operator { std::ostream& operator<<(std::ostream&, Operator const&); -class Emittable { +class Localizable { +public: + void setLocation(location const& l) { + loc = l; + } + + location const& getLocation() const { + return loc; + } + +private: + location loc; +}; + +class Emittable: public Localizable { public: virtual ~Emittable() {} virtual bool emit(Emitter *emitter) const = 0; }; -class Statement: public Emittable {}; +class Statement: virtual public Emittable {}; -class Expression: public Emittable {}; +class Expression: virtual public Emittable {}; class SimpleExpression: public Expression {}; -class SemiExpression { +class SemiExpression: public Localizable { public: SemiExpression(Operator op, Expression *l): op(op), left(l) {} @@ -321,7 +337,7 @@ private: Pointer> args; }; -class BranchCase { +class BranchCase: public Localizable { public: BranchCase(SemiExpression *c, PointerList *b): condition(c), body(b) {} @@ -341,7 +357,7 @@ private: class Branch: public Statement { public: - class Body { + class Body: public Localizable { public: Body(PointerList *c, PointerList *e = nullptr): cases(c), els(e) {} @@ -380,7 +396,7 @@ private: Function *makeMain(PointerList *body); -class FunArg { +class FunArg: public Localizable { public: FunArg(Id *n, Type t, bool p): name(n), type(t), pointer(p) {} From 4c9c5dc13bbc88d12aac7fc77637901750447f6c Mon Sep 17 00:00:00 2001 From: Stefano Sanfilippo Date: Thu, 26 Mar 2015 15:18:44 +0100 Subject: [PATCH 3/4] Pass current node to reportError function. This way, the location is included in the error message. --- src/BitcodeEmitter.cpp | 61 +++++++++++++++++++++++------------------- 1 file changed, 34 insertions(+), 27 deletions(-) diff --git a/src/BitcodeEmitter.cpp b/src/BitcodeEmitter.cpp index 559a91f..5a4f695 100644 --- a/src/BitcodeEmitter.cpp +++ b/src/BitcodeEmitter.cpp @@ -71,7 +71,10 @@ llvm::AllocaInst* allocateReturnVariable(llvm::Function *func) { } static -bool reportError(std::initializer_list const& what) { +bool reportError(Localizable const& node, std::initializer_list const& what) { + std::cerr << "line " << node.getLocation().begin.line << ", "; + std::cerr << "col " << node.getLocation().begin.column << ": "; + for (std::string const& chunk: what) { std::cerr << chunk << ' '; } @@ -307,7 +310,7 @@ bool BitcodeEmitter::emit(VarDeclaration const& node) { if (node.getInitializer()) { GUARDED(node.getInitializer()->emit(this)); if (!convertAndStore(d, alloc, d->retval)) { - return reportError({ + return reportError(node, { "Invalid inizializer for variable", node.getId().getValue() }); } @@ -324,14 +327,15 @@ bool BitcodeEmitter::emit(Assignment const& node) { auto var = d->scope.lookup(node.getName().getValue()); if (!var) { - return reportError({ - "Attempting assignment to undefined var", node.getName().getValue() + return reportError(node, { + "Attempting assignment to undefined variable", + node.getName().getValue() }); } GUARDED(node.getValue().emit(this)); if (!convertAndStore(d, *var, d->retval)) { - return reportError({ + return reportError(node, { "Invalid assignment to variable", node.getName().getValue() }); } @@ -347,19 +351,19 @@ bool BitcodeEmitter::emit(Print const& node) { Type printType = MonicelliType(d->retval->getType()); if (printType == Type::UNKNOWN) { - return reportError({"Attempting to print unknown type"}); + return reportError(node, {"Attempting to print unknown type"}); } auto toCall = PUT_NAMES.find(printType); if (toCall == PUT_NAMES.end()) { - return reportError({"Unknown print function for type"}); + return reportError(node, {"Unknown print function for type"}); } llvm::Function *callee = module->getFunction(toCall->second); if (callee == nullptr) { - return reportError({"Print function was not registered"}); + return reportError(node, {"Print function was not registered"}); } d->builder.CreateCall(callee, callargs); @@ -371,20 +375,23 @@ bool BitcodeEmitter::emit(Input const& node) { auto lookupResult = d->scope.lookup(node.getVariable().getValue()); if (!lookupResult) { - return reportError({"Attempting to read undefined variable"}); + return reportError(node, { + "Attempting to read undefined variable", + node.getVariable().getValue() + }); } llvm::AllocaInst *variable = *lookupResult; Type inputType = MonicelliType(variable->getAllocatedType()); if (inputType == Type::UNKNOWN) { - return reportError({"Attempting to read unknown type"}); + return reportError(node, {"Attempting to read unknown type"}); } auto toCall = GET_NAMES.find(inputType); if (toCall == GET_NAMES.end()) { - return reportError({ + return reportError(node, { "Unknown input function for type" }); } @@ -392,7 +399,7 @@ bool BitcodeEmitter::emit(Input const& node) { llvm::Function *callee = module->getFunction(toCall->second); if (callee == nullptr) { - return reportError({ + return reportError(node, { "Input function was not registered for type" }); } @@ -403,11 +410,11 @@ bool BitcodeEmitter::emit(Input const& node) { return true; } -bool BitcodeEmitter::emit(Abort const&) { +bool BitcodeEmitter::emit(Abort const& node) { llvm::Function *callee = module->getFunction(ABORT_NAME); if (callee == nullptr) { - return reportError({"Abort function was not registered"}); + return reportError(node, {"Abort function was not registered"}); } d->builder.CreateCall(callee); @@ -419,7 +426,7 @@ bool BitcodeEmitter::emit(Assert const& node) { llvm::Function *callee = module->getFunction(ASSERT_NAME); if (callee == nullptr) { - return reportError({"Assert function was not registered"}); + return reportError(node, {"Assert function was not registered"}); } node.getExpression().emit(this); @@ -432,14 +439,14 @@ bool BitcodeEmitter::emit(FunctionCall const& node) { llvm::Function *callee = module->getFunction(node.getName().getValue()); if (callee == 0) { - return reportError({ + return reportError(node, { "Attempting to call undefined function", node.getName().getValue() + "()" }); } if (callee->arg_size() != node.getArgs().size()) { - return reportError({ + return reportError(node, { "Argument number mismatch in call of", node.getName().getValue() + "()", "expected", std::to_string(callee->arg_size()), @@ -518,7 +525,7 @@ bool BitcodeEmitter::emit(FunctionPrototype const& node) { for (FunArg const& arg: node.getArgs()) { std::string const& name = arg.getName().getValue(); if (argsSet.find(name) != argsSet.end()) { - return reportError({ + return reportError(node, { "Two arguments with same name to function", node.getName().getValue() + "():", name }); @@ -539,13 +546,13 @@ bool BitcodeEmitter::emit(FunctionPrototype const& node) { func = module->getFunction(node.getName().getValue()); if (!func->empty()) { - return reportError({ + return reportError(node, { "Redefining function", node.getName().getValue() }); } if (func->arg_size() != node.getArgs().size()) { - return reportError({ + return reportError(node, { "Argument number mismatch in definition vs declaration of", node.getName().getValue() + "()", "expected", std::to_string(func->arg_size()), @@ -650,7 +657,7 @@ bool BitcodeEmitter::emit(Id const& node) { auto value = d->scope.lookup(node.getValue()); if (!value) { - return reportError({ + return reportError(node, { "Undefined variable", node.getValue() }); } @@ -685,17 +692,17 @@ bool BitcodeEmitter::emit(Float const& node) { #define HANDLE_INT_ONLY(op, symbol) \ if (fp) { \ - return reportError({"Operator " #symbol " cannot be applied to float values!"}); \ + return reportError(node, {"Operator " #symbol " cannot be applied to float values!"}); \ } else { \ d->retval = d->builder.Create##op(left, right); \ } static -bool createOp(BitcodeEmitter::Private *d, llvm::Value *left, Operator op, llvm::Value *right) { +bool createOp(BitcodeEmitter::Private *d, Localizable const& node, llvm::Value *left, Operator op, llvm::Value *right) { llvm::Type *retType = deduceResultType(left, right); if (retType == nullptr) { - return reportError({"Cannot combine operators."}); + return reportError(node, {"Cannot combine operators."}); } bool fp = isFP(retType); @@ -704,7 +711,7 @@ bool createOp(BitcodeEmitter::Private *d, llvm::Value *left, Operator op, llvm:: right = coerce(d, right, retType); if (left == nullptr || right == nullptr) { - return reportError({"Cannot convert operators to result type."}); + return reportError(node, {"Cannot convert operators to result type."}); } switch (op) { @@ -756,7 +763,7 @@ bool BitcodeEmitter::emit(BinaryExpression const& expression) { GUARDED(expression.getRight().emit(this)); llvm::Value *right = d->retval; - GUARDED(createOp(d, left, expression.getOperator(), right)); + GUARDED(createOp(d, expression, left, expression.getOperator(), right)); return true; } @@ -768,7 +775,7 @@ bool BitcodeEmitter::emitSemiExpression(Id const& left, SemiExpression const& ri GUARDED(right.getLeft().emit(this)); llvm::Value *rhs = d->retval; - GUARDED(createOp(d, lhs, right.getOperator(), rhs)); + GUARDED(createOp(d, right, lhs, right.getOperator(), rhs)); return true; } From 554f80ac5d01eb0ac218cf12540cd427763505a4 Mon Sep 17 00:00:00 2001 From: Stefano Sanfilippo Date: Thu, 26 Mar 2015 15:19:07 +0100 Subject: [PATCH 4/4] Keeping track of locations in parser. --- src/Monicelli.ypp | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/src/Monicelli.ypp b/src/Monicelli.ypp index 408078a..9068d07 100644 --- a/src/Monicelli.ypp +++ b/src/Monicelli.ypp @@ -126,9 +126,10 @@ %type assign_stmt %type loop_stmt %type return_stmt -%type expression maybe_expression simple_expression var_init +%type expression maybe_expression simple_expression expression_inner +%type var_init %type call_arglist call_args -%type semi_expression +%type semi_expression semi_expression_inner %type variable %type numeric %type pointer @@ -196,6 +197,7 @@ statements: } | statements statement { if ($2 != nullptr) { + $2->setLocation(@2); $1->push_back($2); } $$ = $1; @@ -268,6 +270,7 @@ loop_stmt: ; branch_stmt: BRANCH_CONDITION variable BRANCH_BEGIN branch_body BRANCH_END { + $2->setLocation(@2); $$ = new Branch($2, $4); } ; @@ -329,6 +332,12 @@ assert_stmt: } ; expression: + expression_inner { + $1->setLocation(@1); + $$ = $1; + } +; +expression_inner: simple_expression { $$ = $1; } @@ -364,6 +373,12 @@ expression: } ; semi_expression: + semi_expression_inner { + $1->setLocation(@1); + $$ = $1; + } +; +semi_expression_inner: expression { $$ = new SemiExpEq($1); }