diff --git a/coco/Parser.cpp b/coco/Parser.cpp index 61fc797..3ec2513 100644 --- a/coco/Parser.cpp +++ b/coco/Parser.cpp @@ -1,654 +1,719 @@ /*---------------------------------------------------------------------- Compiler Generator Coco/R, Copyright (c) 1990, 2004 Hanspeter Moessenboeck, University of Linz extended by M. Loeberbauer & A. Woess, Univ. of Linz ported to C++ by Csaba Balazs, University of Szeged with improvements by Pat Terry, Rhodes University 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 2, 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, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. As an exception, it is allowed to write an extension of Coco/R that is used as a plugin in non-free software. If not otherwise stated, any source code generated by Coco/R (other than Coco/R itself) does not fall under the GNU General Public License. -----------------------------------------------------------------------*/ #include #include "Parser.h" #include "Scanner.h" void Parser::SynErr(int n) { if (errDist >= minErrDist) errors->SynErr(la->line, la->col, n); errDist = 0; } void Parser::SemErr(const wchar_t* msg) { if (errDist >= minErrDist) errors->Error(t->line, t->col, msg); errDist = 0; } void Parser::Get() { for (;;) { t = la; la = scanner->Scan(); if (la->kind <= maxT) { ++errDist; break; } if (dummyToken != t) { dummyToken->kind = t->kind; dummyToken->pos = t->pos; dummyToken->col = t->col; dummyToken->line = t->line; dummyToken->next = NULL; coco_string_delete(dummyToken->val); dummyToken->val = coco_string_create(t->val); t = dummyToken; } la = t; } } void Parser::Expect(int n) { if (la->kind==n) Get(); else { SynErr(n); } } void Parser::ExpectWeak(int n, int follow) { if (la->kind == n) Get(); else { SynErr(n); while (!StartOf(follow)) Get(); } } bool Parser::WeakSeparator(int n, int syFol, int repFol) { if (la->kind == n) {Get(); return true;} else if (StartOf(repFol)) {return false;} else { SynErr(n); while (!(StartOf(syFol) || StartOf(repFol) || StartOf(0))) { Get(); } return StartOf(syFol); } } void Parser::Xreate() { - while (la->kind == _ident || la->kind == 24 /* "rule" */) { + while (la->kind == _ident || la->kind == 26 /* "rule" */) { if (la->kind == _ident) { FDecl(); } else { RuleDecl(); } } } void Parser::FDecl() { - std::wstring fname; Expression fbody; std::wstring varname; TypeAnnotation typIn; TypeAnnotation typOut; + std::wstring fname; std::wstring varname; TypeAnnotation typIn; TypeAnnotation typOut; Ident(fname); - Expect(6 /* "=" */); - Expect(7 /* "function" */); - Expect(8 /* ":" */); + Expect(_assign); + Expect(10 /* "function" */); + Expect(11 /* ":" */); Function f = Function(fname); if (StartOf(1)) { Type(typOut); f.setReturnType(typOut); } else if (la->kind == _lparen) { Get(); - Ident(varname); - Expect(8 /* ":" */); - Type(typIn); - f.addArg(varname, typIn); - while (la->kind == 9 /* "," */) { - Get(); + if (la->kind == _ident) { Ident(varname); - Expect(8 /* ":" */); + Expect(11 /* ":" */); Type(typIn); - f.addArg(varname, typIn); + f.addArg(std::move(varname), move(typIn)); + while (la->kind == 12 /* "," */) { + Get(); + Ident(varname); + Expect(11 /* ":" */); + Type(typIn); + f.addArg(std::move(varname), move(typIn)); + } } Expect(_rparen); - Expect(10 /* "-" */); - Expect(11 /* ">" */); + Expect(_implic); Type(typOut); f.setReturnType(typOut); - while (la->kind == 9 /* "," */) { + while (la->kind == 12 /* "," */) { Get(); FnTag(f); } - } else SynErr(34); - Expect(12 /* "{" */); - while (la->kind == _ident) { - VDecl(f); - Expect(13 /* ";" */); - } - Expr(fbody); - Expect(13 /* ";" */); - Expect(14 /* "}" */); - f.setBody(fbody); root.add(f); + } else SynErr(37); + BDecl(f.getEntryScope()); + root.add(f); } void Parser::RuleDecl() { - Expect(24 /* "rule" */); - Expect(8 /* ":" */); + Expect(26 /* "rule" */); + Expect(11 /* ":" */); RuleArguments args; RuleGuards guards; DomainAnnotation typ; std::wstring arg; Expect(_lparen); Ident(arg); - Expect(8 /* ":" */); + Expect(11 /* ":" */); Domain(typ); args.add(arg, typ); - while (la->kind == 9 /* "," */) { + while (la->kind == 12 /* "," */) { Get(); Ident(arg); - Expect(8 /* ":" */); + Expect(11 /* ":" */); Domain(typ); args.add(arg, typ); } Expect(_rparen); - if (la->kind == 25 /* "case" */) { + if (la->kind == 27 /* "case" */) { Get(); RGuard(guards); - while (la->kind == 9 /* "," */) { + while (la->kind == 12 /* "," */) { Get(); RGuard(guards); } } - - Expect(12 /* "{" */); + Expect(19 /* "{" */); RBody(args, guards); - Expect(14 /* "}" */); + Expect(20 /* "}" */); } void Parser::Ident(std::wstring& name) { Expect(_ident); name = t->val; } void Parser::Type(TypeAnnotation& typ) { TypeAnnotation typ2; TypeAtom typ3; - if (la->kind == 20 /* "[" */) { + if (la->kind == _lbrack) { Get(); Type(typ2); - Expect(21 /* "]" */); - typ = TypeAnnotation(TypeOperator::LIST, typ2); + Expect(_rbrack); + typ = TypeAnnotation(TypeOperator::LIST, {typ2}); } else if (StartOf(2)) { TypeTerm(typ3); typ = TypeAnnotation(typ3); - } else SynErr(35); + } else SynErr(38); } void Parser::FnTag(Function& f) { - std::wstring tag; TagModifier mod = TagModifier::NONE; - Ident(tag); - if (la->kind == 10 /* "-" */) { + Expression tag; TagModifier mod = TagModifier::NONE; + MetaSimpExpr(tag); + if (la->kind == 23 /* "-" */) { Get(); TagMod(mod); } - f.addTag(tag, mod); -} - -void Parser::VDecl(Function& f) { - std::wstring vname; Expression e; TypeAnnotation typ; - Ident(vname); - Expect(6 /* "=" */); - if (StartOf(3)) { - Expr(e); - Expect(8 /* ":" */); - Type(typ); - f.addDeclaration(vname, typ, e); - } else if (la->kind == 20 /* "[" */) { - ListLiteral(e); - Expect(8 /* ":" */); - Type(typ); - f.addListDeclaration(vname, typ, e); - } else SynErr(36); -} - -void Parser::Expr(Expression& e) { - Operator op; Expression e2; - SimExpr(e); - if (la->kind == 6 /* "=" */ || la->kind == 11 /* ">" */ || la->kind == 32 /* "<" */) { - RelOp(op); - SimExpr(e2); - e = Expression(op, {e, e2}); + f.addTag(std::move(tag), mod); +} + +void Parser::BDecl(CodeScope& scope) { + Expression body; + Expect(19 /* "{" */); + while (StartOf(3)) { + if (checkAssignment()) { + VDecl(scope); + Expect(18 /* ";" */); + } else if (la->kind == 11 /* ":" */) { + TagsDecl(scope); + Expect(18 /* ";" */); + } else { + Expr(body); + Expect(18 /* ";" */); + scope.setBody(body); + } } + Expect(20 /* "}" */); } void Parser::TypeTerm(TypeAtom& typ) { - if (la->kind == 15 /* "string" */) { + if (la->kind == 13 /* "string" */) { Get(); - } else if (la->kind == 16 /* "int" */) { + } else if (la->kind == 14 /* "int" */) { Get(); - } else if (la->kind == 17 /* "num" */) { + } else if (la->kind == 15 /* "num" */) { Get(); - } else if (la->kind == 18 /* "float" */) { + } else if (la->kind == 16 /* "float" */) { Get(); - } else if (la->kind == 19 /* "bool" */) { + } else if (la->kind == 17 /* "bool" */) { Get(); - } else SynErr(37); + } else SynErr(39); typ = Atom(t->val); } +void Parser::VDecl(CodeScope& f) { + std::wstring vname; Expression e; TypeAnnotation typ; + Ident(vname); + Expect(_assign); + if (la->kind == _lbrack) { + ListLiteral(e); + Expect(11 /* ":" */); + Type(typ); + } else if (la->kind == 21 /* "loop" */) { + LoopDecl(e, typ); + Expect(18 /* ";" */); + } else if (StartOf(4)) { + Expr(e); + Expect(11 /* ":" */); + Type(typ); + } else SynErr(40); + f.addDeclaration(move(vname), move(typ), move(e)); +} + void Parser::ListLiteral(Expression& e) { Expression e2; - Expect(20 /* "[" */); + Expect(_lbrack); e.setOp(Operator::LIST); - if (StartOf(3)) { + if (StartOf(4)) { Expr(e2); e.addArg(std::move(e2)); - while (la->kind == 9 /* "," */) { + while (la->kind == 12 /* "," */) { Get(); Expr(e2); e.addArg(std::move(e2)); } } - Expect(21 /* "]" */); + Expect(_rbrack); +} + +void Parser::LoopDecl(Expression& e, TypeAnnotation& typOut) { + std::wstring varIn, varEl; TypeAnnotation typEl; CodeScope block; + Expect(21 /* "loop" */); + Expect(22 /* "map" */); + Expect(_lparen); + Ident(varIn); + Expect(_implic); + Ident(varEl); + Expect(11 /* ":" */); + Type(typEl); + Expect(_rparen); + Expect(11 /* ":" */); + Type(typOut); + BDecl(block); + e = Expression(Operator::LOOP, {Expression(Atom(varIn))}); e.addBindings({Atom(varEl)}); + block.addArg(Atom(varEl), move(typEl)); e.addBlock(move(block)); +} + +void Parser::Expr(Expression& e) { + Operator op; Expression e2; + SimExpr(e); + if (la->kind == _assign || la->kind == 34 /* "<" */ || la->kind == 35 /* ">" */) { + RelOp(op); + SimExpr(e2); + e = Expression(op, {e, e2}); + } +} + +void Parser::TagsDecl(CodeScope& f) { + Expression tag; TagModifier mod = TagModifier::NONE; + Expect(11 /* ":" */); + while (la->kind == _ident || la->kind == 23 /* "-" */) { + MetaSimpExpr(tag); + if (la->kind == 23 /* "-" */) { + Get(); + TagMod(mod); + } + + } +} + +void Parser::MetaSimpExpr(Expression& e) { + std::wstring i1, infix; Expression e2; + if (la->kind == 23 /* "-" */) { + Get(); + MetaSimpExpr(e2); + e = Expression(Operator::NEG, {e2}); + } else if (checkParametersList()) { + Ident(i1); + e = Expression(Operator::CALL, {Expression(Atom(i1))}); + Expect(_lparen); + if (StartOf(4)) { + CalleeParams(e); + } + Expect(_rparen); + } else if (checkInfix()) { + Ident(i1); + Ident(infix); + MetaSimpExpr(e2); + e = Expression(Operator::CALL, {Expression(Atom(infix))}); + e.addArg(Expression(Atom(i1))); + e.addArg(std::move(e2)); + + } else if (la->kind == _ident) { + Ident(i1); + e = Expression(Atom(i1)); + } else SynErr(41); } void Parser::TagMod(TagModifier& mod) { - if (la->kind == 22 /* "assert" */) { + if (la->kind == 24 /* "assert" */) { Get(); mod = TagModifier::ASSERT; - } else if (la->kind == 23 /* "require" */) { + } else if (la->kind == 25 /* "require" */) { Get(); mod = TagModifier::REQUIRE; - } else SynErr(38); + } else SynErr(42); } void Parser::Domain(DomainAnnotation& dom) { - if (la->kind == 7 /* "function" */) { + if (la->kind == 10 /* "function" */) { Get(); dom = DomainAnnotation::FUNCTION; - } else if (la->kind == 26 /* "variable" */) { + } else if (la->kind == 28 /* "variable" */) { Get(); dom = DomainAnnotation::VARIABLE; - } else SynErr(39); + } else SynErr(43); } void Parser::RGuard(RuleGuards& guards) { Expression e; MetaExpr(e); guards.add(std::move(e)); } void Parser::RBody(const RuleArguments& args, const RuleGuards& guards) { Expression e; std::wstring msg; - Expect(27 /* "warning" */); + Expect(29 /* "warning" */); MetaExpr(e); - if (la->kind == 28 /* "message" */) { + if (la->kind == 30 /* "message" */) { Get(); Expect(_string); msg = t->val; } root.add(new RuleWarning(RuleArguments(args), RuleGuards(guards), std::move(e), Atom(msg))); } void Parser::MetaExpr(Expression& e) { Operator op; Expression e2; MetaExpr2(e); - if (la->kind == 10 /* "-" */) { + if (la->kind == _implic) { MetaOp(op); MetaExpr2(e2); e = Expression(op, {e, e2}); } } void Parser::MetaExpr2(Expression& e) { - std::wstring i1, i2, infix; - if (checkParametersList()) { - Ident(i1); - e = Expression(Operator::CALL, {Expression(Atom(i1))}); - Expect(_lparen); - if (StartOf(3)) { - CalleeParams(e); - } - Expect(_rparen); - } else if (checkInfix()) { - Ident(i1); - Ident(infix); - Ident(i2); - e = Expression(Operator::CALL, {Expression(Atom(infix))}); - e.addArg(Expression(Atom(i1))); - e.addArg(Expression(Atom(i2))); - - } else if (la->kind == _ident) { - Ident(i1); - e = Expression(Atom(i1)); - } else if (la->kind == _lparen) { + if (la->kind == _lparen) { Get(); MetaExpr(e); Expect(_rparen); - } else SynErr(40); + } else if (la->kind == _ident || la->kind == 23 /* "-" */) { + MetaSimpExpr(e); + } else SynErr(44); } void Parser::MetaOp(Operator& op) { - Expect(10 /* "-" */); - Expect(11 /* ">" */); + Expect(_implic); op = Operator::IMPL; } void Parser::CalleeParams(Expression& e) { Expression e2; Expr(e2); e.addArg(std::move(e2)); - while (la->kind == 9 /* "," */) { + while (la->kind == 12 /* "," */) { Get(); Expr(e2); e.addArg(std::move(e2)); } } void Parser::SimExpr(Expression& e) { Operator op; Expression e2; Term(e); - while (la->kind == 10 /* "-" */ || la->kind == 29 /* "+" */) { + while (la->kind == 23 /* "-" */ || la->kind == 31 /* "+" */) { AddOp(op); Term(e2); e = Expression(op, {e, e2}); } } void Parser::RelOp(Operator& op) { op = Operator::EQU; - if (la->kind == 6 /* "=" */) { + if (la->kind == _assign) { Get(); - Expect(6 /* "=" */); - } else if (la->kind == 32 /* "<" */) { + Expect(_assign); + } else if (la->kind == 34 /* "<" */) { Get(); op = Operator::LSS; - } else if (la->kind == 11 /* ">" */) { + } else if (la->kind == 35 /* ">" */) { Get(); op = Operator::GTR; - } else SynErr(41); + } else SynErr(45); } void Parser::Term(Expression& e) { Operator op; Expression e2; Factor(e); - while (la->kind == 30 /* "*" */ || la->kind == 31 /* "/" */) { + while (la->kind == 32 /* "*" */ || la->kind == 33 /* "/" */) { MulOp(op); Factor(e2); e = Expression(op, {e, e2}); } } void Parser::AddOp(Operator& op) { op = Operator::ADD; - if (la->kind == 29 /* "+" */) { + if (la->kind == 31 /* "+" */) { Get(); - } else if (la->kind == 10 /* "-" */) { + } else if (la->kind == 23 /* "-" */) { Get(); op = Operator::SUB; - } else SynErr(42); + } else SynErr(46); } void Parser::Factor(Expression& e) { std::wstring name; if (checkParametersList()) { Ident(name); e = Expression(Operator::CALL, {Atom(name)}); Expect(_lparen); - if (StartOf(3)) { + if (StartOf(4)) { CalleeParams(e); } Expect(_rparen); + } else if (checkIndex()) { + Ident(name); + e = Expression(Operator::INDEX, {Atom(name)}); + Expect(_lbrack); + CalleeParams(e); + Expect(_rbrack); } else if (la->kind == _ident) { Ident(name); e = Expression(Atom(name)); } else if (la->kind == _number) { Get(); e = Expression(Atom(t->val)); - } else if (la->kind == 10 /* "-" */) { + } else if (la->kind == 23 /* "-" */) { Get(); Factor(e); e = Expression(Operator::NEG, {e}); } else if (la->kind == _lparen) { Get(); Expr(e); Expect(_rparen); - } else SynErr(43); + } else SynErr(47); } void Parser::MulOp(Operator& op) { op = Operator::MUL; - if (la->kind == 30 /* "*" */) { + if (la->kind == 32 /* "*" */) { Get(); - } else if (la->kind == 31 /* "/" */) { + } else if (la->kind == 33 /* "/" */) { Get(); op = Operator::DIV; - } else SynErr(44); + } else SynErr(48); } // If the user declared a method Init and a mehtod Destroy they should // be called in the contructur and the destructor respctively. // // The following templates are used to recognize if the user declared // the methods Init and Destroy. template struct ParserInitExistsRecognizer { template struct ExistsIfInitIsDefinedMarker{}; struct InitIsMissingType { char dummy1; }; struct InitExistsType { char dummy1; char dummy2; }; // exists always template static InitIsMissingType is_here(...); // exist only if ExistsIfInitIsDefinedMarker is defined template static InitExistsType is_here(ExistsIfInitIsDefinedMarker*); enum { InitExists = (sizeof(is_here(NULL)) == sizeof(InitExistsType)) }; }; template struct ParserDestroyExistsRecognizer { template struct ExistsIfDestroyIsDefinedMarker{}; struct DestroyIsMissingType { char dummy1; }; struct DestroyExistsType { char dummy1; char dummy2; }; // exists always template static DestroyIsMissingType is_here(...); // exist only if ExistsIfDestroyIsDefinedMarker is defined template static DestroyExistsType is_here(ExistsIfDestroyIsDefinedMarker*); enum { DestroyExists = (sizeof(is_here(NULL)) == sizeof(DestroyExistsType)) }; }; // The folloing templates are used to call the Init and Destroy methods if they exist. // Generic case of the ParserInitCaller, gets used if the Init method is missing template::InitExists> struct ParserInitCaller { static void CallInit(T *t) { // nothing to do } }; // True case of the ParserInitCaller, gets used if the Init method exists template struct ParserInitCaller { static void CallInit(T *t) { t->Init(); } }; // Generic case of the ParserDestroyCaller, gets used if the Destroy method is missing template::DestroyExists> struct ParserDestroyCaller { static void CallDestroy(T *t) { // nothing to do } }; // True case of the ParserDestroyCaller, gets used if the Destroy method exists template struct ParserDestroyCaller { static void CallDestroy(T *t) { t->Destroy(); } }; void Parser::Parse() { t = NULL; la = dummyToken = new Token(); la->val = coco_string_create(L"Dummy Token"); Get(); Xreate(); Expect(0); } Parser::Parser(Scanner *scanner) { - maxT = 33; + maxT = 36; ParserInitCaller::CallInit(this); dummyToken = NULL; t = la = NULL; minErrDist = 2; errDist = minErrDist; this->scanner = scanner; errors = new Errors(); } bool Parser::StartOf(int s) { const bool T = true; const bool x = false; - static bool set[4][35] = { - {T,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x}, - {x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,T, T,T,T,T, T,x,x,x, x,x,x,x, x,x,x,x, x,x,x}, - {x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,T, T,T,T,T, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x}, - {x,T,T,x, T,x,x,x, x,x,T,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x} + static bool set[5][38] = { + {T,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x}, + {x,x,x,x, x,x,T,x, x,x,x,x, x,T,T,T, T,T,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x}, + {x,x,x,x, x,x,x,x, x,x,x,x, x,T,T,T, T,T,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x}, + {x,T,T,x, T,x,x,x, x,x,x,T, x,x,x,x, x,x,x,x, x,x,x,T, x,x,x,x, x,x,x,x, x,x,x,x, x,x}, + {x,T,T,x, T,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,T, x,x,x,x, x,x,x,x, x,x,x,x, x,x} }; return set[s][la->kind]; } Parser::~Parser() { ParserDestroyCaller::CallDestroy(this); delete errors; delete dummyToken; } Errors::Errors() { count = 0; } void Errors::SynErr(int line, int col, int n) { wchar_t* s; switch (n) { case 0: s = coco_string_create(L"EOF expected"); break; case 1: s = coco_string_create(L"ident expected"); break; case 2: s = coco_string_create(L"number expected"); break; case 3: s = coco_string_create(L"string expected"); break; case 4: s = coco_string_create(L"lparen expected"); break; case 5: s = coco_string_create(L"rparen expected"); break; - case 6: s = coco_string_create(L"\"=\" expected"); break; - case 7: s = coco_string_create(L"\"function\" expected"); break; - case 8: s = coco_string_create(L"\":\" expected"); break; - case 9: s = coco_string_create(L"\",\" expected"); break; - case 10: s = coco_string_create(L"\"-\" expected"); break; - case 11: s = coco_string_create(L"\">\" expected"); break; - case 12: s = coco_string_create(L"\"{\" expected"); break; - case 13: s = coco_string_create(L"\";\" expected"); break; - case 14: s = coco_string_create(L"\"}\" expected"); break; - case 15: s = coco_string_create(L"\"string\" expected"); break; - case 16: s = coco_string_create(L"\"int\" expected"); break; - case 17: s = coco_string_create(L"\"num\" expected"); break; - case 18: s = coco_string_create(L"\"float\" expected"); break; - case 19: s = coco_string_create(L"\"bool\" expected"); break; - case 20: s = coco_string_create(L"\"[\" expected"); break; - case 21: s = coco_string_create(L"\"]\" expected"); break; - case 22: s = coco_string_create(L"\"assert\" expected"); break; - case 23: s = coco_string_create(L"\"require\" expected"); break; - case 24: s = coco_string_create(L"\"rule\" expected"); break; - case 25: s = coco_string_create(L"\"case\" expected"); break; - case 26: s = coco_string_create(L"\"variable\" expected"); break; - case 27: s = coco_string_create(L"\"warning\" expected"); break; - case 28: s = coco_string_create(L"\"message\" expected"); break; - case 29: s = coco_string_create(L"\"+\" expected"); break; - case 30: s = coco_string_create(L"\"*\" expected"); break; - case 31: s = coco_string_create(L"\"/\" expected"); break; - case 32: s = coco_string_create(L"\"<\" expected"); break; - case 33: s = coco_string_create(L"??? expected"); break; - case 34: s = coco_string_create(L"invalid FDecl"); break; - case 35: s = coco_string_create(L"invalid Type"); break; - case 36: s = coco_string_create(L"invalid VDecl"); break; - case 37: s = coco_string_create(L"invalid TypeTerm"); break; - case 38: s = coco_string_create(L"invalid TagMod"); break; - case 39: s = coco_string_create(L"invalid Domain"); break; - case 40: s = coco_string_create(L"invalid MetaExpr2"); break; - case 41: s = coco_string_create(L"invalid RelOp"); break; - case 42: s = coco_string_create(L"invalid AddOp"); break; - case 43: s = coco_string_create(L"invalid Factor"); break; - case 44: s = coco_string_create(L"invalid MulOp"); break; + case 6: s = coco_string_create(L"lbrack expected"); break; + case 7: s = coco_string_create(L"rbrack expected"); break; + case 8: s = coco_string_create(L"assign expected"); break; + case 9: s = coco_string_create(L"implic expected"); break; + case 10: s = coco_string_create(L"\"function\" expected"); break; + case 11: s = coco_string_create(L"\":\" expected"); break; + case 12: s = coco_string_create(L"\",\" expected"); break; + case 13: s = coco_string_create(L"\"string\" expected"); break; + case 14: s = coco_string_create(L"\"int\" expected"); break; + case 15: s = coco_string_create(L"\"num\" expected"); break; + case 16: s = coco_string_create(L"\"float\" expected"); break; + case 17: s = coco_string_create(L"\"bool\" expected"); break; + case 18: s = coco_string_create(L"\";\" expected"); break; + case 19: s = coco_string_create(L"\"{\" expected"); break; + case 20: s = coco_string_create(L"\"}\" expected"); break; + case 21: s = coco_string_create(L"\"loop\" expected"); break; + case 22: s = coco_string_create(L"\"map\" expected"); break; + case 23: s = coco_string_create(L"\"-\" expected"); break; + case 24: s = coco_string_create(L"\"assert\" expected"); break; + case 25: s = coco_string_create(L"\"require\" expected"); break; + case 26: s = coco_string_create(L"\"rule\" expected"); break; + case 27: s = coco_string_create(L"\"case\" expected"); break; + case 28: s = coco_string_create(L"\"variable\" expected"); break; + case 29: s = coco_string_create(L"\"warning\" expected"); break; + case 30: s = coco_string_create(L"\"message\" expected"); break; + case 31: s = coco_string_create(L"\"+\" expected"); break; + case 32: s = coco_string_create(L"\"*\" expected"); break; + case 33: s = coco_string_create(L"\"/\" expected"); break; + case 34: s = coco_string_create(L"\"<\" expected"); break; + case 35: s = coco_string_create(L"\">\" expected"); break; + case 36: s = coco_string_create(L"??? expected"); break; + case 37: s = coco_string_create(L"invalid FDecl"); break; + case 38: s = coco_string_create(L"invalid Type"); break; + case 39: s = coco_string_create(L"invalid TypeTerm"); break; + case 40: s = coco_string_create(L"invalid VDecl"); break; + case 41: s = coco_string_create(L"invalid MetaSimpExpr"); break; + case 42: s = coco_string_create(L"invalid TagMod"); break; + case 43: s = coco_string_create(L"invalid Domain"); break; + case 44: s = coco_string_create(L"invalid MetaExpr2"); break; + case 45: s = coco_string_create(L"invalid RelOp"); break; + case 46: s = coco_string_create(L"invalid AddOp"); break; + case 47: s = coco_string_create(L"invalid Factor"); break; + case 48: s = coco_string_create(L"invalid MulOp"); break; default: { wchar_t format[20]; coco_swprintf(format, 20, L"error %d", n); s = coco_string_create(format); } break; } wprintf(L"-- line %d col %d: %ls\n", line, col, s); coco_string_delete(s); count++; } void Errors::Error(int line, int col, const wchar_t *s) { wprintf(L"-- line %d col %d: %ls\n", line, col, s); count++; } void Errors::Warning(int line, int col, const wchar_t *s) { wprintf(L"-- line %d col %d: %ls\n", line, col, s); } void Errors::Warning(const wchar_t *s) { wprintf(L"%ls\n", s); } void Errors::Exception(const wchar_t* s) { wprintf(L"%ls", s); exit(1); } diff --git a/coco/Parser.h b/coco/Parser.h index b986250..5d18bbc 100644 --- a/coco/Parser.h +++ b/coco/Parser.h @@ -1,138 +1,163 @@ /*---------------------------------------------------------------------- Compiler Generator Coco/R, Copyright (c) 1990, 2004 Hanspeter Moessenboeck, University of Linz extended by M. Loeberbauer & A. Woess, Univ. of Linz ported to C++ by Csaba Balazs, University of Szeged with improvements by Pat Terry, Rhodes University 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 2, 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, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. As an exception, it is allowed to write an extension of Coco/R that is used as a plugin in non-free software. If not otherwise stated, any source code generated by Coco/R (other than Coco/R itself) does not fall under the GNU General Public License. -----------------------------------------------------------------------*/ #if !defined(COCO_PARSER_H__) #define COCO_PARSER_H__ #include "ast.h" #include +using namespace xreate; +using namespace std; + #include "Scanner.h" class Errors { public: int count; // number of errors detected Errors(); void SynErr(int line, int col, int n); void Error(int line, int col, const wchar_t *s); void Warning(int line, int col, const wchar_t *s); void Warning(const wchar_t *s); void Exception(const wchar_t *s); }; // Errors class Parser { private: enum { _EOF=0, _ident=1, _number=2, _string=3, _lparen=4, - _rparen=5 + _rparen=5, + _lbrack=6, + _rbrack=7, + _assign=8, + _implic=9 }; int maxT; Token *dummyToken; int errDist; int minErrDist; void SynErr(int n); void Get(); void Expect(int n); bool StartOf(int s); void ExpectWeak(int n, int follow); bool WeakSeparator(int n, int syFol, int repFol); public: Scanner *scanner; Errors *errors; Token *t; // last recognized token Token *la; // lookahead token -AST root; // current program unit (procedure or main program) +xreate::AST root; // current program unit (procedure or main program) bool checkParametersList() { scanner->ResetPeek(); Token* x = scanner->Peek(); return la->kind == _ident && x->kind == _lparen; } bool checkInfix() { - scanner->ResetPeek(); + scanner->ResetPeek(); Token* x = scanner->Peek(); return la->kind == _ident && x->kind == _ident; } +bool checkIndex() +{ + scanner->ResetPeek(); + Token* x = scanner->Peek(); + return la->kind == _ident && x->kind == _lbrack; +} + +bool checkAssignment() +{ + scanner->ResetPeek(); + Token* x = scanner->Peek(); + return la->kind == _ident && x->kind == _assign; +} + Parser(Scanner *scanner); ~Parser(); void SemErr(const wchar_t* msg); void Xreate(); void FDecl(); void RuleDecl(); void Ident(std::wstring& name); void Type(TypeAnnotation& typ); void FnTag(Function& f); - void VDecl(Function& f); - void Expr(Expression& e); + void BDecl(CodeScope& scope); void TypeTerm(TypeAtom& typ); + void VDecl(CodeScope& f); void ListLiteral(Expression& e); + void LoopDecl(Expression& e, TypeAnnotation& typOut); + void Expr(Expression& e); + void TagsDecl(CodeScope& f); + void MetaSimpExpr(Expression& e); void TagMod(TagModifier& mod); void Domain(DomainAnnotation& dom); void RGuard(RuleGuards& guards); void RBody(const RuleArguments& args, const RuleGuards& guards); void MetaExpr(Expression& e); void MetaExpr2(Expression& e); void MetaOp(Operator& op); void CalleeParams(Expression& e); void SimExpr(Expression& e); void RelOp(Operator& op); void Term(Expression& e); void AddOp(Operator& op); void Factor(Expression& e); void MulOp(Operator& op); void Parse(); }; // end Parser #endif diff --git a/coco/Scanner.cpp b/coco/Scanner.cpp index 78e2975..c541a86 100644 --- a/coco/Scanner.cpp +++ b/coco/Scanner.cpp @@ -1,759 +1,766 @@ /*---------------------------------------------------------------------- Compiler Generator Coco/R, Copyright (c) 1990, 2004 Hanspeter Moessenboeck, University of Linz extended by M. Loeberbauer & A. Woess, Univ. of Linz ported to C++ by Csaba Balazs, University of Szeged with improvements by Pat Terry, Rhodes University 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 2, 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, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. As an exception, it is allowed to write an extension of Coco/R that is used as a plugin in non-free software. If not otherwise stated, any source code generated by Coco/R (other than Coco/R itself) does not fall under the GNU General Public License. -----------------------------------------------------------------------*/ #include #include #include "Scanner.h" // string handling, wide character wchar_t* coco_string_create(const wchar_t* value) { return coco_string_create(value, 0); } wchar_t* coco_string_create(const wchar_t *value, int startIndex) { int valueLen = 0; int len = 0; if (value) { valueLen = wcslen(value); len = valueLen - startIndex; } return coco_string_create(value, startIndex, len); } wchar_t* coco_string_create(const wchar_t *value, int startIndex, int length) { int len = 0; wchar_t* data; if (value) { len = length; } data = new wchar_t[len + 1]; wcsncpy(data, &(value[startIndex]), len); data[len] = 0; return data; } wchar_t* coco_string_create_upper(const wchar_t* data) { if (!data) { return NULL; } int dataLen = 0; if (data) { dataLen = wcslen(data); } wchar_t *newData = new wchar_t[dataLen + 1]; for (int i = 0; i <= dataLen; i++) { if ((L'a' <= data[i]) && (data[i] <= L'z')) { newData[i] = data[i] + (L'A' - L'a'); } else { newData[i] = data[i]; } } newData[dataLen] = L'\0'; return newData; } wchar_t* coco_string_create_lower(const wchar_t* data) { if (!data) { return NULL; } int dataLen = wcslen(data); return coco_string_create_lower(data, 0, dataLen); } wchar_t* coco_string_create_lower(const wchar_t* data, int startIndex, int dataLen) { if (!data) { return NULL; } wchar_t* newData = new wchar_t[dataLen + 1]; for (int i = 0; i <= dataLen; i++) { wchar_t ch = data[startIndex + i]; if ((L'A' <= ch) && (ch <= L'Z')) { newData[i] = ch - (L'A' - L'a'); } else { newData[i] = ch; } } newData[dataLen] = L'\0'; return newData; } wchar_t* coco_string_create_append(const wchar_t* data1, const wchar_t* data2) { wchar_t* data; int data1Len = 0; int data2Len = 0; if (data1) { data1Len = wcslen(data1); } if (data2) {data2Len = wcslen(data2); } data = new wchar_t[data1Len + data2Len + 1]; if (data1) { wcscpy(data, data1); } if (data2) { wcscpy(data + data1Len, data2); } data[data1Len + data2Len] = 0; return data; } wchar_t* coco_string_create_append(const wchar_t *target, const wchar_t appendix) { int targetLen = coco_string_length(target); wchar_t* data = new wchar_t[targetLen + 2]; wcsncpy(data, target, targetLen); data[targetLen] = appendix; data[targetLen + 1] = 0; return data; } void coco_string_delete(wchar_t* &data) { delete [] data; data = NULL; } int coco_string_length(const wchar_t* data) { if (data) { return wcslen(data); } return 0; } bool coco_string_endswith(const wchar_t* data, const wchar_t *end) { int dataLen = wcslen(data); int endLen = wcslen(end); return (endLen <= dataLen) && (wcscmp(data + dataLen - endLen, end) == 0); } int coco_string_indexof(const wchar_t* data, const wchar_t value) { const wchar_t* chr = wcschr(data, value); if (chr) { return (chr-data); } return -1; } int coco_string_lastindexof(const wchar_t* data, const wchar_t value) { const wchar_t* chr = wcsrchr(data, value); if (chr) { return (chr-data); } return -1; } void coco_string_merge(wchar_t* &target, const wchar_t* appendix) { if (!appendix) { return; } wchar_t* data = coco_string_create_append(target, appendix); delete [] target; target = data; } bool coco_string_equal(const wchar_t* data1, const wchar_t* data2) { return wcscmp( data1, data2 ) == 0; } int coco_string_compareto(const wchar_t* data1, const wchar_t* data2) { return wcscmp(data1, data2); } int coco_string_hash(const wchar_t *data) { int h = 0; if (!data) { return 0; } while (*data != 0) { h = (h * 7) ^ *data; ++data; } if (h < 0) { h = -h; } return h; } // string handling, ascii character wchar_t* coco_string_create(const char* value) { int len = 0; if (value) { len = strlen(value); } wchar_t* data = new wchar_t[len + 1]; for (int i = 0; i < len; ++i) { data[i] = (wchar_t) value[i]; } data[len] = 0; return data; } char* coco_string_create_char(const wchar_t *value) { int len = coco_string_length(value); char *res = new char[len + 1]; for (int i = 0; i < len; ++i) { res[i] = (char) value[i]; } res[len] = 0; return res; } void coco_string_delete(char* &data) { delete [] data; data = NULL; } Token::Token() { kind = 0; pos = 0; col = 0; line = 0; val = NULL; next = NULL; } Token::~Token() { coco_string_delete(val); } Buffer::Buffer(FILE* s, bool isUserStream) { // ensure binary read on windows #if _MSC_VER >= 1300 _setmode(_fileno(s), _O_BINARY); #endif stream = s; this->isUserStream = isUserStream; if (CanSeek()) { fseek(s, 0, SEEK_END); fileLen = ftell(s); fseek(s, 0, SEEK_SET); bufLen = (fileLen < COCO_MAX_BUFFER_LENGTH) ? fileLen : COCO_MAX_BUFFER_LENGTH; bufStart = INT_MAX; // nothing in the buffer so far } else { fileLen = bufLen = bufStart = 0; } bufCapacity = (bufLen>0) ? bufLen : COCO_MIN_BUFFER_LENGTH; buf = new unsigned char[bufCapacity]; if (fileLen > 0) SetPos(0); // setup buffer to position 0 (start) else bufPos = 0; // index 0 is already after the file, thus Pos = 0 is invalid if (bufLen == fileLen && CanSeek()) Close(); } Buffer::Buffer(Buffer *b) { buf = b->buf; bufCapacity = b->bufCapacity; b->buf = NULL; bufStart = b->bufStart; bufLen = b->bufLen; fileLen = b->fileLen; bufPos = b->bufPos; stream = b->stream; b->stream = NULL; isUserStream = b->isUserStream; } Buffer::Buffer(const unsigned char* buf, int len) { this->buf = new unsigned char[len]; memcpy(this->buf, buf, len*sizeof(unsigned char)); bufStart = 0; bufCapacity = bufLen = len; fileLen = len; bufPos = 0; stream = NULL; } Buffer::~Buffer() { Close(); if (buf != NULL) { delete [] buf; buf = NULL; } } void Buffer::Close() { if (!isUserStream && stream != NULL) { fclose(stream); stream = NULL; } } int Buffer::Read() { if (bufPos < bufLen) { return buf[bufPos++]; } else if (GetPos() < fileLen) { SetPos(GetPos()); // shift buffer start to Pos return buf[bufPos++]; } else if ((stream != NULL) && !CanSeek() && (ReadNextStreamChunk() > 0)) { return buf[bufPos++]; } else { return EoF; } } int Buffer::Peek() { int curPos = GetPos(); int ch = Read(); SetPos(curPos); return ch; } // beg .. begin, zero-based, inclusive, in byte // end .. end, zero-based, exclusive, in byte wchar_t* Buffer::GetString(int beg, int end) { int len = 0; wchar_t *buf = new wchar_t[end - beg]; int oldPos = GetPos(); SetPos(beg); while (GetPos() < end) buf[len++] = (wchar_t) Read(); SetPos(oldPos); wchar_t *res = coco_string_create(buf, 0, len); coco_string_delete(buf); return res; } int Buffer::GetPos() { return bufPos + bufStart; } void Buffer::SetPos(int value) { if ((value >= fileLen) && (stream != NULL) && !CanSeek()) { // Wanted position is after buffer and the stream // is not seek-able e.g. network or console, // thus we have to read the stream manually till // the wanted position is in sight. while ((value >= fileLen) && (ReadNextStreamChunk() > 0)); } if ((value < 0) || (value > fileLen)) { wprintf(L"--- buffer out of bounds access, position: %d\n", value); exit(1); } if ((value >= bufStart) && (value < (bufStart + bufLen))) { // already in buffer bufPos = value - bufStart; } else if (stream != NULL) { // must be swapped in fseek(stream, value, SEEK_SET); bufLen = fread(buf, sizeof(unsigned char), bufCapacity, stream); bufStart = value; bufPos = 0; } else { bufPos = fileLen - bufStart; // make Pos return fileLen } } // Read the next chunk of bytes from the stream, increases the buffer // if needed and updates the fields fileLen and bufLen. // Returns the number of bytes read. int Buffer::ReadNextStreamChunk() { int free = bufCapacity - bufLen; if (free == 0) { // in the case of a growing input stream // we can neither seek in the stream, nor can we // foresee the maximum length, thus we must adapt // the buffer size on demand. bufCapacity = bufLen * 2; unsigned char *newBuf = new unsigned char[bufCapacity]; memcpy(newBuf, buf, bufLen*sizeof(unsigned char)); delete [] buf; buf = newBuf; free = bufLen; } int read = fread(buf + bufLen, sizeof(unsigned char), free, stream); if (read > 0) { fileLen = bufLen = (bufLen + read); return read; } // end of stream reached return 0; } bool Buffer::CanSeek() { return (stream != NULL) && (ftell(stream) != -1); } int UTF8Buffer::Read() { int ch; do { ch = Buffer::Read(); // until we find a utf8 start (0xxxxxxx or 11xxxxxx) } while ((ch >= 128) && ((ch & 0xC0) != 0xC0) && (ch != EoF)); if (ch < 128 || ch == EoF) { // nothing to do, first 127 chars are the same in ascii and utf8 // 0xxxxxxx or end of file character } else if ((ch & 0xF0) == 0xF0) { // 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx int c1 = ch & 0x07; ch = Buffer::Read(); int c2 = ch & 0x3F; ch = Buffer::Read(); int c3 = ch & 0x3F; ch = Buffer::Read(); int c4 = ch & 0x3F; ch = (((((c1 << 6) | c2) << 6) | c3) << 6) | c4; } else if ((ch & 0xE0) == 0xE0) { // 1110xxxx 10xxxxxx 10xxxxxx int c1 = ch & 0x0F; ch = Buffer::Read(); int c2 = ch & 0x3F; ch = Buffer::Read(); int c3 = ch & 0x3F; ch = (((c1 << 6) | c2) << 6) | c3; } else if ((ch & 0xC0) == 0xC0) { // 110xxxxx 10xxxxxx int c1 = ch & 0x1F; ch = Buffer::Read(); int c2 = ch & 0x3F; ch = (c1 << 6) | c2; } return ch; } Scanner::Scanner(const unsigned char* buf, int len) { buffer = new Buffer(buf, len); Init(); } Scanner::Scanner(const wchar_t* fileName) { FILE* stream; char *chFileName = coco_string_create_char(fileName); if ((stream = fopen(chFileName, "rb")) == NULL) { wprintf(L"--- Cannot open file %ls\n", fileName); exit(1); } coco_string_delete(chFileName); buffer = new Buffer(stream, false); Init(); } Scanner::Scanner(FILE* s) { buffer = new Buffer(s, true); Init(); } Scanner::~Scanner() { char* cur = (char*) firstHeap; while(cur != NULL) { cur = *(char**) (cur + COCO_HEAP_BLOCK_SIZE); free(firstHeap); firstHeap = cur; } delete [] tval; delete buffer; } void Scanner::Init() { EOL = '\n'; eofSym = 0; - maxT = 33; - noSym = 33; + maxT = 36; + noSym = 36; int i; for (i = 65; i <= 90; ++i) start.set(i, 1); for (i = 97; i <= 122; ++i) start.set(i, 1); for (i = 48; i <= 57; ++i) start.set(i, 2); start.set(34, 3); start.set(40, 5); start.set(41, 6); - start.set(61, 7); - start.set(58, 8); - start.set(44, 9); - start.set(45, 10); - start.set(62, 11); - start.set(123, 12); + start.set(91, 7); + start.set(93, 8); + start.set(61, 9); + start.set(45, 21); + start.set(58, 11); + start.set(44, 12); start.set(59, 13); - start.set(125, 14); - start.set(91, 15); - start.set(93, 16); - start.set(43, 17); - start.set(42, 18); - start.set(47, 19); - start.set(60, 20); + start.set(123, 14); + start.set(125, 15); + start.set(43, 16); + start.set(42, 17); + start.set(47, 18); + start.set(60, 19); + start.set(62, 20); start.set(Buffer::EoF, -1); - keywords.set(L"function", 7); - keywords.set(L"string", 15); - keywords.set(L"int", 16); - keywords.set(L"num", 17); - keywords.set(L"float", 18); - keywords.set(L"bool", 19); - keywords.set(L"assert", 22); - keywords.set(L"require", 23); - keywords.set(L"rule", 24); - keywords.set(L"case", 25); - keywords.set(L"variable", 26); - keywords.set(L"warning", 27); - keywords.set(L"message", 28); + keywords.set(L"function", 10); + keywords.set(L"string", 13); + keywords.set(L"int", 14); + keywords.set(L"num", 15); + keywords.set(L"float", 16); + keywords.set(L"bool", 17); + keywords.set(L"loop", 21); + keywords.set(L"map", 22); + keywords.set(L"assert", 24); + keywords.set(L"require", 25); + keywords.set(L"rule", 26); + keywords.set(L"case", 27); + keywords.set(L"variable", 28); + keywords.set(L"warning", 29); + keywords.set(L"message", 30); tvalLength = 128; tval = new wchar_t[tvalLength]; // text of current token // COCO_HEAP_BLOCK_SIZE byte heap + pointer to next heap block heap = malloc(COCO_HEAP_BLOCK_SIZE + sizeof(void*)); firstHeap = heap; heapEnd = (void**) (((char*) heap) + COCO_HEAP_BLOCK_SIZE); *heapEnd = 0; heapTop = heap; if (sizeof(Token) > COCO_HEAP_BLOCK_SIZE) { wprintf(L"--- Too small COCO_HEAP_BLOCK_SIZE\n"); exit(1); } pos = -1; line = 1; col = 0; charPos = -1; oldEols = 0; NextCh(); if (ch == 0xEF) { // check optional byte order mark for UTF-8 NextCh(); int ch1 = ch; NextCh(); int ch2 = ch; if (ch1 != 0xBB || ch2 != 0xBF) { wprintf(L"Illegal byte order mark at start of file"); exit(1); } Buffer *oldBuf = buffer; buffer = new UTF8Buffer(buffer); col = 0; charPos = -1; delete oldBuf; oldBuf = NULL; NextCh(); } pt = tokens = CreateToken(); // first token is a dummy } void Scanner::NextCh() { if (oldEols > 0) { ch = EOL; oldEols--; } else { pos = buffer->GetPos(); // buffer reads unicode chars, if UTF8 has been detected ch = buffer->Read(); col++; charPos++; // replace isolated '\r' by '\n' in order to make // eol handling uniform across Windows, Unix and Mac if (ch == L'\r' && buffer->Peek() != L'\n') ch = EOL; if (ch == EOL) { line++; col = 0; } } } void Scanner::AddCh() { if (tlen >= tvalLength) { tvalLength *= 2; wchar_t *newBuf = new wchar_t[tvalLength]; memcpy(newBuf, tval, tlen*sizeof(wchar_t)); delete [] tval; tval = newBuf; } if (ch != Buffer::EoF) { tval[tlen++] = ch; NextCh(); } } bool Scanner::Comment0() { int level = 1, pos0 = pos, line0 = line, col0 = col, charPos0 = charPos; NextCh(); if (ch == L'/') { NextCh(); for(;;) { if (ch == 10) { level--; if (level == 0) { oldEols = line - line0; NextCh(); return true; } NextCh(); } else if (ch == buffer->EoF) return false; else NextCh(); } } else { buffer->SetPos(pos0); NextCh(); line = line0; col = col0; charPos = charPos0; } return false; } bool Scanner::Comment1() { int level = 1, pos0 = pos, line0 = line, col0 = col, charPos0 = charPos; NextCh(); if (ch == L'*') { NextCh(); for(;;) { if (ch == L'*') { NextCh(); if (ch == L'/') { level--; if (level == 0) { oldEols = line - line0; NextCh(); return true; } NextCh(); } } else if (ch == L'/') { NextCh(); if (ch == L'*') { level++; NextCh(); } } else if (ch == buffer->EoF) return false; else NextCh(); } } else { buffer->SetPos(pos0); NextCh(); line = line0; col = col0; charPos = charPos0; } return false; } void Scanner::CreateHeapBlock() { void* newHeap; char* cur = (char*) firstHeap; while(((char*) tokens < cur) || ((char*) tokens > (cur + COCO_HEAP_BLOCK_SIZE))) { cur = *((char**) (cur + COCO_HEAP_BLOCK_SIZE)); free(firstHeap); firstHeap = cur; } // COCO_HEAP_BLOCK_SIZE byte heap + pointer to next heap block newHeap = malloc(COCO_HEAP_BLOCK_SIZE + sizeof(void*)); *heapEnd = newHeap; heapEnd = (void**) (((char*) newHeap) + COCO_HEAP_BLOCK_SIZE); *heapEnd = 0; heap = newHeap; heapTop = heap; } Token* Scanner::CreateToken() { Token *t; if (((char*) heapTop + (int) sizeof(Token)) >= (char*) heapEnd) { CreateHeapBlock(); } t = (Token*) heapTop; heapTop = (void*) ((char*) heapTop + sizeof(Token)); t->val = NULL; t->next = NULL; return t; } void Scanner::AppendVal(Token *t) { int reqMem = (tlen + 1) * sizeof(wchar_t); if (((char*) heapTop + reqMem) >= (char*) heapEnd) { if (reqMem > COCO_HEAP_BLOCK_SIZE) { wprintf(L"--- Too long token value\n"); exit(1); } CreateHeapBlock(); } t->val = (wchar_t*) heapTop; heapTop = (void*) ((char*) heapTop + reqMem); wcsncpy(t->val, tval, tlen); t->val[tlen] = L'\0'; } Token* Scanner::NextToken() { while (ch == ' ' || (ch >= 9 && ch <= 10) || ch == 13 ) NextCh(); if ((ch == L'/' && Comment0()) || (ch == L'/' && Comment1())) return NextToken(); int recKind = noSym; int recEnd = pos; t = CreateToken(); t->pos = pos; t->col = col; t->line = line; t->charPos = charPos; int state = start.state(ch); tlen = 0; AddCh(); switch (state) { case -1: { t->kind = eofSym; break; } // NextCh already done case 0: { case_0: if (recKind != noSym) { tlen = recEnd - t->pos; SetScannerBehindT(); } t->kind = recKind; break; } // NextCh already done case 1: case_1: recEnd = pos; recKind = 1; - if ((ch >= L'0' && ch <= L'9') || (ch >= L'A' && ch <= L'Z') || (ch >= L'a' && ch <= L'z')) {AddCh(); goto case_1;} + if ((ch >= L'0' && ch <= L'9') || (ch >= L'A' && ch <= L'Z') || ch == L'_' || (ch >= L'a' && ch <= L'z')) {AddCh(); goto case_1;} else {t->kind = 1; wchar_t *literal = coco_string_create(tval, 0, tlen); t->kind = keywords.get(literal, t->kind); coco_string_delete(literal); break;} case 2: case_2: recEnd = pos; recKind = 2; if ((ch >= L'0' && ch <= L'9')) {AddCh(); goto case_2;} else {t->kind = 2; break;} case 3: case_3: if (ch <= L'!' || (ch >= L'#' && ch <= 65535)) {AddCh(); goto case_3;} else if (ch == L'"') {AddCh(); goto case_4;} else {goto case_0;} case 4: case_4: {t->kind = 3; break;} case 5: {t->kind = 4; break;} case 6: {t->kind = 5; break;} case 7: {t->kind = 6; break;} case 8: - {t->kind = 8; break;} + {t->kind = 7; break;} case 9: - {t->kind = 9; break;} + {t->kind = 8; break;} case 10: - {t->kind = 10; break;} + case_10: + {t->kind = 9; break;} case 11: {t->kind = 11; break;} case 12: {t->kind = 12; break;} case 13: - {t->kind = 13; break;} + {t->kind = 18; break;} case 14: - {t->kind = 14; break;} + {t->kind = 19; break;} case 15: {t->kind = 20; break;} case 16: - {t->kind = 21; break;} + {t->kind = 31; break;} case 17: - {t->kind = 29; break;} + {t->kind = 32; break;} case 18: - {t->kind = 30; break;} + {t->kind = 33; break;} case 19: - {t->kind = 31; break;} + {t->kind = 34; break;} case 20: - {t->kind = 32; break;} + {t->kind = 35; break;} + case 21: + recEnd = pos; recKind = 23; + if (ch == L'>') {AddCh(); goto case_10;} + else {t->kind = 23; break;} } AppendVal(t); return t; } void Scanner::SetScannerBehindT() { buffer->SetPos(t->pos); NextCh(); line = t->line; col = t->col; charPos = t->charPos; for (int i = 0; i < tlen; i++) NextCh(); } // get the next token (possibly a token already seen during peeking) Token* Scanner::Scan() { if (tokens->next == NULL) { return pt = tokens = NextToken(); } else { pt = tokens = tokens->next; return tokens; } } // peek for the next token, ignore pragmas Token* Scanner::Peek() { do { if (pt->next == NULL) { pt->next = NextToken(); } pt = pt->next; } while (pt->kind > maxT); // skip pragmas return pt; } // make sure that peeking starts at the current scan position void Scanner::ResetPeek() { pt = tokens; } diff --git a/coco/xreate.ATG b/coco/xreate.ATG index 7d4eb54..8a7ea6e 100644 --- a/coco/xreate.ATG +++ b/coco/xreate.ATG @@ -1,194 +1,242 @@ #include "ast.h" #include +using namespace xreate; +using namespace std; COMPILER Xreate -AST root; // current program unit (procedure or main program) +xreate::AST root; // current program unit (procedure or main program) bool checkParametersList() { scanner->ResetPeek(); Token* x = scanner->Peek(); return la->kind == _ident && x->kind == _lparen; } bool checkInfix() { - scanner->ResetPeek(); + scanner->ResetPeek(); Token* x = scanner->Peek(); return la->kind == _ident && x->kind == _ident; } +bool checkIndex() +{ + scanner->ResetPeek(); + Token* x = scanner->Peek(); + return la->kind == _ident && x->kind == _lbrack; +} + +bool checkAssignment() +{ + scanner->ResetPeek(); + Token* x = scanner->Peek(); + return la->kind == _ident && x->kind == _assign; +} + CHARACTERS letter = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz". any = ANY - '"'. digit = "0123456789". cr = '\r'. lf = '\n'. tab = '\t'. TOKENS - ident = letter {letter | digit}. + ident = letter {letter | digit | '_'}. number = digit {digit}. string = '"' { any } '"'. lparen = '('. rparen = ')'. + lbrack = '['. + rbrack = ']'. + assign = '='. + implic = '-' '>'. COMMENTS FROM "/*" TO "*/" NESTED COMMENTS FROM "//" TO lf IGNORE cr + lf + tab PRODUCTIONS Xreate = { ( FDecl | RuleDecl ) }. Ident = ident (. name = t->val; .). -FDecl<> = (. std::wstring fname; Expression fbody; std::wstring varname; TypeAnnotation typIn; TypeAnnotation typOut; .) -Ident '=' "function" ':' (. Function f = Function(fname); .) +FDecl<> = (. std::wstring fname; std::wstring varname; TypeAnnotation typIn; TypeAnnotation typOut; .) +Ident assign "function" ':' (. Function f = Function(fname); .) ( Type (. f.setReturnType(typOut); .) -| '('Ident ':' Type (. f.addArg(varname, typIn); .) -{',' Ident ':' Type (. f.addArg(varname, typIn);.) -} ')' '-' '>' Type (. f.setReturnType(typOut); .) +| '(' [Ident ':' Type (. f.addArg(std::move(varname), move(typIn)); .) +{',' Ident ':' Type (. f.addArg(std::move(varname), move(typIn));.) +}] ')' implic Type (. f.setReturnType(typOut); .) {',' FnTag } -) '{' {VDecl ';' } -Expr ';' '}' (. f.setBody(fbody); root.add(f); .) . +) BDecl (. root.add(f); .) +. TypeTerm = ("string" | "int" | "num" | "float" | "bool") (. typ = Atom(t->val); .) . Type = (. TypeAnnotation typ2; TypeAtom typ3; .) -('[' Type ']' (. typ = TypeAnnotation(TypeOperator::LIST, typ2); .) +('[' Type ']' (. typ = TypeAnnotation(TypeOperator::LIST, {typ2}); .) | TypeTerm (. typ = TypeAnnotation(typ3); .) ) . -VDecl = (. std::wstring vname; Expression e; TypeAnnotation typ; .) -Ident '=' -(Expr ':' Type (. f.addDeclaration(vname, typ, e); .) -|ListLiteral ':' Type (. f.addListDeclaration(vname, typ, e); .) -). +VDecl = (. std::wstring vname; Expression e; TypeAnnotation typ; .) +Ident assign +(ListLiteral ':' Type +| LoopDecl ';' +| Expr ':' Type +) (. f.addDeclaration(move(vname), move(typ), move(e)); .). + +BDecl = (. Expression body; .) +'{' { ( + IF(checkAssignment()) VDecl ';' + | TagsDecl ';' + | Expr ';' (. scope.setBody(body); .) +)} +'}'. + +LoopDecl = (. std::wstring varIn, varEl; TypeAnnotation typEl; CodeScope block; .) + + "loop" "map" '(' Ident implic Ident ':' Type ')' ':' Type BDecl + (. e = Expression(Operator::LOOP, {Expression(Atom(varIn))}); e.addBindings({Atom(varEl)}); + block.addArg(Atom(varEl), move(typEl)); e.addBlock(move(block)); .) +. + /*============================ METAPROGRAMMING ===============================*/ - -FnTag = (.std::wstring tag; TagModifier mod = TagModifier::NONE; .) -Ident -['-' TagMod] (. f.addTag(tag, mod); .). + +TagsDecl = (. Expression tag; TagModifier mod = TagModifier::NONE; .) +':' { MetaSimpExpr ['-' TagMod] (. /*f.addTag(std::move(tag), mod); */ .) +}. + +FnTag = (. Expression tag; TagModifier mod = TagModifier::NONE; .) +MetaSimpExpr +['-' TagMod] (. f.addTag(std::move(tag), mod); .). TagMod = ( "assert" (. mod = TagModifier::ASSERT; .) | "require" (. mod = TagModifier::REQUIRE; .) ). RuleDecl<> = "rule" ':' (. RuleArguments args; RuleGuards guards; DomainAnnotation typ; std::wstring arg; .) '(' Ident ':' Domain (. args.add(arg, typ); .) {',' Ident ':'Domain (. args.add(arg, typ); .) } ')' ["case" RGuard {',' RGuard}] - (. .) -'{' RBody '}' . +'{' RBody '}' . Domain = ( "function" (. dom = DomainAnnotation::FUNCTION; .) | "variable" (. dom = DomainAnnotation::VARIABLE; .) ). RGuard= (. Expression e; .) MetaExpr (. guards.add(std::move(e)); .). MetaExpr= (.Operator op; Expression e2; .) MetaExpr2 [MetaOp MetaExpr2 (. e = Expression(op, {e, e2}); .) ]. -MetaExpr2= (. std::wstring i1, i2, infix; .) -( IF(checkParametersList()) Ident (. e = Expression(Operator::CALL, {Expression(Atom(i1))}); .) +MetaExpr2= +( +'(' MetaExpr ')' +| MetaSimpExpr +). + +MetaSimpExpr= (. std::wstring i1, infix; Expression e2; .) +( '-' MetaSimpExpr (. e = Expression(Operator::NEG, {e2}); .) +| IF(checkParametersList()) Ident (. e = Expression(Operator::CALL, {Expression(Atom(i1))}); .) '(' [ CalleeParams ] ')' -| IF(checkInfix()) Ident Ident Ident +| IF(checkInfix()) Ident Ident MetaSimpExpr (. e = Expression(Operator::CALL, {Expression(Atom(infix))}); e.addArg(Expression(Atom(i1))); - e.addArg(Expression(Atom(i2))); + e.addArg(std::move(e2)); .) | Ident (. e = Expression(Atom(i1)); .) -| '(' MetaExpr ')' ). RBody = (. Expression e; std::wstring msg; .) "warning" MetaExpr ["message" string (. msg = t->val; .) ] (. root.add(new RuleWarning(RuleArguments(args), RuleGuards(guards), std::move(e), Atom(msg))); .) . MetaOp< Operator& op> = - '-' '>' (. op = Operator::IMPL; .) + implic (. op = Operator::IMPL; .) . /*============================ Expressions ===============================*/ // dublicates CalleeParams ListLiteral = (. Expression e2; .) '[' (. e.setOp(Operator::LIST); .) [ Expr (. e.addArg(std::move(e2)); .) {',' Expr (. e.addArg(std::move(e2)); .) }] ']'. Expr< Expression& e> (. Operator op; Expression e2; .) = SimExpr< e> [ RelOp< op> SimExpr< e2> (. e = Expression(op, {e, e2}); .) ]. SimExpr< Expression& e> (. Operator op; Expression e2; .) = Term< e> { AddOp< op> Term< e2> (. e = Expression(op, {e, e2});.) }. Term< Expression& e> (. Operator op; Expression e2; .) = Factor< e> { MulOp< op> Factor< e2> (. e = Expression(op, {e, e2}); .) }. Factor< Expression& e> (. std::wstring name;.) = (IF (checkParametersList()) Ident< name> (. e = Expression(Operator::CALL, {Atom(name)}); .) '(' [CalleeParams] ')' + |IF (checkIndex()) Ident (. e = Expression(). e.setOp(Operator::INDEX); e.addArg(Atom(name)}); .) + lbrack CalleeParams rbrack | Ident< name> (. e = Expression(Atom(name)); .) | number (. e = Expression(Atom(t->val)); .) | '-' Factor< e> (. e = Expression(Operator::NEG, {e}); .) | '(' Expr ')' ). CalleeParams = (. Expression e2; .) Expr (. e.addArg(std::move(e2)); .) {',' Expr (. e.addArg(std::move(e2)); .) }. AddOp< Operator& op> = (. op = Operator::ADD; .) ( '+' | '-' (. op = Operator::SUB; .) ). MulOp< Operator& op> = (. op = Operator::MUL; .) ( '*' | '/' (. op = Operator::DIV; .) ). RelOp< Operator& op> = (. op = Operator::EQU; .) ( '=' '=' | '<' (. op = Operator::LSS; .) | '>' (. op = Operator::GTR; .) ). END Xreate. diff --git a/cpp/CMakeLists.txt b/cpp/CMakeLists.txt index e4f435f..b93b617 100644 --- a/cpp/CMakeLists.txt +++ b/cpp/CMakeLists.txt @@ -1,69 +1,89 @@ cmake_minimum_required(VERSION 2.8.11) -project(Xreate) +project(xreate) find_package(LLVM REQUIRED CONFIG) find_package(Qt5Core) message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}") message(STATUS "Using LLVMConfig.cmake in: ${LLVM_DIR}") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") set(SOURCE_FILES ./src/ast.cpp ./src/ast-compilation.cpp ./src/llvmlayer.cpp ./src/clasplayer.cpp + ./src/codeinstructions.cpp #./src/main.cpp + ./tests/tests.cpp + ./src/pass/cfgpass.cpp ./src/pass/functiontagspass.cpp ./src/pass/rulespass.cpp /opt/potassco/gringo-4.4.0-source/app/shared/src/clingocontrol.cc /opt/potassco/gringo-4.4.0-source/app/pyclingo/src/clingo_lib.cc ) -set(COCO_PATH "./../coco/") +set(COCO_PATH ${CMAKE_HOME_DIRECTORY}/../coco/) set(COCO_SOURCE_FILES ${COCO_PATH}/Parser.h ${COCO_PATH}/Scanner.h ${COCO_PATH}/Parser.cpp ${COCO_PATH}/Scanner.cpp ) set(POTASSCO_PATH "/opt/potassco/gringo-4.4.0-source") INCLUDE_DIRECTORIES(${COCO_PATH} ./src) INCLUDE_DIRECTORIES(${POTASSCO_PATH}/libgringo ${POTASSCO_PATH}/libclasp ${POTASSCO_PATH}/app/shared/include ${POTASSCO_PATH}/app/pyclingo/src ${POTASSCO_PATH}/libprogram_opts ) -execute_process(COMMAND ${COCO_PATH}/gen-xreate WORKING_DIRECTORY ${COCO_PATH} OUTPUT_VARIABLE COCO_OUTPUT) +#execute_process(COMMAND ${COCO_PATH}/gen-xreate WORKING_DIRECTORY OUTPUT_VARIABLE COCO_OUTPUT) + + + message(STATUS "COCO GRAMMAR BUILD STATUS:" ${COCO_OUTPUT}) include_directories(${LLVM_INCLUDE_DIRS}) add_definitions(${LLVM_DEFINITIONS}) add_executable(xreate ${SOURCE_FILES} ${COCO_SOURCE_FILES}) +set(COCO_TARGET cocoTarget) + +add_custom_target(${COCO_TARGET} + WORKING_DIRECTORY ${COCO_PATH} +) + +add_custom_command(TARGET ${COCO_TARGET} + PRE_BUILD + COMMAND ${COCO_PATH}/gen-xreate + WORKING_DIRECTORY ${COCO_PATH} +) + +#add_dependencies(${PROJECT_NAME} ${COCO_TARGET}) + llvm_map_components_to_libnames(llvm_libs support core irreader) message(STATUS "LLVM LIBS: " ${llvm_libs}) set (LIBCLASP_PATH ${POTASSCO_PATH}/build/debug) #find_library(LIBCLASP_LIBRARY_GRINGO NAMES gringo # HINTS ${LIBCLASP_PATH}) #find_library(LIBCLASP_LIBRARY_CLASP NAMES clasp # HINTS ${LIBCLASP_PATH}) set(LIBCLASP_LIBS ${LIBCLASP_PATH}/libclasp.a ${LIBCLASP_PATH}/libgringo.a ${LIBCLASP_PATH}/libprogram_opts.a ) message(STATUS ${LIBCLASP_LIBS}) target_link_libraries(xreate ${llvm_libs} pthread Qt5::Core ${LIBCLASP_LIBS}) add_definitions(-DWITH_THREADS=0) diff --git a/cpp/src/ast-compilation.cpp b/cpp/src/ast-compilation.cpp index bfa81ab..655a495 100644 --- a/cpp/src/ast-compilation.cpp +++ b/cpp/src/ast-compilation.cpp @@ -1,168 +1,185 @@ #include +#include "codeinstructions.h" + +using namespace xreate; + + llvm::Value * + CodeScope::compileExpression(const Expression &expr, LLVMLayer &l, const std::string * const hintRetVar) { + #define VARNAME(x) (hintRetVar==0 ? x: *hintRetVar) + llvm::Value *left; + llvm::Value *right; + + + switch (expr.__op) { + case Operator::ADD: + case Operator::SUB: + case Operator::MUL: + case Operator::DIV: + case Operator::EQU: + case Operator::LSS: + case Operator::GTR: + assert(expr.__state == Expression::COMPOUND); + assert(expr.operands.size() == 2); + + left = compileExpression(expr.operands[0], l); + right = compileExpression(expr.operands[1], l); + break; + + default:; + } + + switch (expr.__op) { + case Operator::ADD: + return l.builder.CreateAdd(left, right, VARNAME("tmp_add")); + break; + + case Operator::SUB: + return l.builder.CreateSub(left, right, VARNAME("tmp_sub")); + break; + + case Operator::MUL: + return l.builder.CreateMul(left, right, VARNAME("tmp_mul")); + break; + + case Operator::DIV: + return l.builder.CreateSDiv(left, right, VARNAME("tmp_div")); + break; + + case Operator::EQU: + left->getType()->dump(); + right->getType()->dump(); + return l.builder.CreateICmpEQ(left, right, VARNAME("tmp_equ")); + break; + + case Operator::LSS: + return l.builder.CreateICmpSLT(left, right, VARNAME("tmp_lss")); + break; + + case Operator::GTR: + return l.builder.CreateICmpSGT(left, right, VARNAME("tmp_gtr")); + break; + + case Operator::NEG: + left = compileExpression(expr.operands[0], l); + return l.builder.CreateNeg(left, VARNAME("tmp_neg")); + break; + + case Operator::CALL: { + assert(expr.__state == Expression::COMPOUND); + + const std::string &fname = expr.__valueS; + assert(l.ast->__indexFunctions.count(fname)); + + const Function &calleeFunc = l.ast->getFunctionById(l.ast->__indexFunctions[fname]); + llvm::Function *callee = calleeFunc.__raw; + + std::vector args; + args.reserve(expr.operands.size() - 1); + + std::transform(expr.operands.begin(), expr.operands.end(), std::inserter(args, args.end()), + [&l, this](const Expression &operand) { + return compileExpression(operand, l); + } + ); + + return l.builder.CreateCall(callee, args, VARNAME("tmp_call")); + } -llvm::Value* -Function::compileExpression(const Expression& expr, LLVMLayer& l, std::string* hintRetVar=0) -{ - std::string var; - if (hintRetVar && this->__vartable.count(*hintRetVar)) - { - var = *hintRetVar; - } - - #define VARNAME(x) (var.size()? var : x) - llvm::Value* left; llvm::Value* right; - - - switch (expr.__op) - { - case Operator::ADD: case Operator::SUB: case Operator::MUL: case Operator::DIV: case Operator::EQU: case Operator::LSS: case Operator::GTR: - assert(expr.__state == Expression::COMPOUND); - assert(expr.operands.size() == 2); - - left = compileExpression(expr.operands[0], l); - right = compileExpression(expr.operands[1], l); - break; - - default: ; - } - - switch (expr.__op) - { - case Operator::ADD: - return l.builder.CreateFAdd(left, right, VARNAME("tmp_add")); - break; - - case Operator::SUB: - return l.builder.CreateFSub(left, right, VARNAME("tmp_sub")); - break; - - case Operator::MUL: - return l.builder.CreateFMul(left, right, VARNAME("tmp_mul")); - break; - - case Operator::DIV: - return l.builder.CreateFDiv(left, right, VARNAME("tmp_div")); - break; - - case Operator::EQU: - return l.builder.CreateFCmpOEQ(left, right, VARNAME("tmp_equ")); - break; - - case Operator::LSS: - return l.builder.CreateFCmpOLT(left, right, VARNAME("tmp_lss")); - break; - - case Operator::GTR: - return l.builder.CreateFCmpOGT(left, right, VARNAME("tmp_gtr")); - break; - - case Operator::NEG: - left = compileExpression(expr.operands[0], l); - return l.builder.CreateFNeg(left, VARNAME("tmp_neg")); - break; - - case Operator::CALL: - { - assert(expr.__state == Expression::COMPOUND); - - const std::string& fname = expr.__valueS; - assert(root->__indexFunctions.count(fname)); - - const Function& calleeFunc = root->getFunctionById(root->__indexFunctions[fname]); - llvm::Function* callee = calleeFunc.__raw; - - std::vector args; - args.reserve(expr.operands.size()-1); - - std::transform(expr.operands.begin(), expr.operands.end(), std::inserter(args, args.end()), - [&l, this](const Expression &operand){return compileExpression(operand, l); } - ); - - return l.builder.CreateCall(callee, args, VARNAME("tmp_call")); - } - break; - - - case Operator::NONE: - assert(expr.__state != Expression::COMPOUND); - - switch (expr.__state) + case Operator::LIST: { - case Expression::IDENT: + return CodeInstruction(expr, l).compile(hintRetVar); + }; + + case Operator::INDEX: { - std::string vname = expr.__valueS; - assert(__vartable.count(vname)); - - VID vId =__vartable.at(vname); - if (__rawVars.count(vId)) - { - return this->__rawVars.at(vId); - } - - Expression& e = __declarations[vId]; - llvm::Value* result = compileExpression(e, l, &vname); - __rawVars[vId] = result; + assert(expr.operands.size()); + const std::string &name = expr.__valueS; + llvm::Value* heap = findSymbol(name, l); + std::vector indexes; + + indexes.push_back(llvm::ConstantInt::get(llvm::Type::getInt32Ty(llvm::getGlobalContext()), 0)); + std::transform(expr.operands.begin(), expr.operands.end(), std::inserter(indexes, indexes.end()), + [this, &l] (const Expression& op){return compileExpression(op, l);} + ); + + llvm::Value* result = l.builder.CreateGEP(heap, llvm::ArrayRef(indexes), VARNAME("tmp_el_of_arr")); + result->getType()->dump(); return result; - break; - } - - case Expression::NUMBER: - double literal = expr.__valueD; - return llvm::ConstantFP::get(llvm::getGlobalContext(), llvm::APFloat(literal)); }; - break; - - } - assert(false); - return 0; -} + case Operator::NONE: + assert(expr.__state != Expression::COMPOUND); -llvm::Function* -Function::compile(LLVMLayer &l) -{ + switch (expr.__state) { + case Expression::IDENT: { + const std::string &vname = expr.__valueS; + return findSymbol(vname, l); + } - std::vector types; - std::transform(__args.begin(), __args.end(), std::inserter(types, types.end()), - [this](std::string& arg) { - assert(__vartable.count(arg)); - VID argid = __vartable[arg]; + case Expression::NUMBER: + int literal = expr.__valueD; + return llvm::ConstantInt::get(llvm::Type::getInt32Ty(llvm::getGlobalContext()), literal); + }; - assert(__definitions.count(argid)); - return __definitions[argid].toLLVMType(); - } ); + break; - llvm::FunctionType* ft = llvm::FunctionType::get(__retType.toLLVMType(), types,false); - __raw = llvm::cast(l.module->getOrInsertFunction(__name,ft)); + } - llvm::Function::arg_iterator fargsI = __raw->arg_begin(); - for(std::string& arg : __args) - { - VID argid = __vartable[arg]; - - __rawVars[argid] = fargsI; - fargsI->setName(arg); - ++fargsI; + assert(false); + return 0; } - llvm::BasicBlock *block = llvm::BasicBlock::Create(llvm::getGlobalContext(), "entry", __raw); - l.builder.SetInsertPoint(block); - - l.builder.CreateRet(compileExpression(__body, l, 0)); - l.moveToGarbage(ft); - - return __raw; -}; - -void -AST::compile(LLVMLayer &layer) -{ - layer.module = new llvm::Module(getModuleName(),llvm::getGlobalContext()); - - for(Function& f: __functions) - { - llvm::Function* rawf = f.compile(layer); + llvm::Value * + CodeScope::compile(LLVMLayer &l, const std::string * const hintBlockName) { + if (hintBlockName) { + llvm::BasicBlock *block = llvm::BasicBlock::Create(llvm::getGlobalContext(), *hintBlockName, l.function); + l.builder.SetInsertPoint(block); + } + return compileExpression(__body, l, 0); } -} + + llvm::Function * + Function::compile(LLVMLayer &l) { + + std::vector types; + std::transform(__entry.__args.begin(), __entry.__args.end(), std::inserter(types, types.end()), + [this](const std::string &arg)->llvm::Type* { + assert(__entry.__vartable.count(arg)); + VID argid = __entry.__vartable.at(arg); + assert(__entry.__definitions.count(argid)); + return __entry.__definitions.at(argid).toLLVMType(); + }); + + llvm::FunctionType *ft = llvm::FunctionType::get(__retType.toLLVMType(), types, false); + __raw = llvm::cast(l.module->getOrInsertFunction(__name, ft)); + + llvm::Function::arg_iterator fargsI = __raw->arg_begin(); + for (std::string &arg : __entry.__args) { + VID argid = __entry.__vartable[arg]; + + __entry.__rawVars[argid] = fargsI; + fargsI->setName(arg); + ++fargsI; + } + + l.function = __raw; + const std::string blockName = "entry"; + l.builder.CreateRet(__entry.compile(l, &blockName)); + l.function = nullptr; + l.moveToGarbage(ft); + + return __raw; + }; + + void + AST::compile(LLVMLayer &layer) { + layer.ast = this; + layer.module = new llvm::Module(getModuleName(), llvm::getGlobalContext()); + + int __debug_fcount = __functions.size(); + for (Function &f: __functions) { + llvm::Function *rawf = f.compile(layer); + } + } \ No newline at end of file diff --git a/cpp/src/ast.cpp b/cpp/src/ast.cpp index 3faabe7..318aeaa 100644 --- a/cpp/src/ast.cpp +++ b/cpp/src/ast.cpp @@ -1,243 +1,384 @@ #include "ast.h" #include #include #include #include using namespace std; +namespace xreate{ + TypeAnnotation::TypeAnnotation() -{} +{ +} TypeAnnotation::TypeAnnotation(const Atom &typ) + : __value(typ.get()) { - __value = typ.get(); + ; } -TypeAnnotation::TypeAnnotation(const TypeOperator &op, const TypeAnnotation &typ) +TypeAnnotation::TypeAnnotation (TypePrimitive typ) + : __value(typ) {} +TypeAnnotation::TypeAnnotation(TypeOperator op, std::initializer_list operands) + : __operator(op), __operands(operands) +{ + +} + +TypeAnnotation::TypeAnnotation (llvm_array_tag, TypePrimitive typ, int size) + :TypeAnnotation(TypeOperator::LIST, {typ}) +{ + __size=size; +} +/* +TypeAnnotation (struct_tag, std::initializer_list) +{} +*/ + llvm::Type* TypeAnnotation::toLLVMType() { - switch (__value) + switch (__operator) { - case Bool: - return llvm::Type::getInt1Ty(llvm::getGlobalContext()); + case TypeOperator::LIST: + { + assert(__operands.size()); + TypeAnnotation elTy = __operands.at(0); + + return llvm::ArrayType::get(elTy.toLLVMType(), __size); + } + + case TypeOperator::NONE: { + switch (__value) { + case TypePrimitive::Bool: + return llvm::Type::getInt1Ty(llvm::getGlobalContext()); + + case TypePrimitive::Int: + case TypePrimitive::i32: + case TypePrimitive::Num: + return llvm::Type::getInt32Ty(llvm::getGlobalContext()); + + case TypePrimitive::Float: + return llvm::Type::getDoubleTy(llvm::getGlobalContext()); - case Int: - case Float: - case Num: - return llvm::Type::getDoubleTy(llvm::getGlobalContext()); + default: + assert(false); + } + } default: assert(false); } - return NULL; + assert(false); + return nullptr; } Expression::Expression(const Atom& number) : __state(NUMBER), __op(Operator::NONE), __valueD(number.get()) { } Expression::Expression(const Atom &ident) : __state(IDENT), __op(Operator::NONE), __valueS(ident.get()) { } Expression::Expression(const Operator &op, std::initializer_list params) : __state(COMPOUND), __op(op) { - if (op == Operator::CALL) + if (op == Operator::CALL || op == Operator::INDEX) { assert(params.size() > 0); Expression arg = *params.begin(); assert(arg.__state == Expression::IDENT); __valueS = std::move(arg.__valueS); return; } operands.insert(operands.end(), params); } void Expression::setOp(Operator op) { __op = op; switch (op) { case Operator::NONE: __state = INVALID; break; default: __state = COMPOUND; break; } } void Expression::addArg(Expression &&arg) { operands.push_back(arg); } +void +Expression::addBindings(std::initializer_list> params) +{ + bindings.insert(bindings.end(), params); +} + +void +Expression::addBlock(CodeScope&& scope) +{ + blocks.push_back(scope); +} + +const std::vector& +Expression::getOperands() const +{ + return operands; +} + +double +Expression::getValueDouble() const +{ + return __valueD; +} + +const std::string& +Expression::getValueString() const +{ + return __valueS; +} + + + + Expression::Expression() : __op(Operator::NONE), __state(INVALID) {} AST::AST() { } void AST::add(Function &f) { - f.root = this; __functions.push_back(f); __indexFunctions[f.getName()] = __functions.size()-1; } void AST::add(MetaRuleAbstract *r) { __rules.push_back(unique_ptr(r)); } std::string AST::getModuleName() { const std::string name = "moduleTest"; return name; } FID AST::getFunctionsCount() const { return __functions.size(); } const Function& AST::getFunctionById(FID id)const { assert(id>=0 && id < __functions.size()); return __functions[id]; } void AST::run(LLVMLayer &l) { llvm::PassManager PM; PM.add(llvm::createPrintModulePass(llvm::outs())); PM.run(*l.module); } Function::Function(const Atom& name) - :__vCounter(0) { __name = name.get(); - } void -Function::addTag(const Atom& aname, const TagModifier amod) +Function::addTag(Expression&& tag, const TagModifier mod) { - cout << QString("Function annotation: %1 <- %2").arg(__name.c_str()).arg(aname.get().c_str()).toStdString()<>& +const std::vector& Function::getAnnotations() const { return __tags; } +const CodeScope& +Function::getEntryScope() const +{ + return __entry; +} + +CodeScope& +Function::getEntryScope() +{ + return __entry; +} + void -Function::addArg(const Atom &vname, const TypeAnnotation &typ) +Function::setEntryScope(CodeScope&& scope) { - VID id = registerVar(vname.get()); - __definitions[id] = typ; - __args.push_back(vname.get()); + __entry = scope; } void -Function::setBody(const Expression &body) +CodeScope::addArg(Atom && name, TypeAnnotation&& typ) { - __body = body; + VID id = registerVar(std::move(const_cast(name.get())), std::move(typ)); + __args.push_back(name.get()); +} + + ; + +void +Function::addArg(Atom && name, TypeAnnotation&& typ) +{ + __entry.addArg(move(name), move(typ)); } void Function::setReturnType(const TypeAnnotation &rtyp) { __retType = rtyp; } +const std::string& +Function::getName() const +{ + return __name; +} + +CodeScope::CodeScope() +{ + +} + VID -Function::registerVar(const std::string& vname) +CodeScope::registerVar(std::string&& name, TypeAnnotation &&typ) { - __vartable[vname] = ++__vCounter; + __vartable[name] = ++__vCounter; + __definitions[__vCounter] = typ; + return __vCounter; } -const std::string& -Function::getName() const +void +CodeScope::bindArg(llvm::Value* var, std::string&& name) { - return __name; + assert(__vartable.count(name)); + VID id = __vartable.at(name); + __rawVars[id] = var; } void -Function::addListDeclaration(const Atom &vname, const TypeAnnotation &typ, const Expression &e) -{} +CodeScope::addDeclaration(const Atom &&name, TypeAnnotation &&typ, Expression&& body) +{ + VID id = registerVar(std::move(const_cast(name.get())), move(typ)); + __declarations[id] = body; +} void -Function::addDeclaration(const Atom &vname, const TypeAnnotation &typ, const Expression &e) +CodeScope::setBody(const Expression &body) +{ + __body = body; +} + +llvm::Value* +CodeScope::findSymbol(const std::string &name, LLVMLayer &l) { - VID id = registerVar(vname.get()); - __definitions[id] = typ; - __declarations[id] = e; + //search var in current block + if (__vartable.count(name)) + { + VID vId = __vartable.at(name); + + //search in already compiled vars + if (__rawVars.count(vId)) + { + return __rawVars.at(vId); + } + + //search in ordinary decls + if (__declarations.count(vId)){ + const Expression& e = __declarations.at(vId); + + llvm::Value* result = compileExpression(e, l, &name); + __rawVars[vId] = result; + return result; + } + } + + //search in parent scope + if (__parent) + { + return __parent->findSymbol(name, l); + } + + //exception: Ident not found + assert(false); } + void RuleArguments::add(const Atom &arg, DomainAnnotation typ) { emplace_back(arg.get(), typ); } void RuleGuards::add(Expression&& e) { push_back(e); } MetaRuleAbstract:: MetaRuleAbstract(RuleArguments&& args, RuleGuards&& guards) : __args(std::move(args)), __guards(std::move(guards)) {} MetaRuleAbstract::~MetaRuleAbstract(){} RuleWarning:: RuleWarning(RuleArguments&& args, RuleGuards&& guards, Expression&& condition, Atom&& message) : MetaRuleAbstract(std::move(args), std::move(guards)), __condition(condition), __message(message.get()) {} RuleWarning::~RuleWarning(){} void RuleWarning::compile(ClaspLayer& layer) { layer.addRuleWarning(*this); } +} + diff --git a/cpp/src/ast.h b/cpp/src/ast.h index 52645f0..9f5298d 100644 --- a/cpp/src/ast.h +++ b/cpp/src/ast.h @@ -1,276 +1,324 @@ #ifndef AST_H #define AST_H #include #include #include #include "llvmlayer.h" #include +#include +#include + +namespace xreate { struct String_t{}; struct Identifier_t {}; struct Number_t {}; struct Type_t {}; template -class Atom{}; +class Atom {}; template<> class Atom { public: Atom(const std::wstring& value) { char buffer[32]; wcstombs(buffer, value.c_str(), 32); __value = buffer; } const std::string& get() const{return __value; } private: std::string __value; }; template<> class Atom { public: Atom(wchar_t* value) { __value = wcstol(value, 0, 10); } double get()const {return __value; } private: double __value; }; template<> class Atom { public: Atom(const std::wstring& value) : __value(value.begin(), value.end()) { } const std::string& get() const {return __value; } private: std::string __value; }; -enum TimePrimitive {Bool, Int, Float, Num, String}; +enum class TypePrimitive {Bool, Int, Float, Num, String, i32}; template<> class Atom { public: Atom(wchar_t* value) { char buffer_[32]; wcstombs(buffer_, value, 32); std::string buffer(buffer_); if (buffer=="bool"){ - __value = Bool; + __value = TypePrimitive ::Bool; } else if (buffer=="int") { - __value = Int; + __value = TypePrimitive::Int; } else if (buffer=="float") { - __value = Float; + __value = TypePrimitive::Float; } else if (buffer=="num") { - __value = Num; + __value = TypePrimitive::Num; } else if (buffer=="string") { - __value = String; + __value = TypePrimitive::String; } } - Atom () + Atom() { } - TimePrimitive get() const + TypePrimitive get() const { return __value; } private: - TimePrimitive __value; + TypePrimitive __value; }; typedef Atom TypeAtom; -enum class TypeOperator{LIST}; +enum class TypeOperator{NONE, LIST, STRUCT}; +struct llvm_array_tag {}; struct struct_tag{}; + const llvm_array_tag tag_array = llvm_array_tag(); + const struct_tag tag_struct = struct_tag(); class TypeAnnotation { public: + TypeAnnotation(); TypeAnnotation (const Atom& typ); - TypeAnnotation (const TypeOperator& op, const TypeAnnotation& typ); + TypeAnnotation (TypePrimitive typ); + TypeAnnotation (llvm_array_tag, TypePrimitive typ, int size); - TypeAnnotation(); + TypeAnnotation (TypeOperator op, std::initializer_list operands); + // TypeAnnotation (struct_tag, std::initializer_list); llvm::Type* toLLVMType(); private: - TimePrimitive __value; + TypePrimitive __value; + TypeOperator __operator = TypeOperator::NONE; + std::vector __operands; + int __size = 0; }; enum class Operator { -ADD, SUB, MUL, DIV, EQU, LSS, GTR, NEG, LIST, CALL, NONE, IMPL/* implication */ +ADD, SUB, MUL, DIV, EQU, LSS, GTR, NEG, LIST, CALL, NONE, IMPL, LOOP, INDEX/* implication */ }; class Function; class AST; +class CodeScope; class Expression { - friend class Function; + friend class CodeScope; friend class ClaspLayer; friend class CFGPass; public: Expression(const Operator &op, std::initializer_list params); Expression(const Atom& ident); Expression(const Atom& number); Expression(); void setOp(Operator op); void addArg(Expression&& arg); -protected: - Operator __op; + void addBindings(std::initializer_list> params); + void addBlock(CodeScope&& scope); + + const std::vector& getOperands() const; + double getValueDouble() const; + const std::string& getValueString() const; + +private: + Operator __op ; std::vector operands; + std::vector> bindings; + std::vector blocks; std::string __valueS; double __valueD; enum {INVALID, COMPOUND, IDENT, NUMBER, STRING} __state; }; typedef std::list ExpressionList; enum class TagModifier {NONE, ASSERT, REQUIRE}; enum class DomainAnnotation {FUNCTION, VARIABLE}; class RuleArguments: public std::vector> { public: void add(const Atom& name, DomainAnnotation typ); }; class RuleGuards: public std::vector { public: void add(Expression&& e); }; class ClaspLayer; class MetaRuleAbstract { public: MetaRuleAbstract(RuleArguments&& args, RuleGuards&& guards); virtual ~MetaRuleAbstract(); virtual void compile(ClaspLayer& layer) =0; protected: RuleArguments __args; RuleGuards __guards; }; class RuleWarning: public MetaRuleAbstract { friend class ClaspLayer; public: RuleWarning(RuleArguments&& args, RuleGuards&& guards, Expression&& condition, Atom&& message); virtual void compile(ClaspLayer& layer); ~RuleWarning(); private: std::string __message; Expression __condition; }; typedef unsigned int VID; /* class Expression: ExpressionAbstract { friend class CFGPass; public: llvm::Value* compile(LLVMLayer& l, Function* f, std::string* hintRetVar=0) const; }; */ typedef std::pair VariableDefinition; typedef std::pair VariableDeclaration; -class Function + +typedef std::pair Tag; + +class CodeScope { - friend class Expression; + friend class Function; friend class CFGPass; + public: - Function(const Atom& name); - void setReturnType(const TypeAnnotation& rtyp); - void addArg(const Atom& vname, const TypeAnnotation& typ); + CodeScope(); void setBody(const Expression& body); + void addDeclaration(const Atom &&name, TypeAnnotation &&typ, Expression&& body); - void addTag(const Atom& aname, const TagModifier amod); - const std::vector>& getAnnotations() const; + void addArg(Atom && name, TypeAnnotation&& typ); + void bindArg(llvm::Value* var, std::string&& name); + llvm::Value* compile(LLVMLayer &l, const std::string * const hintBlockName=0); + llvm::Value* findSymbol(const std::string &name, LLVMLayer &l); - void addDeclaration(const Atom & vname, const TypeAnnotation& typ, const Expression& e); - void addListDeclaration(const Atom & vname, const TypeAnnotation& typ, const Expression& e); +private: + std::unordered_map __definitions; + std::unordered_map __declarations; + std::map __vartable; + std::vector __args; + + Expression __body; + VID __vCounter=0; + + std::map __rawVars; + CodeScope * __parent=0; + + VID registerVar(std::string&& name, TypeAnnotation &&typ); + llvm::Value* compileExpression(const Expression& expr, LLVMLayer& l, const std::string* const hintRetVar = 0); +}; + +class Function +{ + friend class Expression; + friend class CodeScope; + friend class AST; + +public: + Function(const Atom& name); + + void addArg(Atom && name, TypeAnnotation&& typ); + void addTag(Expression&& tag, const TagModifier mod); + void setReturnType(const TypeAnnotation& rtyp); const std::string& getName() const; - llvm::Function* compile(LLVMLayer& l); - AST* root; + llvm::Function* compile(LLVMLayer& l); + const std::vector& getAnnotations() const; + const CodeScope& getEntryScope() const; + CodeScope& getEntryScope(); + void setEntryScope(CodeScope&& scope); private: + CodeScope __entry; std::string __name; TypeAnnotation __retType; - std::vector __args; - std::vector> __tags; - std::map __definitions; - std::map __declarations; - std::map __vartable; - Expression __body; + std::vector __tags; llvm::Function* __raw; - std::map __rawVars; - - VID __vCounter; - VID registerVar(const std::string& vname); - - llvm::Value* compileExpression(const Expression& expr, LLVMLayer& l, std::string* hintRetVar); }; typedef unsigned int FID; class AST { - friend class Function; + friend class CodeScope; friend class CFGPass; friend class RulesPass; public: AST(); void add(Function& f); void add(MetaRuleAbstract* r); void compile(LLVMLayer& l); void run(LLVMLayer& l); std::string getModuleName(); FID getFunctionsCount() const; const Function& getFunctionById(FID id) const; private: std::list> __rules; std::vector __functions; std::map __indexFunctions; }; +} #endif // AST_H diff --git a/cpp/src/clasplayer.cpp b/cpp/src/clasplayer.cpp index fe75d6d..2faebad 100644 --- a/cpp/src/clasplayer.cpp +++ b/cpp/src/clasplayer.cpp @@ -1,306 +1,305 @@ #include "clasplayer.h" #include // for defining logic programs #include // unfounded set checkers #include // for enumerating answer sets #include #include #include #include using namespace std; -bool -ClaspLayer::onModel(Gringo::Model const & model) -{ - std::list warnings; - cout << "Model: " << endl; - for (Gringo::Value atom : model.atoms(Gringo::Model::ATOMS)) - { - atom.print(cout); - cout << endl; - - auto hookI = __hooks.find(*(atom.name())); - - if (hookI != __hooks.end()) { - warnings.push_back(hookI->second); +namespace xreate { + bool + ClaspLayer::onModel(Gringo::Model const &model) { + std::list warnings; + cout << "Model: " << endl; + for (Gringo::Value atom : model.atoms(Gringo::Model::ATOMS)) { + atom.print(cout); + cout << endl; + + auto hookI = __hooks.find(*(atom.name())); + + if (hookI != __hooks.end()) { + warnings.push_back(hookI->second); + } } - } - - for (auto warning: warnings) - { - cout << "Warning: "<< warning << endl; - } -} -QStringList multiplyLists(std::list&& lists) -{ - QStringList result = lists.front(); - lists.pop_front(); - - for (QStringList& list: lists) - { - QStringList::const_iterator end = result.end(); - for (QStringList::iterator expr1I=result.begin(); expr1I &&lists) { + QStringList result = lists.front(); + lists.pop_front(); -void -ClaspLayer::addCFGData(CFGraph &&graph) -{ - ostream& cout = __partGeneral; + for (QStringList &list: lists) { + QStringList::const_iterator end = result.end(); + for (QStringList::iterator expr1I = result.begin(); expr1I < end; ++expr1I) { + if (list.size() == 0) continue; - cout <& relation: graph.__relations) - { - const string& tagFrom = graph.__nodes.at(relation.first); - const string& tagTo = graph.__nodes.at(relation.second); - - cout << (QString("call(%1, %2) .").arg(tagFrom.c_str()).arg(tagTo.c_str())).toStdString()<& tags) -{ - ostream& cout = __partTags; - - cout << (QString("function(%1) .").arg(function.c_str())).toStdString()<& argument) { - char* domain; - switch (argument.second) - { case DomainAnnotation::FUNCTION: - domain = "function"; - break; - case DomainAnnotation::VARIABLE: - domain = "variable"; - break; - } + void + ClaspLayer::addCFGData(CFGraph &&graph) { + ostream &cout = __partGeneral; - return QString("%1(%2)").arg(domain).arg(argument.first.c_str()); - }); + cout << endl << "%\t\tStatic analysis: CFG" << endl; - QStringList vars; - std::transform(rule.__args.begin(), rule.__args.end(), std::inserter(vars, vars.begin()), - [](const std::pair& argument) { - return argument.first.c_str(); - }); + for (const std::pair &relation: graph.__relations) { + const string &tagFrom = graph.__nodes.at(relation.first); + const string &tagTo = graph.__nodes.at(relation.second); - std::list guardsRaw; - std::transform(rule.__guards.begin(), rule.__guards.end(), std::inserter(guardsRaw, guardsRaw.begin()), - [this](const Expression& guard) { - return compile(guard); - }); + cout << (QString("call(%1, %2) .").arg(tagFrom.c_str()).arg(tagTo.c_str())).toStdString() << endl; + } + } - QStringList guards = multiplyLists(std::move(guardsRaw)); - QStringList&& branches = compileNeg(rule.__condition); + void + ClaspLayer::addFunctionTags(const std::string &function, const std::vector &tags) { + ostream &cout = __partTags; - for (const QString& guardsJoined: guards) - for(const QString& branch: branches) - { - const std::string&& hook = registerHook(rule.__message); + cout << (QString("function(%1) .").arg(function.c_str())).toStdString() << std::endl; - QString result = QString("%1(%2):-%3, %4, %5.") - .arg(hook.c_str()) - .arg(vars.join(", ")) - .arg(branch) - .arg(guardsJoined) - .arg(domains.join(", ")); + int tagsCount = 0; + for (const Tag &tag: tags) { + QStringList tagRaw = compile(tag.first); + assert(tagRaw.size() == 1); - __partGeneral<< result.toStdString() << endl; + cout << QString("tag(%1, %2).").arg(function.c_str()).arg(tagRaw.at(0)).toStdString() << endl; + ++tagsCount; + } + if (tagsCount == 0) { + cout << "%no tags at all" << endl; + } } -} - -QStringList -ClaspLayer::compile(const Expression& e) const -{ - QStringList result; - - switch(e.__op) - { - case Operator::CALL: - { - assert(e.__state == Expression::COMPOUND); - - std::list operands; - std::transform(e.operands.begin(), e.operands.end(), std::inserter(operands, operands.begin()), - [this](const Expression& e) {return compile(e);}); - QStringList&& operands_ = multiplyLists(std::move(operands)); - result.append(QString("%1(%2)").arg(e.__valueS.c_str()).arg(operands_.join(", "))); - break; + void + ClaspLayer::addRuleWarning(const RuleWarning &rule) { + //__partGeneral << rule << endl; + + QStringList domains; + std::transform(rule.__args.begin(), rule.__args.end(), std::inserter(domains, domains.begin()), + [](const std::pair &argument) { + char *domain; + switch (argument.second) { + case DomainAnnotation::FUNCTION: + domain = "function"; + break; + case DomainAnnotation::VARIABLE: + domain = "variable"; + break; + } + + return QString("%1(%2)").arg(domain).arg(argument.first.c_str()); + }); + + QStringList vars; + std::transform(rule.__args.begin(), rule.__args.end(), std::inserter(vars, vars.begin()), + [](const std::pair &argument) { + return argument.first.c_str(); + }); + + std::list guardsRaw; + std::transform(rule.__guards.begin(), rule.__guards.end(), std::inserter(guardsRaw, guardsRaw.begin()), + [this](const Expression &guard) { + return compile(guard); + }); + + QStringList guards = multiplyLists(std::move(guardsRaw)); + QStringList &&branches = compileNeg(rule.__condition); + + for (const QString &guardsJoined: guards) + for (const QString &branch: branches) { + const std::string &&hook = registerHook(rule.__message); + + QString result = QString("%1(%2):-%3, %4, %5.") + .arg(hook.c_str()) + .arg(vars.join(", ")) + .arg(branch) + .arg(guardsJoined) + .arg(domains.join(", ")); + + __partGeneral << result.toStdString() << endl; + } } - case Operator::NONE: - { - switch (e.__state) - { + QStringList + ClaspLayer::compile(const Expression &e) const { + QStringList result; + + switch (e.__op) { + case Operator::CALL: { + assert(e.__state == Expression::COMPOUND); + + std::list operands; + std::transform(e.operands.begin(), e.operands.end(), std::inserter(operands, operands.begin()), + [this](const Expression &e) { + return compile(e); + }); + + QStringList &&operands_ = multiplyLists(std::move(operands)); + result.append(QString("%1(%2)").arg(e.__valueS.c_str()).arg(operands_.join(", "))); + break; + } + case Operator::NEG: { + assert(e.operands.size() == 1); + + const Expression &op = e.operands.at(0); + QStringList &&rawOp = compile(op); + + assert(rawOp.size() == 1); + result.append(QString("not %1").arg(rawOp.at(0))); + break; + }; + + case Operator::NONE: { + switch (e.__state) { case Expression::IDENT: result.append(QString(e.__valueS.c_str())); break; case Expression::NUMBER: result.append(QString::number(e.__valueD)); break; default: assert(true); } - break; - } - } - - return result; -} + break; + } + } -QStringList -ClaspLayer::compileNeg(const Expression& e) const -{ - QStringList result; - switch(e.__op) - { - case Operator::IMPL: - { - assert(e.__state == Expression::COMPOUND); - assert(e.operands.size() == 2); - QStringList operands1 = compile(e.operands.at(0)); - QStringList operands2 = compile(e.operands.at(1)); - - for (const auto& op1: operands1) - for (const auto& op2: operands2) - { - result.append(QString("%1, not %2").arg(op1).arg(op2)); - } - break; + return result; } - default: - assert(true); + QStringList + ClaspLayer::compileNeg(const Expression &e) const { + QStringList result; + switch (e.__op) { + case Operator::IMPL: { + assert(e.__state == Expression::COMPOUND); + assert(e.operands.size() == 2); + QStringList operands1 = compile(e.operands.at(0)); + QStringList operands2 = compile(e.operands.at(1)); + + for (const auto &op1: operands1) + for (const auto &op2: operands2) { + result.append(QString("%1, not %2").arg(op1).arg(op2)); + } + break; + } + case Operator::NEG: { + assert(e.operands.size() == 1); + + const Expression &op = e.operands.at(0); + QStringList &&rawOp = compile(op); + + assert(rawOp.size() == 1); + result.append(rawOp.at(0)); + break; + }; + + default: + assert(true); + } + + return result; } - return result; -} + std::string + ClaspLayer::registerHook(const std::string &message) { + static int i = 0; + std::string hookId = "hook" + std::to_string(++i); + __hooks.insert(make_pair(hookId, message)); -std::string -ClaspLayer::registerHook(const std::string& message) -{ - static int i=0; - std::string hookId = "hook" + std::to_string(++i); - __hooks.insert(make_pair(hookId, message)); - - return hookId; -} + return hookId; + } -void -ClaspLayer::run() -{ - ostringstream program; - program << __partTags.str() << __partGeneral.str(); - cout << program.str() << endl; + void + ClaspLayer::run() { + ostringstream program; + program << __partTags.str() << __partGeneral.str(); + cout << program.str() << endl; - const char* argv[] = {nullptr, nullptr}; - ClingoLib ctl(2, argv); + const char *argv[] = {nullptr, nullptr}; + ClingoLib ctl(2, argv); - //prg.add("p", ["t"], "q(t).") - Gringo::FWStringVec vars{}; + //prg.add("p", ["t"], "q(t).") + Gringo::FWStringVec vars{}; ctl.add("base", vars, program.str()); - //prg.ground([("p", [2])]) + //prg.ground([("p", [2])]) Gringo::Control::GroundVec vals{std::make_pair("base", Gringo::FWValVec {})}; ctl.ground(vals, Gringo::Any()); - //solve + //solve Gringo::Control::Assumptions as; - Gringo::SolveResult result = ctl.solve(Gringo::Control::ModelHandler([&](Gringo::Model const &model){return this->onModel(model);}), std::move(as)); - - if (result == Gringo::SolveResult::SAT) - { - cout << "SUCCESSFULLY" << endl; - } else { - cout << "UNSUCCESSFULLY" << endl; + Gringo::SolveResult result = ctl.solve(Gringo::Control::ModelHandler([&](Gringo::Model const &model) { + return this->onModel(model); + }), std::move(as)); + + if (result == Gringo::SolveResult::SAT) { + cout << "SUCCESSFULLY" << endl; + } else { + cout << "UNSUCCESSFULLY" << endl; + } } -} -ClaspLayer::ClaspLayer() -{} + ClaspLayer::ClaspLayer() { + } /* void AspOutPrinter::reportSolution(const Clasp::Solver&, const Clasp::Enumerator&, bool complete) { if (complete) std::cout << "No more models!" << std::endl; else std::cout << "More models possible!" << std::endl; } void AspOutPrinter::reportModel(const Clasp::Solver& s, const Clasp::Enumerator&) { std::cout << "Model " << s.stats.solve.models << ": \n"; // get the symbol table from the solver const Clasp::AtomIndex& symTab = *s.strategies().symTab; for (Clasp::AtomIndex::const_iterator it = symTab.begin(); it != symTab.end(); ++it) { // print each named atom that is true w.r.t the current assignment } std::cout << std::endl; } */ - - /***************************************** * CFGraph ***************************************** */ void CFGraph::addNode(FID function, std::string&& tag) { - __nodes.insert(make_pair(function, move(tag))); + __nodes.emplace(function, tag); } bool CFGraph::existsNode(FID function) const { return __nodes.count(function); } void CFGraph::addLink(FID nodeFrom, FID nodeTo) { - assert(__nodes.count(nodeFrom)); - assert(__nodes.count(nodeTo)); - __relations.insert(std::make_pair(nodeFrom, nodeTo)); } +} \ No newline at end of file diff --git a/cpp/src/clasplayer.h b/cpp/src/clasplayer.h index c4ba9a5..fb2ca2c 100644 --- a/cpp/src/clasplayer.h +++ b/cpp/src/clasplayer.h @@ -1,50 +1,52 @@ #ifndef CLASPLAYER_H #define CLASPLAYER_H #include #include #include #include -typedef std::pair Tag; +namespace xreate { -class CFGraph; + class CFGraph; -class ClaspLayer -{ + class ClaspLayer { -public: - ClaspLayer(); + public: + AST *ast; - void addFunctionTags(const std::string& function, const std::vector& tags); - void addCFGData(CFGraph&& graph); - void addRuleWarning(const RuleWarning& rule); + ClaspLayer(); + void addFunctionTags(const std::string &function, const std::vector &tags); + void addCFGData(CFGraph &&graph); + void addRuleWarning(const RuleWarning &rule); - void run(); + void run(); -private: - std::map __hooks; - std::ostringstream __partTags; - std::ostringstream __partGeneral; + private: + std::map __hooks; + std::ostringstream __partTags; + std::ostringstream __partGeneral; - bool onModel(Gringo::Model const & model); + bool onModel(Gringo::Model const &model); + QStringList compile(const Expression &e) const; + QStringList compileNeg(const Expression &e) const; + std::string registerHook(const std::string &message); + }; - QStringList compile(const Expression& e) const; - QStringList compileNeg(const Expression& e) const; - std::string registerHook(const std::string& message); -}; + class CFGraph { + friend class ClaspLayer; -class CFGraph -{ - friend class ClaspLayer; -public: - void addNode(FID function, std::string&& tag); - void addLink(FID nodeFrom, FID nodeTo); - bool existsNode(FID function) const; - void print(std::ostream& cout) const; + public: + void addNode(FID function, std::string &&tag); -private: - std::map __relations; - std::map __nodes; -}; + void addLink(FID nodeFrom, FID nodeTo); + bool existsNode(FID function) const; + + void print(std::ostream &cout) const; + + private: + std::map __relations; + std::map __nodes; + }; +} #endif diff --git a/cpp/src/codeinstructions.cpp b/cpp/src/codeinstructions.cpp new file mode 100644 index 0000000..837d8a5 --- /dev/null +++ b/cpp/src/codeinstructions.cpp @@ -0,0 +1,86 @@ +#include "codeinstructions.h" +#include "llvmlayer.h" +#include "ast.h" + +using namespace llvm; +namespace xreate { + llvm::Value* + InstructionMap::compileDefault(const std::string * const hintRetVar) { + + CodeScope body; + std::string varIn; + std::string varOut; + std::string varEl; + int size; + CodeScope *scopeOuter; + + llvm::IntegerType *i32Tag = (llvm::IntegerType*) TypeAnnotation(TypePrimitive::i32).toLLVMType(); + const std::string itLoopName = "it"; + + Value *vecIn = scopeOuter->findSymbol(varIn, llvm); + Value *vecOut = scopeOuter->findSymbol(varOut, llvm); + + llvm::IRBuilder<> &builder = llvm.builder; + + llvm::BasicBlock *blockLoop = llvm::BasicBlock::Create(llvm::getGlobalContext(), "loop", llvm.function); + llvm::BasicBlock *blockBeforeLoop = builder.GetInsertBlock(); + llvm::BasicBlock *blockAfterLoop = builder.GetInsertBlock(); + Value *cond1 = llvm.builder.CreateICmpEQ(0, ConstantInt::get((i32Tag), size)); + builder.CreateCondBr(cond1, blockAfterLoop, blockLoop); + + builder.SetInsertPoint(blockLoop); + llvm::PHINode *itLoop = builder.CreatePHI(i32Tag, 2, itLoopName); + itLoop->addIncoming(llvm::ConstantInt::get(i32Tag, 0), blockBeforeLoop); + + Value *pElIn = builder.CreateGEP(vecIn, ArrayRef(std::vector{ConstantInt::get(i32Tag, 0), itLoop})); + Value *pElOut = builder.CreateGEP(vecOut, ArrayRef(std::vector{ConstantInt::get(i32Tag, 0), itLoop})); + + Value *elIn = builder.CreateLoad(pElIn, varEl); + + body.bindArg(elIn, std::string(varEl)); + Value *elOut = body.compile(llvm); + + builder.CreateStore(elOut, pElOut); + Value *itNextLoop = builder.CreateAdd(itLoop, ConstantInt::get(i32Tag, 1)); + itLoop->addIncoming(itNextLoop, builder.GetInsertBlock()); + + Value *cond2 = llvm.builder.CreateICmpSLT(itNextLoop, ConstantInt::get(i32Tag, size)); + builder.CreateCondBr(cond2, blockLoop, blockAfterLoop); + + builder.SetInsertPoint(blockAfterLoop); + + return elOut; + } + + /* + void InstructionMap::compileComputation() { + + } + */ + + + InstructionList::InstructionList(const Expression& e, LLVMLayer& l) + : llvm(l), __data(e), __size(e.getOperands().size()) + { + } + + llvm::Value* + InstructionList::compileDefault(const std::string * const hintRetVar) { + ArrayType* typList = (ArrayType*) (TypeAnnotation(tag_array, TypePrimitive::i32, __size).toLLVMType()); + Type*typI32 = TypeAnnotation(TypePrimitive::i32).toLLVMType(); + + std::vector list; + list.reserve(__size); + + const std::vector operands = __data.getOperands(); + std::transform(operands.begin(), operands.end(), std::inserter(list, list.begin()), + [typI32](const Expression& e){return ConstantFP::get(typI32, e.getValueDouble());}); + + Value* listSource = ConstantArray::get(typList, ArrayRef(list)); + Value* listDest = llvm.builder.CreateAlloca(typList, ConstantFP::get(typI32, __size), *hintRetVar); + + llvm.builder.CreateMemCpy(listDest, listSource, __size, 16); + + return listDest; + } +} \ No newline at end of file diff --git a/cpp/src/codeinstructions.h b/cpp/src/codeinstructions.h new file mode 100644 index 0000000..09877fb --- /dev/null +++ b/cpp/src/codeinstructions.h @@ -0,0 +1,65 @@ +#ifndef CODEINSTRUCTIONS_H +#define CODEINSTRUCTIONS_H + +#include "llvmlayer.h" +#include "ast.h" +#include + +namespace xreate { + +class InstructionMap +{ +public: + InstructionMap(const Expression& e, LLVMLayer& l); + llvm::Value* compileDefault(const std::string * const hintRetVar); + +private: + LLVMLayer& llvm; + const Expression& __data; +}; + +class InstructionList +{ +public: + InstructionList(const Expression& e, LLVMLayer& l); + llvm::Value* compileDefault(const std::string * const hintRetVar); + +private: + LLVMLayer& llvm; + int __size; + const Expression& __data; +}; + + + template + struct InstructionClasses {}; + + template<> + struct InstructionClasses { + typedef InstructionList base; + }; + + template<> + struct InstructionClasses { + typedef InstructionMap base; + }; + + template + class CodeInstruction: public InstructionClasses::base + { + typedef typename InstructionClasses::base InstructionImpl; + + public: + CodeInstruction(const Expression& e, LLVMLayer& l) + : InstructionImpl(e, l) + {} + + llvm::Value* compile(const std::string * const hintRetVar) + { + InstructionImpl::compileDefault(hintRetVar); + } + }; +} + + +#endif //CODEINSTRUCTIONS_H \ No newline at end of file diff --git a/cpp/src/llvmlayer.cpp b/cpp/src/llvmlayer.cpp index 97f5978..192ec38 100644 --- a/cpp/src/llvmlayer.cpp +++ b/cpp/src/llvmlayer.cpp @@ -1,13 +1,15 @@ #include "llvmlayer.h" using namespace llvm; +using namespace xreate; + LLVMLayer::LLVMLayer() :builder(getGlobalContext()) { } void LLVMLayer::moveToGarbage(void *o) { __garbage.push_back(o); } diff --git a/cpp/src/llvmlayer.h b/cpp/src/llvmlayer.h index 7cbe58e..8fc6d4d 100644 --- a/cpp/src/llvmlayer.h +++ b/cpp/src/llvmlayer.h @@ -1,31 +1,35 @@ #ifndef LLVMLAYER_H #define LLVMLAYER_H #include "llvm/IR/Module.h" #include "llvm/IR/Function.h" #include "llvm/PassManager.h" #include "llvm/IR/CallingConv.h" #include "llvm/IR/Verifier.h" #include "llvm/IR/IRPrintingPasses.h" #include "llvm/IR/IRBuilder.h" #include "llvm/Support/raw_ostream.h" #include "llvm/IR/LLVMContext.h" //#include "ast.h" +namespace xreate { + class AST; -class LLVMLayer -{ -public: - LLVMLayer(); + class LLVMLayer { + public: + LLVMLayer(); - llvm::Module* module; - llvm::IRBuilder<> builder; + AST *ast; + llvm::Module *module; + llvm::IRBuilder<> builder; + llvm::Function *function = 0; - void moveToGarbage(void* o); - llvm::Value* compile() const; + void moveToGarbage(void *o); -private: - std::vector __garbage; -}; + llvm::Value *compile() const; + private: + std::vector __garbage; + }; +} #endif // LLVMLAYER_H diff --git a/cpp/src/pass/cfgpass.cpp b/cpp/src/pass/cfgpass.cpp index 844abc3..f243f73 100644 --- a/cpp/src/pass/cfgpass.cpp +++ b/cpp/src/pass/cfgpass.cpp @@ -1,75 +1,99 @@ #include "cfgpass.h" #include using namespace std; +using namespace xreate; -CFGPass::CFGPass(const AST& entity) - : __root(entity) +CFGPass::CFGPass(ClaspLayer* claspLayer) + : clasp(claspLayer) { - } void -CFGPass::process(const Expression& entity, const FID funcId) +CFGPass::process(const Expression& entity,const Context& context) { switch(entity.__state) { case Expression::COMPOUND: - for (const Expression& op: entity.operands) - { - process(op, funcId); + { + switch (entity.__op){ + // First of all process all parameters + case Operator::CALL : case Operator::LIST: case Operator::LOOP: + for (const Expression& op: entity.operands) + { + process(op, context); + } } + // this is what we are looking for if (entity.__op == Operator::CALL) { const std::string& calleeName = entity.__valueS; - assert(__root.__indexFunctions.count(calleeName)); - FID calleeId = __root.__indexFunctions.at(calleeName); + assert(clasp->ast->__indexFunctions.count(calleeName)); + FID calleeId = clasp->ast->__indexFunctions.at(calleeName); - if (!__graph.existsNode(calleeId)) - { - __graph.addNode(calleeId, string(calleeName)); - process(calleeId); - } + __graph.addLink(context.id, calleeId); + break; + } - __graph.addLink(funcId, calleeId); + if (entity.__op == Operator::LOOP) + { + assert(entity.blocks.size()); + process(&(entity.blocks[0]), context); } - break; + + break; + } case Expression::IDENT: - const Function& func = __root.getFunctionById(funcId); - const std::string& identName = entity.__valueS; + const std::string& name = entity.__valueS; + //search in current scope: + if (context.scope->__vartable.count(name)) + { + VID ident = context.scope->__vartable.at(name); - assert(func.__vartable.count(identName)); - VID identId = func.__vartable.at(identName); + // if ident is scope arg then do nothing + if (! context.scope->__declarations.count(ident)) + { + break; + } - if (func.__declarations.count(identId)) - { - const Expression& identExpr = func.__declarations.at(identId); - process(identExpr, funcId); + // if ident declared within current scope, + const Expression& decl = context.scope->__declarations.at(ident); + process(decl, context); } + + //search in parent scope + if (context.scope->__parent) + { + Context context2 = context; + context2.scope = context.scope->__parent; + + process(entity, context2); + }; } } -void -CFGPass::process(const FID funcId) +void CFGPass:: process(const CodeScope* scope, Context context) { - const Function& f = __root.getFunctionById(funcId); - process(f.__body, funcId); + context.scope = scope; + process(scope->__body, context); } void -CFGPass::run(ClaspLayer& clasp) +CFGPass::run() { __graph = CFGraph(); cout << "CFGPass::run" << endl; - for(FID f=0, fcount=__root.getFunctionsCount(); fast->getFunctionsCount(); fast->getFunctionById(f); __graph.addNode(f, string(func.getName())); - process(f); - } - clasp.addCFGData(std::move(__graph)); + Context context{f, nullptr}; + process(&func.getEntryScope(), context); + }; + + clasp->addCFGData(std::move(__graph)); } diff --git a/cpp/src/pass/cfgpass.h b/cpp/src/pass/cfgpass.h index aff1589..11a0f36 100644 --- a/cpp/src/pass/cfgpass.h +++ b/cpp/src/pass/cfgpass.h @@ -1,25 +1,31 @@ // Control Flow Graph determination pass #ifndef CFGPASS_H #define CFGPASS_H #include "ast.h" #include #include #include "clasplayer.h" +namespace xreate { class CFGPass { public: - CFGPass(const AST& entity); - void run(ClaspLayer& clasp); + void run(); + CFGPass(ClaspLayer* claspLayer); private: - const AST& __root; + struct Context { + FID id; + const CodeScope* scope; + }; + CFGraph __graph; + ClaspLayer* clasp; - void process(const Expression& entity, const FID funcId); - void process(const FID funcId); -}; + void process(const Expression& entity, const Context& context); + void process(const CodeScope* scope, Context context); +}; } #endif // CFGPASS_H diff --git a/cpp/src/pass/functiontagspass.cpp b/cpp/src/pass/functiontagspass.cpp index e57c472..eb130de 100644 --- a/cpp/src/pass/functiontagspass.cpp +++ b/cpp/src/pass/functiontagspass.cpp @@ -1,18 +1,19 @@ #include "functiontagspass.h" #include using namespace std; +using namespace xreate; FunctionTagsPass::FunctionTagsPass(AST& root) : __root(root) { } void FunctionTagsPass::run(ClaspLayer& clasp) { for (FID id=0, count = __root.getFunctionsCount(); id < count; ++id) { const Function& f = __root.getFunctionById(id); clasp.addFunctionTags(f.getName(), f.getAnnotations()); } } diff --git a/cpp/src/pass/functiontagspass.h b/cpp/src/pass/functiontagspass.h index e58020f..17b4d53 100644 --- a/cpp/src/pass/functiontagspass.h +++ b/cpp/src/pass/functiontagspass.h @@ -1,17 +1,18 @@ #ifndef FUNCTIONTAGSPASS_H #define FUNCTIONTAGSPASS_H #include "ast.h" #include #include "clasplayer.h" +namespace xreate { class FunctionTagsPass { public: FunctionTagsPass(AST& root); void run(ClaspLayer& clasp); private: const AST& __root; -}; +};} #endif // FUNCTIONTAGSPASS_H diff --git a/cpp/src/pass/rulespass.cpp b/cpp/src/pass/rulespass.cpp index c97577c..066a530 100644 --- a/cpp/src/pass/rulespass.cpp +++ b/cpp/src/pass/rulespass.cpp @@ -1,14 +1,16 @@ #include "rulespass.h" +using namespace xreate; + RulesPass::RulesPass(const AST& ast) : __root(ast) {} void RulesPass::run(ClaspLayer& clasp) { for(const auto& rule: __root.__rules) { rule->compile(clasp); } } diff --git a/cpp/src/pass/rulespass.h b/cpp/src/pass/rulespass.h index eb7f8d4..7a82b71 100644 --- a/cpp/src/pass/rulespass.h +++ b/cpp/src/pass/rulespass.h @@ -1,16 +1,17 @@ #ifndef RULESPASS_H #define RULESPASS_H #include #include +namespace xreate { class RulesPass { public: RulesPass(const AST& ast); void run(ClaspLayer& clasp); private: const AST& __root; -}; +}; } #endif // RULESPASS_H diff --git a/cpp/tests/tests.cpp b/cpp/tests/tests.cpp index e3cc471..5a8efae 100644 --- a/cpp/tests/tests.cpp +++ b/cpp/tests/tests.cpp @@ -1,89 +1,88 @@ #include "Scanner.h" #include "Parser.h" #include "ast.h" #include #include #include "pass/cfgpass.h" #include "pass/functiontagspass.h" #include "pass/rulespass.h" #include "clasplayer.h" #include using namespace std; void testParser_1() { shared_ptr scanner(new Scanner(L"scripts/input.xreate")); shared_ptr parser(new Parser(scanner.get())); parser->Parse(); flush(cout); AST& root = parser->root; LLVMLayer l; root.compile(l); root.run(l); } void testClasp2() { shared_ptr scanner(new Scanner(L"scripts/input.xreate")); shared_ptr parser(new Parser(scanner.get())); parser->Parse(); flush(cout); if (parser->errors->count) { cout << "Found " << parser->errors->count << " errors. Stop" << endl; exit(1); } AST& root = parser->root; ClaspLayer clasp; FunctionTagsPass(root).run(clasp); RulesPass(root).run(clasp); - CFGPass(root).run(clasp); - //clasp.addRule(":- call(X, Y), tag(Y, unsafe), not tag(X, unsafe), function(X), function(Y)."); + CFGPass(&clasp).run(); clasp.run(); } void testUnsafeCode1() { - shared_ptr scanner(new Scanner(L"scripts/cases/unsafe-code.xreate")); + shared_ptr scanner(new Scanner(L"scripts/cases/bugs-code.xreate")); shared_ptr parser(new Parser(scanner.get())); parser->Parse(); flush(cout); if (parser->errors->count) { cout << "Found " << parser->errors->count << " errors. Stop" << endl; exit(1); } AST& root = parser->root; ClaspLayer clasp; FunctionTagsPass(root).run(clasp); RulesPass(root).run(clasp); - CFGPass(root).run(clasp); + CFGPass(&clasp).run(); //clasp.addRule(":- call(X, Y), tag(Y, unsafe), not tag(X, unsafe), function(X), function(Y)."); clasp.run(); } void tests_ListsMultiply() { } int main() { - testUnsafeCode1(); + testParser_1(); return 0; } diff --git a/problems/code-bugs.lp b/problems/code-bugs.lp new file mode 100644 index 0000000..a90de4f --- /dev/null +++ b/problems/code-bugs.lp @@ -0,0 +1,12 @@ +tag(fun1, bug(1)). +tag(fun2, bug(2)). + + +call(fun1, fun2). + + +warning(X, Y, no):- call(X, Y), tag(Y, bug(Z)), not tag(X, bug(Z)), no=Z. +%:- call(X, Y), tag(Y, bug(Z)), not tag(X, bug(Z)). + + +%#show warning/3. \ No newline at end of file diff --git a/scripts/cases/bugs-code.xreate b/scripts/cases/bugs-code.xreate new file mode 100644 index 0000000..ebd32b6 --- /dev/null +++ b/scripts/cases/bugs-code.xreate @@ -0,0 +1,33 @@ + +//unsafe code propagation rule +rule: (X: function, Y: function) +case X call Y, -X tag suppress(unsafe_propagation_warning) + { + warning Y tag unsafe -> X tag unsafe + message "safe function should not call unsafe code" + } + +//bugs propagation rule +rule: (X: function, Y: function) +case X call Y, - X tag suppress(bugs_propagation_warnings) + { + warning Y tag bug(no(No)) -> X tag bug(no(No)) + message "Function should declare bugs it aware of" + } + +testfunc3 = function: (a: num, b: num)->num , unsafe, bug(no(1273)) //function tags list +{ + x = a+b: num; + y = a - b: num; + + (x + y) / 2; +} + +testfunc2 = function: (a: num)->bool // because of testfunc3 marked as unsafe code, + // testfunc2 should be marked so too +,suppress(bugs_propagation_warnings), suppress(unsafe_propagation_warning) + +{ + b = testfunc3(a+1, a-1): num; + (b==0); +} \ No newline at end of file diff --git a/scripts/input.xreate b/scripts/input.xreate index 20c792c..971d3f0 100644 --- a/scripts/input.xreate +++ b/scripts/input.xreate @@ -1,42 +1,65 @@ //unsafe code propagation rule rule: (X: function, Y: function) case X call Y { warning Y tag unsafe -> X tag unsafe message "safe function should not call unsafe code" } -testfunc3 = function: (a: num, b: num)->num , unsafe //function tags list +//unsafe code propagation rule +rule: (X: function, Y: function) +case X call Y + { + warning Y tag bug(no(No)) -> X tag bug(no(No)) + message "Function should declare bugs it aware of" + } + +testfunc3 = function: (a: num, b: num)->num , unsafe, bug(no(1273)) //function tags list { x = a+b: num; y = a - b: num; (x + y) / 2; } -testfunc2 = function: (a: num)->bool, unsafe // because of testfunc3 marked as unsafe code, +testfunc2 = function: (a: num)->bool // because of testfunc3 marked as unsafe code, // testfunc2 should be marked so too { b = testfunc3(a+1, a-1): num; (b==0); } -/*cl +testfunc4 = function: ()->bool +{ + a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] : [num]; + b = [1, 3, 2]: [num]; + + (a[1]==b[2]); +} + +/* find6 = function: bool { x = [1, 2, 3, 4, 5, 6, 7]: [num]; //эффективная инициализация y = map (x) [el]-> {2 * el}; - + + + y = loop map (x->el: num ): [num] + { + 2 * el; + } + + exists(y, 12); } exists = function: (list:[a], el: a)->bool { acc: bool; acc = reduce(list, false) [el, acc] -> { acc = acc & (el == e): saturated(true); } } */