No OneTemporary

File Metadata

Created
Sat, Mar 14, 4:35 AM
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 <wchar.h>
#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<Type_t>(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<Identifier_t>(varIn))}); e.addBindings({Atom<Identifier_t>(varEl)});
+ block.addArg(Atom<Identifier_t>(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<Identifier_t>(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<Identifier_t>(infix))});
+ e.addArg(Expression(Atom<Identifier_t>(i1)));
+ e.addArg(std::move(e2));
+
+ } else if (la->kind == _ident) {
+ Ident(i1);
+ e = Expression(Atom<Identifier_t>(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<String_t>(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<Identifier_t>(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<Identifier_t>(infix))});
- e.addArg(Expression(Atom<Identifier_t>(i1)));
- e.addArg(Expression(Atom<Identifier_t>(i2)));
-
- } else if (la->kind == _ident) {
- Ident(i1);
- e = Expression(Atom<Identifier_t>(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<Identifier_t>(name)});
Expect(_lparen);
- if (StartOf(3)) {
+ if (StartOf(4)) {
CalleeParams(e);
}
Expect(_rparen);
+ } else if (checkIndex()) {
+ Ident(name);
+ e = Expression(Operator::INDEX, {Atom<Identifier_t>(name)});
+ Expect(_lbrack);
+ CalleeParams(e);
+ Expect(_rbrack);
} else if (la->kind == _ident) {
Ident(name);
e = Expression(Atom<Identifier_t>(name));
} else if (la->kind == _number) {
Get();
e = Expression(Atom<Number_t>(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<typename T>
struct ParserInitExistsRecognizer {
template<typename U, void (U::*)() = &U::Init>
struct ExistsIfInitIsDefinedMarker{};
struct InitIsMissingType {
char dummy1;
};
struct InitExistsType {
char dummy1; char dummy2;
};
// exists always
template<typename U>
static InitIsMissingType is_here(...);
// exist only if ExistsIfInitIsDefinedMarker is defined
template<typename U>
static InitExistsType is_here(ExistsIfInitIsDefinedMarker<U>*);
enum { InitExists = (sizeof(is_here<T>(NULL)) == sizeof(InitExistsType)) };
};
template<typename T>
struct ParserDestroyExistsRecognizer {
template<typename U, void (U::*)() = &U::Destroy>
struct ExistsIfDestroyIsDefinedMarker{};
struct DestroyIsMissingType {
char dummy1;
};
struct DestroyExistsType {
char dummy1; char dummy2;
};
// exists always
template<typename U>
static DestroyIsMissingType is_here(...);
// exist only if ExistsIfDestroyIsDefinedMarker is defined
template<typename U>
static DestroyExistsType is_here(ExistsIfDestroyIsDefinedMarker<U>*);
enum { DestroyExists = (sizeof(is_here<T>(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<typename T, bool = ParserInitExistsRecognizer<T>::InitExists>
struct ParserInitCaller {
static void CallInit(T *t) {
// nothing to do
}
};
// True case of the ParserInitCaller, gets used if the Init method exists
template<typename T>
struct ParserInitCaller<T, true> {
static void CallInit(T *t) {
t->Init();
}
};
// Generic case of the ParserDestroyCaller, gets used if the Destroy method is missing
template<typename T, bool = ParserDestroyExistsRecognizer<T>::DestroyExists>
struct ParserDestroyCaller {
static void CallDestroy(T *t) {
// nothing to do
}
};
// True case of the ParserDestroyCaller, gets used if the Destroy method exists
template<typename T>
struct ParserDestroyCaller<T, true> {
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<Parser>::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<Parser>::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 <string>
+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 <memory.h>
#include <string.h>
#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 <string>
+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<std::wstring& name>
= ident (. name = t->val; .).
-FDecl<> = (. std::wstring fname; Expression fbody; std::wstring varname; TypeAnnotation typIn; TypeAnnotation typOut; .)
-Ident<fname> '=' "function" ':' (. Function f = Function(fname); .)
+FDecl<> = (. std::wstring fname; std::wstring varname; TypeAnnotation typIn; TypeAnnotation typOut; .)
+Ident<fname> assign "function" ':' (. Function f = Function(fname); .)
( Type<typOut> (. f.setReturnType(typOut); .)
-| '('Ident<varname> ':' Type<typIn> (. f.addArg(varname, typIn); .)
-{',' Ident<varname> ':' Type<typIn> (. f.addArg(varname, typIn);.)
-} ')' '-' '>' Type<typOut> (. f.setReturnType(typOut); .)
+| '(' [Ident<varname> ':' Type<typIn> (. f.addArg(std::move(varname), move(typIn)); .)
+{',' Ident<varname> ':' Type<typIn> (. f.addArg(std::move(varname), move(typIn));.)
+}] ')' implic Type<typOut> (. f.setReturnType(typOut); .)
{',' FnTag<f> }
-) '{' {VDecl<f> ';' }
-Expr<fbody> ';' '}' (. f.setBody(fbody); root.add(f); .) .
+) BDecl<f.getEntryScope()> (. root.add(f); .)
+.
TypeTerm<TypeAtom& typ> = ("string" | "int" | "num" | "float" | "bool") (. typ = Atom<Type_t>(t->val); .) .
Type<TypeAnnotation& typ> = (. TypeAnnotation typ2; TypeAtom typ3; .)
-('[' Type<typ2> ']' (. typ = TypeAnnotation(TypeOperator::LIST, typ2); .)
+('[' Type<typ2> ']' (. typ = TypeAnnotation(TypeOperator::LIST, {typ2}); .)
| TypeTerm<typ3> (. typ = TypeAnnotation(typ3); .)
) .
-VDecl<Function& f> = (. std::wstring vname; Expression e; TypeAnnotation typ; .)
-Ident<vname> '='
-(Expr<e> ':' Type<typ> (. f.addDeclaration(vname, typ, e); .)
-|ListLiteral<e> ':' Type<typ> (. f.addListDeclaration(vname, typ, e); .)
-).
+VDecl<CodeScope& f> = (. std::wstring vname; Expression e; TypeAnnotation typ; .)
+Ident<vname> assign
+(ListLiteral<e> ':' Type<typ>
+| LoopDecl<e, typ> ';'
+| Expr<e> ':' Type<typ>
+) (. f.addDeclaration(move(vname), move(typ), move(e)); .).
+
+BDecl<CodeScope& scope> = (. Expression body; .)
+'{' { (
+ IF(checkAssignment()) VDecl<scope> ';'
+ | TagsDecl<scope> ';'
+ | Expr<body> ';' (. scope.setBody(body); .)
+)}
+'}'.
+
+LoopDecl<Expression& e, TypeAnnotation& typOut> = (. std::wstring varIn, varEl; TypeAnnotation typEl; CodeScope block; .)
+
+ "loop" "map" '(' Ident<varIn> implic Ident<varEl> ':' Type<typEl> ')' ':' Type<typOut> BDecl<block>
+ (. e = Expression(Operator::LOOP, {Expression(Atom<Identifier_t>(varIn))}); e.addBindings({Atom<Identifier_t>(varEl)});
+ block.addArg(Atom<Identifier_t>(varEl), move(typEl)); e.addBlock(move(block)); .)
+.
+
/*============================ METAPROGRAMMING ===============================*/
-
-FnTag<Function& f> = (.std::wstring tag; TagModifier mod = TagModifier::NONE; .)
-Ident<tag>
-['-' TagMod<mod>] (. f.addTag(tag, mod); .).
+
+TagsDecl<CodeScope& f> = (. Expression tag; TagModifier mod = TagModifier::NONE; .)
+':' { MetaSimpExpr<tag> ['-' TagMod<mod>] (. /*f.addTag(std::move(tag), mod); */ .)
+}.
+
+FnTag<Function& f> = (. Expression tag; TagModifier mod = TagModifier::NONE; .)
+MetaSimpExpr<tag>
+['-' TagMod<mod>] (. f.addTag(std::move(tag), mod); .).
TagMod<TagModifier& mod> =
( "assert" (. mod = TagModifier::ASSERT; .)
| "require" (. mod = TagModifier::REQUIRE; .)
).
RuleDecl<> =
"rule" ':' (. RuleArguments args; RuleGuards guards; DomainAnnotation typ; std::wstring arg; .)
'(' Ident<arg> ':' Domain<typ> (. args.add(arg, typ); .)
{',' Ident<arg> ':'Domain<typ> (. args.add(arg, typ); .)
} ')'
["case" RGuard<guards> {',' RGuard<guards>}]
- (. .)
-'{' RBody<args, guards> '}' .
+'{' RBody<args, guards> '}' .
Domain<DomainAnnotation& dom> =
(
"function" (. dom = DomainAnnotation::FUNCTION; .)
| "variable" (. dom = DomainAnnotation::VARIABLE; .)
).
RGuard<RuleGuards& guards>= (. Expression e; .)
MetaExpr<e> (. guards.add(std::move(e)); .).
MetaExpr<Expression& e>= (.Operator op; Expression e2; .)
MetaExpr2<e>
[MetaOp<op> MetaExpr2<e2> (. e = Expression(op, {e, e2}); .)
].
-MetaExpr2<Expression& e>= (. std::wstring i1, i2, infix; .)
-( IF(checkParametersList()) Ident<i1> (. e = Expression(Operator::CALL, {Expression(Atom<Identifier_t>(i1))}); .)
+MetaExpr2<Expression& e>=
+(
+'(' MetaExpr<e> ')'
+| MetaSimpExpr<e>
+).
+
+MetaSimpExpr<Expression& e>= (. std::wstring i1, infix; Expression e2; .)
+( '-' MetaSimpExpr<e2> (. e = Expression(Operator::NEG, {e2}); .)
+| IF(checkParametersList()) Ident<i1> (. e = Expression(Operator::CALL, {Expression(Atom<Identifier_t>(i1))}); .)
'(' [ CalleeParams<e> ] ')'
-| IF(checkInfix()) Ident<i1> Ident<infix> Ident<i2>
+| IF(checkInfix()) Ident<i1> Ident<infix> MetaSimpExpr<e2>
(. e = Expression(Operator::CALL, {Expression(Atom<Identifier_t>(infix))});
e.addArg(Expression(Atom<Identifier_t>(i1)));
- e.addArg(Expression(Atom<Identifier_t>(i2)));
+ e.addArg(std::move(e2));
.)
| Ident<i1> (. e = Expression(Atom<Identifier_t>(i1)); .)
-| '(' MetaExpr<e> ')'
).
RBody<const RuleArguments& args, const RuleGuards& guards> =
(. Expression e; std::wstring msg; .)
"warning" MetaExpr<e> ["message" string (. msg = t->val; .)
] (. root.add(new RuleWarning(RuleArguments(args), RuleGuards(guards), std::move(e), Atom<String_t>(msg))); .)
.
MetaOp< Operator& op> =
- '-' '>' (. op = Operator::IMPL; .)
+ implic (. op = Operator::IMPL; .)
.
/*============================ Expressions ===============================*/
// dublicates CalleeParams
ListLiteral<Expression& e> = (. Expression e2; .)
'[' (. e.setOp(Operator::LIST); .)
[ Expr<e2> (. e.addArg(std::move(e2)); .)
{',' Expr<e2> (. 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<Identifier_t>(name)}); .)
'(' [CalleeParams<e>] ')'
+ |IF (checkIndex()) Ident<name> (. e = Expression(). e.setOp(Operator::INDEX); e.addArg(Atom<Identifier_t>(name)}); .)
+ lbrack CalleeParams<e> rbrack
| Ident< name> (. e = Expression(Atom<Identifier_t>(name)); .)
| number (. e = Expression(Atom<Number_t>(t->val)); .)
| '-' Factor< e> (. e = Expression(Operator::NEG, {e}); .)
| '(' Expr<e> ')'
).
CalleeParams<Expression& e> = (. Expression e2; .)
Expr<e2> (. e.addArg(std::move(e2)); .)
{',' Expr<e2> (. 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 <ast.h>
+#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<llvm::Value *> 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<llvm::Value*> 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<Operator::LIST>(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<llvm::Value*> 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<llvm::Value*>(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<llvm::Type*> 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<llvm::Function>(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<llvm::Type *> 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<llvm::Function>(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 <stdexcept>
#include <iostream>
#include <QString>
#include <clasplayer.h>
using namespace std;
+namespace xreate{
+
TypeAnnotation::TypeAnnotation()
-{}
+{
+}
TypeAnnotation::TypeAnnotation(const Atom<Type_t> &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<TypeAnnotation> 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<TypeAnnotation>)
+{}
+*/
+
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_t>& number)
: __state(NUMBER), __op(Operator::NONE), __valueD(number.get())
{
}
Expression::Expression(const Atom<Identifier_t> &ident)
: __state(IDENT), __op(Operator::NONE), __valueS(ident.get())
{
}
Expression::Expression(const Operator &op, std::initializer_list<Expression> 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<Atom<Identifier_t>> params)
+{
+ bindings.insert(bindings.end(), params);
+}
+
+void
+Expression::addBlock(CodeScope&& scope)
+{
+ blocks.push_back(scope);
+}
+
+const std::vector<Expression>&
+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<MetaRuleAbstract>(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<Identifier_t>& name)
- :__vCounter(0)
{
__name = name.get();
-
}
void
-Function::addTag(const Atom<Identifier_t>& 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()<<endl;
- __tags.emplace_back(aname.get(), amod);
+ __tags.emplace_back(tag, mod);
}
-const std::vector<std::pair<std::string, TagModifier>>&
+const std::vector<Tag>&
Function::getAnnotations() const
{
return __tags;
}
+const CodeScope&
+Function::getEntryScope() const
+{
+ return __entry;
+}
+
+CodeScope&
+Function::getEntryScope()
+{
+ return __entry;
+}
+
void
-Function::addArg(const Atom<Identifier_t> &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 <Identifier_t>&& name, TypeAnnotation&& typ)
{
- __body = body;
+ VID id = registerVar(std::move(const_cast<std::string&>(name.get())), std::move(typ));
+ __args.push_back(name.get());
+}
+
+ ;
+
+void
+Function::addArg(Atom <Identifier_t>&& 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<Identifier_t> &vname, const TypeAnnotation &typ, const Expression &e)
-{}
+CodeScope::addDeclaration(const Atom <Identifier_t> &&name, TypeAnnotation &&typ, Expression&& body)
+{
+ VID id = registerVar(std::move(const_cast<string&>(name.get())), move(typ));
+ __declarations[id] = body;
+}
void
-Function::addDeclaration(const Atom<Identifier_t> &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<Identifier_t> &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<String_t>&& 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 <vector>
#include <stdlib.h>
#include <string>
#include "llvmlayer.h"
#include <list>
+#include <unordered_map>
+#include <unordered_set>
+
+namespace xreate {
struct String_t{};
struct Identifier_t {};
struct Number_t {};
struct Type_t {};
template<typename A>
-class Atom{};
+class Atom {};
template<> class Atom<Identifier_t>
{
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<Number_t>
{
public:
Atom(wchar_t* value)
{
__value = wcstol(value, 0, 10);
}
double get()const {return __value; }
private:
double __value;
};
template<> class Atom<String_t>
{
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<Type_t>
{
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<Type_t> 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<Type_t>& 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<TypeAnnotation> operands);
+ // TypeAnnotation (struct_tag, std::initializer_list<TypePrimitive>);
llvm::Type* toLLVMType();
private:
- TimePrimitive __value;
+ TypePrimitive __value;
+ TypeOperator __operator = TypeOperator::NONE;
+ std::vector<TypeAnnotation> __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<Expression> params);
Expression(const Atom<Identifier_t>& ident);
Expression(const Atom<Number_t>& number);
Expression();
void setOp(Operator op);
void addArg(Expression&& arg);
-protected:
- Operator __op;
+ void addBindings(std::initializer_list<Atom<Identifier_t>> params);
+ void addBlock(CodeScope&& scope);
+
+ const std::vector<Expression>& getOperands() const;
+ double getValueDouble() const;
+ const std::string& getValueString() const;
+
+private:
+ Operator __op ;
std::vector<Expression> operands;
+ std::vector<Atom<Identifier_t>> bindings;
+ std::vector<CodeScope> blocks;
std::string __valueS;
double __valueD;
enum {INVALID, COMPOUND, IDENT, NUMBER, STRING} __state;
};
typedef std::list<Expression> ExpressionList;
enum class TagModifier
{NONE, ASSERT, REQUIRE};
enum class DomainAnnotation
{FUNCTION, VARIABLE};
class RuleArguments: public std::vector<std::pair<std::string, DomainAnnotation>>
{
public:
void add(const Atom<Identifier_t>& name, DomainAnnotation typ);
};
class RuleGuards: public std::vector<Expression>
{
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<String_t>&& 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<VID, TypeAnnotation> VariableDefinition;
typedef std::pair<VID, Expression> VariableDeclaration;
-class Function
+
+typedef std::pair<Expression, TagModifier> Tag;
+
+class CodeScope
{
- friend class Expression;
+ friend class Function;
friend class CFGPass;
+
public:
- Function(const Atom<Identifier_t>& name);
- void setReturnType(const TypeAnnotation& rtyp);
- void addArg(const Atom<Identifier_t>& vname, const TypeAnnotation& typ);
+ CodeScope();
void setBody(const Expression& body);
+ void addDeclaration(const Atom <Identifier_t> &&name, TypeAnnotation &&typ, Expression&& body);
- void addTag(const Atom<Identifier_t>& aname, const TagModifier amod);
- const std::vector<std::pair<std::string, TagModifier>>& getAnnotations() const;
+ void addArg(Atom <Identifier_t>&& 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<Identifier_t> & vname, const TypeAnnotation& typ, const Expression& e);
- void addListDeclaration(const Atom<Identifier_t> & vname, const TypeAnnotation& typ, const Expression& e);
+private:
+ std::unordered_map<VariableDefinition::first_type, VariableDefinition::second_type> __definitions;
+ std::unordered_map<VariableDeclaration::first_type, VariableDeclaration::second_type> __declarations;
+ std::map<std::string, VID> __vartable;
+ std::vector<std::string> __args;
+
+ Expression __body;
+ VID __vCounter=0;
+
+ std::map<VID,llvm::Value*> __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<Identifier_t>& name);
+
+ void addArg(Atom <Identifier_t>&& 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<Tag>& getAnnotations() const;
+ const CodeScope& getEntryScope() const;
+ CodeScope& getEntryScope();
+ void setEntryScope(CodeScope&& scope);
private:
+ CodeScope __entry;
std::string __name;
TypeAnnotation __retType;
- std::vector<std::string> __args;
- std::vector<std::pair<std::string, TagModifier>> __tags;
- std::map<VariableDefinition::first_type, VariableDefinition::second_type> __definitions;
- std::map<VariableDeclaration::first_type, VariableDeclaration::second_type> __declarations;
- std::map<std::string, VID> __vartable;
- Expression __body;
+ std::vector<Tag> __tags;
llvm::Function* __raw;
- std::map<VID,llvm::Value*> __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<std::unique_ptr<MetaRuleAbstract>> __rules;
std::vector<Function> __functions;
std::map<std::string, FID> __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 <clasp/program_builder.h> // for defining logic programs
#include <clasp/unfounded_check.h> // unfounded set checkers
#include <clasp/model_enumerators.h> // for enumerating answer sets
#include <clasp/clasp_facade.h>
#include <clingocontrol.hh>
#include <iostream>
#include <clingo_lib.hh>
using namespace std;
-bool
-ClaspLayer::onModel(Gringo::Model const & model)
-{
- std::list<std::string> 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<std::string> 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<QStringList>&& 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<end; ++expr1I)
- {
- if (list.size() == 0 ) continue;
-
- QStringList::const_iterator expr2I=list.begin();
- for(int expr2No=0, size = list.size()-1; expr2No < size; ++expr2No, ++expr1I)
- result.append(QString("%1, %2").arg(*expr1I).arg(*expr2I));
-
- *expr1I = QString("%1, %2").arg(*expr1I).arg(*expr2I);
+ for (auto warning: warnings) {
+ cout << "Warning: " << warning << endl;
}
}
- return result;
-}
+ QStringList multiplyLists(std::list<QStringList> &&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 <<endl<< "%\t\tStatic analysis: CFG" << endl;
+ QStringList::const_iterator expr2I = list.begin();
+ for (int expr2No = 0, size = list.size() - 1; expr2No < size; ++expr2No, ++expr1I)
+ result.append(QString("%1, %2").arg(*expr1I).arg(*expr2I));
- for (const std::pair<FID, FID>& 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()<<endl;
- }
-}
-
-void
-ClaspLayer::addFunctionTags(const std::string& function, const std::vector<Tag>& tags)
-{
- ostream& cout = __partTags;
-
- cout << (QString("function(%1) .").arg(function.c_str())).toStdString()<<std::endl;
+ *expr1I = QString("%1, %2").arg(*expr1I).arg(*expr2I);
+ }
+ }
- int tagsCount=0;
- for(Tag tag: tags)
- {
- cout << QString("tag(%1, %2).").arg(function.c_str()).arg(tag.first.c_str()).toStdString() << endl;
- ++tagsCount;
+ return result;
}
- if (tagsCount == 0)
- {
- cout << "%no tags at all" << endl;
- }
-}
-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<std::string, DomainAnnotation>& 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<std::string, DomainAnnotation>& argument) {
- return argument.first.c_str();
- });
+ for (const std::pair<FID, FID> &relation: graph.__relations) {
+ const string &tagFrom = graph.__nodes.at(relation.first);
+ const string &tagTo = graph.__nodes.at(relation.second);
- std::list<QStringList> 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<Tag> &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<QStringList> 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<std::string, DomainAnnotation> &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<std::string, DomainAnnotation> &argument) {
+ return argument.first.c_str();
+ });
+
+ std::list<QStringList> 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<QStringList> 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 <string>
#include <gringo/control.hh>
#include <ast.h>
#include <QStringList>
-typedef std::pair<std::string, TagModifier> 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<Tag>& tags);
- void addCFGData(CFGraph&& graph);
- void addRuleWarning(const RuleWarning& rule);
+ ClaspLayer();
+ void addFunctionTags(const std::string &function, const std::vector<Tag> &tags);
+ void addCFGData(CFGraph &&graph);
+ void addRuleWarning(const RuleWarning &rule);
- void run();
+ void run();
-private:
- std::map<std::string, std::string> __hooks;
- std::ostringstream __partTags;
- std::ostringstream __partGeneral;
+ private:
+ std::map<std::string, std::string> __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<FID, FID> __relations;
- std::map<FID, std::string> __nodes;
-};
+ void addLink(FID nodeFrom, FID nodeTo);
+ bool existsNode(FID function) const;
+
+ void print(std::ostream &cout) const;
+
+ private:
+ std::map<FID, FID> __relations;
+ std::map<FID, std::string> __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<Value *>(std::vector<Value*>{ConstantInt::get(i32Tag, 0), itLoop}));
+ Value *pElOut = builder.CreateGEP(vecOut, ArrayRef<Value *>(std::vector<Value*>{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<Constant *> list;
+ list.reserve(__size);
+
+ const std::vector<Expression> 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<Constant*>(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 <llvm/IR/Value.h>
+
+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<Operator Instruction>
+ struct InstructionClasses {};
+
+ template<>
+ struct InstructionClasses<Operator::LIST> {
+ typedef InstructionList base;
+ };
+
+ template<>
+ struct InstructionClasses<Operator::LOOP> {
+ typedef InstructionMap base;
+ };
+
+ template<Operator Instruction>
+ class CodeInstruction: public InstructionClasses<Instruction>::base
+ {
+ typedef typename InstructionClasses<Instruction>::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<void*> __garbage;
-};
+ llvm::Value *compile() const;
+ private:
+ std::vector<void *> __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 <QString>
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(); f<fcount; ++f)
+ for(FID f=0, fcount= clasp->ast->getFunctionsCount(); f<fcount; ++f)
{
- const Function& func = __root.getFunctionById(f);
+ const Function& func = clasp->ast->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 <set>
#include <iostream>
#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 <QString>
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 <iostream>
#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 <ast.h>
#include <clasplayer.h>
+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 <memory>
#include <iostream>
#include "pass/cfgpass.h"
#include "pass/functiontagspass.h"
#include "pass/rulespass.h"
#include "clasplayer.h"
#include <sstream>
using namespace std;
void testParser_1()
{
shared_ptr<Scanner> scanner(new Scanner(L"scripts/input.xreate"));
shared_ptr<Parser> 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> scanner(new Scanner(L"scripts/input.xreate"));
shared_ptr<Parser> 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> scanner(new Scanner(L"scripts/cases/unsafe-code.xreate"));
+ shared_ptr<Scanner> scanner(new Scanner(L"scripts/cases/bugs-code.xreate"));
shared_ptr<Parser> 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);
}
}
*/

Event Timeline