No OneTemporary

File Metadata

Created
Sat, Mar 14, 4:31 AM
diff --git a/coco/Parser.cpp b/coco/Parser.cpp
index fe5a29f..61fc797 100644
--- a/coco/Parser.cpp
+++ b/coco/Parser.cpp
@@ -1,664 +1,654 @@
/*----------------------------------------------------------------------
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" */) {
if (la->kind == _ident) {
FDecl();
} else {
RuleDecl();
}
}
}
void Parser::FDecl() {
std::wstring fname; Expression fbody; std::wstring varname; TypeAnnotation typIn; TypeAnnotation typOut;
Ident(fname);
Expect(6 /* "=" */);
Expect(7 /* "function" */);
Expect(8 /* ":" */);
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();
Ident(varname);
Expect(8 /* ":" */);
Type(typIn);
f.addArg(varname, typIn);
}
Expect(_rparen);
- Expect(10 /* "->" */);
+ Expect(10 /* "-" */);
+ Expect(11 /* ">" */);
Type(typOut);
f.setReturnType(typOut);
while (la->kind == 9 /* "," */) {
Get();
FnTag(f);
}
- } else SynErr(35);
- Expect(11 /* "{" */);
+ } else SynErr(34);
+ Expect(12 /* "{" */);
while (la->kind == _ident) {
VDecl(f);
- Expect(12 /* ";" */);
+ Expect(13 /* ";" */);
}
Expr(fbody);
- Expect(12 /* ";" */);
- Expect(13 /* "}" */);
+ Expect(13 /* ";" */);
+ Expect(14 /* "}" */);
f.setBody(fbody); root.add(f);
}
void Parser::RuleDecl() {
Expect(24 /* "rule" */);
Expect(8 /* ":" */);
- RuleArguments args; RuleGuards guards; RuleBody body; DomainAnnotation typ;
+ RuleArguments args; RuleGuards guards; DomainAnnotation typ; std::wstring arg;
Expect(_lparen);
Ident(arg);
Expect(8 /* ":" */);
Domain(typ);
args.add(arg, typ);
while (la->kind == 9 /* "," */) {
Get();
Ident(arg);
Expect(8 /* ":" */);
Domain(typ);
args.add(arg, typ);
}
Expect(_rparen);
if (la->kind == 25 /* "case" */) {
Get();
RGuard(guards);
while (la->kind == 9 /* "," */) {
Get();
RGuard(guards);
}
}
- Expect(11 /* "{" */);
+ Expect(12 /* "{" */);
RBody(args, guards);
- Expect(13 /* "}" */);
+ Expect(14 /* "}" */);
}
void Parser::Ident(std::wstring& name) {
Expect(_ident);
name = t->val;
}
void Parser::Type(TypeAnnotation& typ) {
TypeAnnotation typ2; TypeAtom typ3;
- if (la->kind == 19 /* "[" */) {
+ if (la->kind == 20 /* "[" */) {
Get();
Type(typ2);
- Expect(20 /* "]" */);
+ Expect(21 /* "]" */);
typ = TypeAnnotation(TypeOperator::LIST, typ2);
} else if (StartOf(2)) {
TypeTerm(typ3);
typ = TypeAnnotation(typ3);
- } else SynErr(36);
+ } else SynErr(35);
}
void Parser::FnTag(Function& f) {
std::wstring tag; TagModifier mod = TagModifier::NONE;
Ident(tag);
- if (la->kind == 21 /* "-" */) {
+ if (la->kind == 10 /* "-" */) {
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 == 19 /* "[" */) {
+ } else if (la->kind == 20 /* "[" */) {
ListLiteral(e);
Expect(8 /* ":" */);
Type(typ);
f.addListDeclaration(vname, typ, e);
- } else SynErr(37);
+ } else SynErr(36);
}
void Parser::Expr(Expression& e) {
Operator op; Expression e2;
SimExpr(e);
- if (la->kind == 6 /* "=" */ || la->kind == 29 /* ">" */ || la->kind == 33 /* "<" */) {
+ if (la->kind == 6 /* "=" */ || la->kind == 11 /* ">" */ || la->kind == 32 /* "<" */) {
RelOp(op);
SimExpr(e2);
- e = Expression(op, e); e.addArg(e2);
+ e = Expression(op, {e, e2});
}
}
void Parser::TypeTerm(TypeAtom& typ) {
- if (la->kind == 14 /* "string" */) {
+ if (la->kind == 15 /* "string" */) {
Get();
- } else if (la->kind == 15 /* "int" */) {
+ } else if (la->kind == 16 /* "int" */) {
Get();
- } else if (la->kind == 16 /* "num" */) {
+ } else if (la->kind == 17 /* "num" */) {
Get();
- } else if (la->kind == 17 /* "float" */) {
+ } else if (la->kind == 18 /* "float" */) {
Get();
- } else if (la->kind == 18 /* "bool" */) {
+ } else if (la->kind == 19 /* "bool" */) {
Get();
- } else SynErr(38);
+ } else SynErr(37);
typ = Atom<Type_t>(t->val);
}
void Parser::ListLiteral(Expression& e) {
Expression e2;
- Expect(19 /* "[" */);
- e = Expression(Operator::LIST, Expression());
+ Expect(20 /* "[" */);
+ e.setOp(Operator::LIST);
if (StartOf(3)) {
Expr(e2);
- e.addArg(e2);
+ e.addArg(std::move(e2));
while (la->kind == 9 /* "," */) {
Get();
Expr(e2);
- e.addArg(e2);
+ e.addArg(std::move(e2));
}
}
- Expect(20 /* "]" */);
+ Expect(21 /* "]" */);
}
void Parser::TagMod(TagModifier& mod) {
if (la->kind == 22 /* "assert" */) {
Get();
mod = TagModifier::ASSERT;
} else if (la->kind == 23 /* "require" */) {
Get();
mod = TagModifier::REQUIRE;
- } else SynErr(39);
+ } else SynErr(38);
}
void Parser::Domain(DomainAnnotation& dom) {
if (la->kind == 7 /* "function" */) {
Get();
dom = DomainAnnotation::FUNCTION;
} else if (la->kind == 26 /* "variable" */) {
Get();
dom = DomainAnnotation::VARIABLE;
- } else SynErr(40);
+ } else SynErr(39);
}
void Parser::RGuard(RuleGuards& guards) {
- MetaExpression e;
+ Expression e;
MetaExpr(e);
- guards.add(e);
+ guards.add(std::move(e));
}
-void Parser::RBody(RuleBody& body) {
- MetaExpr e;
+void Parser::RBody(const RuleArguments& args, const RuleGuards& guards) {
+ Expression e; std::wstring msg;
Expect(27 /* "warning" */);
MetaExpr(e);
if (la->kind == 28 /* "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(MetaExpression& e) {
+void Parser::MetaExpr(Expression& e) {
+ Operator op; Expression e2;
MetaExpr2(e);
- if (la->kind == 21 /* "-" */) {
+ if (la->kind == 10 /* "-" */) {
MetaOp(op);
MetaExpr2(e2);
- MetaParameters params;
- params.add(e);
- params.add(e2);
- e = MetaExpression(op, params);
+ e = Expression(op, {e, e2});
}
}
-void Parser::MetaExpr2(MetaExpression& e) {
- std::wstring i1, i2, infix; MetaParameters params;
+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 (la->kind == _ident || la->kind == _lparen) {
- MetaParams(params);
+ if (StartOf(3)) {
+ CalleeParams(e);
}
Expect(_rparen);
- e = MetaExpression(Operator::CALL, i1, params);
} else if (checkInfix()) {
Ident(i1);
Ident(infix);
Ident(i2);
- params.add(Expression(Atom<Identifier_t>(i1->val)));
- params.add(Expression(Atom<Identifier_t>(i2->val)));
- e = MetaExpression(Operator::CALL, Atom<Identifier_t>(infix->val), params);
+ 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 = MetaExpression(Atom<Identifier_t>(i1->val));
+ e = Expression(Atom<Identifier_t>(i1));
} else if (la->kind == _lparen) {
Get();
MetaExpr(e);
Expect(_rparen);
- } else SynErr(41);
+ } else SynErr(40);
}
void Parser::MetaOp(Operator& op) {
- Expect(21 /* "-" */);
- Expect(29 /* ">" */);
- op = OPERATOR::IMPL;
+ Expect(10 /* "-" */);
+ Expect(11 /* ">" */);
+ op = Operator::IMPL;
}
-void Parser::MetaParams(MetaParameters& params) {
- MetaExpr e;
- MetaExpr(e);
- params.add(e);
+void Parser::CalleeParams(Expression& e) {
+ Expression e2;
+ Expr(e2);
+ e.addArg(std::move(e2));
while (la->kind == 9 /* "," */) {
Get();
- MetaExpr(e);
- params.add(e)
+ Expr(e2);
+ e.addArg(std::move(e2));
}
}
void Parser::SimExpr(Expression& e) {
Operator op; Expression e2;
Term(e);
- while (la->kind == 21 /* "-" */ || la->kind == 30 /* "+" */) {
+ while (la->kind == 10 /* "-" */ || la->kind == 29 /* "+" */) {
AddOp(op);
Term(e2);
- e = Expression(op, e); e.addArg(e2);
+ e = Expression(op, {e, e2});
}
}
void Parser::RelOp(Operator& op) {
op = Operator::EQU;
if (la->kind == 6 /* "=" */) {
Get();
Expect(6 /* "=" */);
- } else if (la->kind == 33 /* "<" */) {
+ } else if (la->kind == 32 /* "<" */) {
Get();
op = Operator::LSS;
- } else if (la->kind == 29 /* ">" */) {
+ } else if (la->kind == 11 /* ">" */) {
Get();
op = Operator::GTR;
- } else SynErr(42);
+ } else SynErr(41);
}
void Parser::Term(Expression& e) {
Operator op; Expression e2;
Factor(e);
- while (la->kind == 31 /* "*" */ || la->kind == 32 /* "/" */) {
+ while (la->kind == 30 /* "*" */ || la->kind == 31 /* "/" */) {
MulOp(op);
Factor(e2);
- e = Expression(op, e); e.addArg(e2);
+ e = Expression(op, {e, e2});
}
}
void Parser::AddOp(Operator& op) {
op = Operator::ADD;
- if (la->kind == 30 /* "+" */) {
+ if (la->kind == 29 /* "+" */) {
Get();
- } else if (la->kind == 21 /* "-" */) {
+ } else if (la->kind == 10 /* "-" */) {
Get();
op = Operator::SUB;
- } else SynErr(43);
+ } else SynErr(42);
}
void Parser::Factor(Expression& e) {
std::wstring name;
if (checkParametersList()) {
Ident(name);
- e = Expression(Operator::CALL, Atom<Identifier_t>(name));
+ e = Expression(Operator::CALL, {Atom<Identifier_t>(name)});
Expect(_lparen);
if (StartOf(3)) {
CalleeParams(e);
}
Expect(_rparen);
} 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 == 21 /* "-" */) {
+ } else if (la->kind == 10 /* "-" */) {
Get();
Factor(e);
- e = Expression(Operator::NEG, e);
+ e = Expression(Operator::NEG, {e});
} else if (la->kind == _lparen) {
Get();
Expr(e);
Expect(_rparen);
- } else SynErr(44);
+ } else SynErr(43);
}
void Parser::MulOp(Operator& op) {
op = Operator::MUL;
- if (la->kind == 31 /* "*" */) {
+ if (la->kind == 30 /* "*" */) {
Get();
- } else if (la->kind == 32 /* "/" */) {
+ } else if (la->kind == 31 /* "/" */) {
Get();
op = Operator::DIV;
- } else SynErr(45);
-}
-
-void Parser::CalleeParams(Expression& e) {
- Expression e2;
- Expr(e2);
- e.addArg(e2);
- while (la->kind == 9 /* "," */) {
- Get();
- Expr(e2);
- e.addArg(e2);
- }
+ } else SynErr(44);
}
// 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 = 34;
+ maxT = 33;
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][36] = {
- {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,x,T,T, T,T,T,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,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}
+ 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}
};
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"\"string\" expected"); break;
- case 15: s = coco_string_create(L"\"int\" expected"); break;
- case 16: s = coco_string_create(L"\"num\" expected"); break;
- case 17: s = coco_string_create(L"\"float\" expected"); break;
- case 18: s = coco_string_create(L"\"bool\" 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"\"-\" 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"??? expected"); break;
- case 35: s = coco_string_create(L"invalid FDecl"); break;
- case 36: s = coco_string_create(L"invalid Type"); break;
- case 37: s = coco_string_create(L"invalid VDecl"); break;
- case 38: s = coco_string_create(L"invalid TypeTerm"); break;
- case 39: s = coco_string_create(L"invalid TagMod"); break;
- case 40: s = coco_string_create(L"invalid Domain"); break;
- case 41: s = coco_string_create(L"invalid MetaExpr2"); break;
- case 42: s = coco_string_create(L"invalid RelOp"); break;
- case 43: s = coco_string_create(L"invalid AddOp"); break;
- case 44: s = coco_string_create(L"invalid Factor"); break;
- case 45: s = coco_string_create(L"invalid MulOp"); 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;
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 8501f6d..b986250 100644
--- a/coco/Parser.h
+++ b/coco/Parser.h
@@ -1,141 +1,138 @@
/*----------------------------------------------------------------------
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>
#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
};
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)
bool checkParametersList()
{
- scanner.ResetPeek();
- Token x = scanner->Peek();
+ scanner->ResetPeek();
+ Token* x = scanner->Peek();
return la->kind == _ident && x->kind == _lparen;
}
bool checkInfix()
{
- scanner.ResetPeek();
- Token x = scanner->Peek();
+ scanner->ResetPeek();
+ Token* x = scanner->Peek();
return la->kind == _ident && x->kind == _ident;
}
-bool check
-
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 TypeTerm(TypeAtom& typ);
void ListLiteral(Expression& e);
void TagMod(TagModifier& mod);
void Domain(DomainAnnotation& dom);
void RGuard(RuleGuards& guards);
- void RBody(RuleBody& body);
- void MetaExpr(MetaExpression& e);
- void MetaExpr2(MetaExpression& e);
+ void RBody(const RuleArguments& args, const RuleGuards& guards);
+ void MetaExpr(Expression& e);
+ void MetaExpr2(Expression& e);
void MetaOp(Operator& op);
- void MetaParams(MetaParameters& params);
+ 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 CalleeParams(Expression& e);
void Parse();
}; // end Parser
#endif
diff --git a/coco/Scanner.cpp b/coco/Scanner.cpp
index f19591f..78e2975 100644
--- a/coco/Scanner.cpp
+++ b/coco/Scanner.cpp
@@ -1,764 +1,759 @@
/*----------------------------------------------------------------------
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 = 34;
- noSym = 34;
+ maxT = 33;
+ noSym = 33;
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, 21);
- start.set(123, 11);
- start.set(59, 12);
- start.set(125, 13);
- start.set(91, 14);
- start.set(93, 15);
- start.set(62, 16);
+ start.set(45, 10);
+ start.set(62, 11);
+ start.set(123, 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(Buffer::EoF, -1);
keywords.set(L"function", 7);
- keywords.set(L"string", 14);
- keywords.set(L"int", 15);
- keywords.set(L"num", 16);
- keywords.set(L"float", 17);
- keywords.set(L"bool", 18);
+ 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);
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;}
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'A' && ch <= L'Z') || (ch >= L'a' && ch <= L'z')) {AddCh(); goto 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;}
case 9:
{t->kind = 9; break;}
case 10:
- case_10:
{t->kind = 10; break;}
case 11:
{t->kind = 11; break;}
case 12:
{t->kind = 12; break;}
case 13:
{t->kind = 13; break;}
case 14:
- {t->kind = 19; break;}
+ {t->kind = 14; break;}
case 15:
{t->kind = 20; break;}
case 16:
- {t->kind = 29; break;}
+ {t->kind = 21; break;}
case 17:
- {t->kind = 30; break;}
+ {t->kind = 29; break;}
case 18:
- {t->kind = 31; break;}
+ {t->kind = 30; break;}
case 19:
- {t->kind = 32; break;}
+ {t->kind = 31; break;}
case 20:
- {t->kind = 33; break;}
- case 21:
- recEnd = pos; recKind = 21;
- if (ch == L'>') {AddCh(); goto case_10;}
- else {t->kind = 21; break;}
+ {t->kind = 32; 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 ed7e702..7d4eb54 100644
--- a/coco/xreate.ATG
+++ b/coco/xreate.ATG
@@ -1,198 +1,194 @@
#include "ast.h"
#include <string>
COMPILER Xreate
AST root; // current program unit (procedure or main program)
bool checkParametersList()
{
- scanner.ResetPeek();
- Token x = scanner->Peek();
+ scanner->ResetPeek();
+ Token* x = scanner->Peek();
return la->kind == _ident && x->kind == _lparen;
}
bool checkInfix()
{
- scanner.ResetPeek();
- Token x = scanner->Peek();
+ scanner->ResetPeek();
+ Token* x = scanner->Peek();
return la->kind == _ident && x->kind == _ident;
}
-bool check
-
CHARACTERS
letter = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz".
+ any = ANY - '"'.
digit = "0123456789".
cr = '\r'.
lf = '\n'.
tab = '\t'.
TOKENS
ident = letter {letter | digit}.
number = digit {digit}.
- string = '"' {letter} '"'.
+ string = '"' { any } '"'.
lparen = '('.
rparen = ')'.
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); .)
( 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); .)
+} ')' '-' '>' Type<typOut> (. f.setReturnType(typOut); .)
{',' FnTag<f> }
) '{' {VDecl<f> ';' }
Expr<fbody> ';' '}' (. f.setBody(fbody); 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); .)
| 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); .)
).
/*============================ METAPROGRAMMING ===============================*/
FnTag<Function& f> = (.std::wstring tag; TagModifier mod = TagModifier::NONE; .)
Ident<tag>
['-' TagMod<mod>] (. f.addTag(tag, mod); .).
TagMod<TagModifier& mod> =
( "assert" (. mod = TagModifier::ASSERT; .)
| "require" (. mod = TagModifier::REQUIRE; .)
).
RuleDecl<> =
-"rule" ':' (. RuleArguments args; RuleGuards guards; RuleBody body; DomainAnnotation typ; .)
+"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> '}' .
Domain<DomainAnnotation& dom> =
(
"function" (. dom = DomainAnnotation::FUNCTION; .)
| "variable" (. dom = DomainAnnotation::VARIABLE; .)
).
-RGuard<RuleGuards& guards>= (. MetaExpression e; .)
-MetaExpr<e> (. guards.add(e); .).
+RGuard<RuleGuards& guards>= (. Expression e; .)
+MetaExpr<e> (. guards.add(std::move(e)); .).
-MetaExpr<MetaExpression& e>=
+MetaExpr<Expression& e>= (.Operator op; Expression e2; .)
MetaExpr2<e>
-[MetaOp<op> MetaExpr2<e2> (. MetaParameters params;
- params.add(e);
- params.add(e2);
- e = MetaExpression(op, params); .)
+[MetaOp<op> MetaExpr2<e2> (. e = Expression(op, {e, e2}); .)
].
-MetaExpr2<MetaExpression& e>= (. std::wstring i1, i2, infix; MetaParameters params; .)
-( IF(checkParametersList()) Ident<i1> '(' [ MetaParams<params> ] ')'
- (. e = MetaExpression(Operator::CALL, i1, params); .)
+MetaExpr2<Expression& e>= (. std::wstring i1, i2, infix; .)
+( IF(checkParametersList()) Ident<i1> (. e = Expression(Operator::CALL, {Expression(Atom<Identifier_t>(i1))}); .)
+'(' [ CalleeParams<e> ] ')'
| IF(checkInfix()) Ident<i1> Ident<infix> Ident<i2>
- (. params.add(Expression(Atom<Identifier_t>(i1->val)));
- params.add(Expression(Atom<Identifier_t>(i2->val)));
- e = MetaExpression(Operator::CALL, Atom<Identifier_t>(infix->val), params); .)
-| Ident<i1> (. e = MetaExpression(Atom<Identifier_t>(i1->val)); .)
+ (. e = Expression(Operator::CALL, {Expression(Atom<Identifier_t>(infix))});
+ e.addArg(Expression(Atom<Identifier_t>(i1)));
+ e.addArg(Expression(Atom<Identifier_t>(i2)));
+ .)
+| Ident<i1> (. e = Expression(Atom<Identifier_t>(i1)); .)
| '(' MetaExpr<e> ')'
).
-MetaParams<MetaParameters& params> = (. MetaExpr e; .)
-MetaExpr<e> (. params.add(e); .)
-{',' MetaExpr<e> (. params.add(e).)
-}.
-
-RBody<RuleBody& body> = (. MetaExpr e; .)
- "warning" MetaExpr<e> ["message" string] .
+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; .)
+ '-' '>' (. op = Operator::IMPL; .)
.
/*============================ Expressions ===============================*/
+// dublicates CalleeParams
ListLiteral<Expression& e> = (. Expression e2; .)
-'[' (. e = Expression(Operator::LIST, Expression()); .)
-[ Expr<e2> (. e.addArg(e2); .)
-{',' Expr<e2> (. e.addArg(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); e.addArg(e2); .)
+SimExpr< e2> (. e = Expression(op, {e, e2}); .)
].
SimExpr< Expression& e> (. Operator op; Expression e2; .)
= Term< e>
{ AddOp< op>
- Term< e2> (. e = Expression(op, e); e.addArg(e2);.)
+ Term< e2> (. e = Expression(op, {e, e2});.)
}.
Term< Expression& e> (. Operator op; Expression e2; .)
= Factor< e>
{ MulOp< op>
- Factor< e2> (. e = Expression(op, e); e.addArg(e2); .)
+ 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)); .)
+ (. e = Expression(Operator::CALL, {Atom<Identifier_t>(name)}); .)
'(' [CalleeParams<e>] ')'
| Ident< name> (. e = Expression(Atom<Identifier_t>(name)); .)
| number (. e = Expression(Atom<Number_t>(t->val)); .)
- | '-' Factor< e> (. e = Expression(Operator::NEG, e); .)
+ | '-' Factor< e> (. e = Expression(Operator::NEG, {e}); .)
| '(' Expr<e> ')'
).
CalleeParams<Expression& e> = (. Expression e2; .)
- Expr<e2> (. e.addArg(e2); .)
- {',' Expr<e2> (. e.addArg(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 58c7116..e4f435f 100644
--- a/cpp/CMakeLists.txt
+++ b/cpp/CMakeLists.txt
@@ -1,68 +1,69 @@
cmake_minimum_required(VERSION 2.8.11)
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/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_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)
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})
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 118252a..bfa81ab 100644
--- a/cpp/src/ast-compilation.cpp
+++ b/cpp/src/ast-compilation.cpp
@@ -1,168 +1,168 @@
#include <ast.h>
llvm::Value*
-LLVMExpression::compile(LLVMLayer& l, Function* f, std::string* hintRetVar) const
+Function::compileExpression(const Expression& expr, LLVMLayer& l, std::string* hintRetVar=0)
{
std::string var;
- if (hintRetVar && f->__vartable.count(*hintRetVar))
+ if (hintRetVar && this->__vartable.count(*hintRetVar))
{
var = *hintRetVar;
}
#define VARNAME(x) (var.size()? var : x)
llvm::Value* left; llvm::Value* right;
- switch (__op)
+ 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(__source.__state == COMPOUND);
- assert(__source.operands.size() == 2);
+ assert(expr.__state == Expression::COMPOUND);
+ assert(expr.operands.size() == 2);
- left = __source.operands[0].compile(l, f);
- right = __source.operands[1].compile(l, f);
+ left = compileExpression(expr.operands[0], l);
+ right = compileExpression(expr.operands[1], l);
break;
default: ;
}
- switch (__op)
+ 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 = __source.operands[0].compile(l, f);
+ left = compileExpression(expr.operands[0], l);
return l.builder.CreateFNeg(left, VARNAME("tmp_neg"));
break;
case Operator::CALL:
{
- assert(__source.__state == COMPOUND);
+ assert(expr.__state == Expression::COMPOUND);
- const std::string& fname = __source.__valueS;
- assert(f->root->__indexFunctions.count(fname));
+ const std::string& fname = expr.__valueS;
+ assert(root->__indexFunctions.count(fname));
- const Function& calleeFunc = f->root->getFunctionById(f->root->__indexFunctions[fname]);
+ const Function& calleeFunc = root->getFunctionById(root->__indexFunctions[fname]);
llvm::Function* callee = calleeFunc.__raw;
std::vector<llvm::Value*> args;
- args.reserve(operands.size()-1);
+ args.reserve(expr.operands.size()-1);
- std::transform(__source.operands.begin(), __source.operands.end(), std::inserter(args, args.end()),
- [&l, f](const Expression &operand){return compile(operand, f); }
+ 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(__source.__state != COMPOUND);
+ assert(expr.__state != Expression::COMPOUND);
- switch (__source.__state)
+ switch (expr.__state)
{
- case IDENT:
+ case Expression::IDENT:
{
- std::string vname = __source.__valueS;
- assert(f->__vartable.count(vname));
+ std::string vname = expr.__valueS;
+ assert(__vartable.count(vname));
- VID vId =f->__vartable[vname];
- if (f->__rawVars.count(vId))
+ VID vId =__vartable.at(vname);
+ if (__rawVars.count(vId))
{
- return f->__rawVars[vId];
+ return this->__rawVars.at(vId);
}
- Expression& e = f->__declarations[vId];
- llvm::Value* result = e.compile(l, f, &vname);
- f->__rawVars[vId] = result;
+ Expression& e = __declarations[vId];
+ llvm::Value* result = compileExpression(e, l, &vname);
+ __rawVars[vId] = result;
return result;
break;
}
- case NUMBER:
- double literal = __valueD;
+ case Expression::NUMBER:
+ double literal = expr.__valueD;
return llvm::ConstantFP::get(llvm::getGlobalContext(), llvm::APFloat(literal));
};
break;
}
assert(false);
return 0;
}
llvm::Function*
Function::compile(LLVMLayer &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];
assert(__definitions.count(argid));
return __definitions[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 : __args)
{
VID argid = __vartable[arg];
__rawVars[argid] = fargsI;
fargsI->setName(arg);
++fargsI;
}
llvm::BasicBlock *block = llvm::BasicBlock::Create(llvm::getGlobalContext(), "entry", __raw);
l.builder.SetInsertPoint(block);
- l.builder.CreateRet(__body.compile(l, this, 0));
+ 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);
}
}
diff --git a/cpp/src/ast.cpp b/cpp/src/ast.cpp
index fcc157f..3faabe7 100644
--- a/cpp/src/ast.cpp
+++ b/cpp/src/ast.cpp
@@ -1,236 +1,243 @@
#include "ast.h"
#include <stdexcept>
#include <iostream>
#include <QString>
#include <clasplayer.h>
using namespace std;
TypeAnnotation::TypeAnnotation()
{}
TypeAnnotation::TypeAnnotation(const Atom<Type_t> &typ)
{
__value = typ.get();
}
TypeAnnotation::TypeAnnotation(const TypeOperator &op, const TypeAnnotation &typ)
{}
llvm::Type*
TypeAnnotation::toLLVMType()
{
switch (__value)
{
case Bool:
return llvm::Type::getInt1Ty(llvm::getGlobalContext());
case Int:
case Float:
case Num:
return llvm::Type::getDoubleTy(llvm::getGlobalContext());
default:
assert(false);
}
return NULL;
}
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)
{
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);
}
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 wstring &name)
+Function::Function(const Atom<Identifier_t>& name)
:__vCounter(0)
{
- char buffer[1000];
- wcstombs(buffer, name.c_str(), 1000);
- __name = buffer;
+ __name = name.get();
+
}
void
-Function::addAnnotation(const wstring& aname, const AnnotationModifier amod)
+Function::addTag(const Atom<Identifier_t>& aname, const TagModifier amod)
{
- char buffer[1000];
- wcstombs(buffer, aname.c_str(), 1000);
- std::string name(buffer);
-
- cout << QString("Function annotation: %1 <- %2").arg(__name.c_str()).arg(name.c_str()).toStdString()<<endl;
- __tags.push_back(std::make_pair(name, amod));
+ cout << QString("Function annotation: %1 <- %2").arg(__name.c_str()).arg(aname.get().c_str()).toStdString()<<endl;
+ __tags.emplace_back(aname.get(), amod);
}
-const std::vector<std::pair<std::string, AnnotationModifier>>&
+const std::vector<std::pair<std::string, TagModifier>>&
Function::getAnnotations() const
{
return __tags;
}
void
-Function::addArg(const wstring &vname, const TypeAnnotation &typ)
+Function::addArg(const Atom<Identifier_t> &vname, const TypeAnnotation &typ)
{
- char buffer[1000];
- wcstombs(buffer, vname.c_str(), 1000);
- std::string name(buffer);
-
- VID id = registerVar(name);
+ VID id = registerVar(vname.get());
__definitions[id] = typ;
- __args.push_back(name);
+ __args.push_back(vname.get());
}
void
Function::setBody(const Expression &body)
{
__body = body;
}
void
Function::setReturnType(const TypeAnnotation &rtyp)
{
__retType = rtyp;
}
VID
Function::registerVar(const std::string& vname)
{
__vartable[vname] = ++__vCounter;
return __vCounter;
}
const std::string&
Function::getName() const
{
return __name;
}
void
-Function::addListDeclaration(const wstring &vname, const TypeAnnotation &typ, const Expression &e)
+Function::addListDeclaration(const Atom<Identifier_t> &vname, const TypeAnnotation &typ, const Expression &e)
{}
void
-Function::addDeclaration(const wstring &vname, const TypeAnnotation &typ, const Expression &e)
+Function::addDeclaration(const Atom<Identifier_t> &vname, const TypeAnnotation &typ, const Expression &e)
{
- char buffer[1000];
- wcstombs(buffer, vname.c_str(), 1000);
-
- std::string v(buffer);
-
- VID id = registerVar(v);
+ VID id = registerVar(vname.get());
__definitions[id] = typ;
__declarations[id] = e;
}
void
-RuleArguments::add(std::string&& name, DomainAnnotation typ)
+RuleArguments::add(const Atom<Identifier_t> &arg, DomainAnnotation typ)
{
- emplace_back(name, 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);
+ layer.addRuleWarning(*this);
}
+
diff --git a/cpp/src/ast.h b/cpp/src/ast.h
index 22b8597..52645f0 100644
--- a/cpp/src/ast.h
+++ b/cpp/src/ast.h
@@ -1,248 +1,276 @@
#ifndef AST_H
#define AST_H
#include <vector>
#include <stdlib.h>
#include <string>
#include "llvmlayer.h"
+#include <list>
+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[1000];
- wcstombs(buffer, value.c_str(), 1000);
+ 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);
}
- int get()const {return __value; }
+ 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};
template<> class Atom<Type_t>
{
public:
Atom(wchar_t* value)
{
- char buffer_[1000];
- wcstombs(buffer_, value, 1000);
+ char buffer_[32];
+ wcstombs(buffer_, value, 32);
std::string buffer(buffer_);
if (buffer=="bool"){
__value = Bool;
} else if (buffer=="int") {
__value = Int;
} else if (buffer=="float") {
__value = Float;
} else if (buffer=="num") {
__value = Num;
} else if (buffer=="string") {
__value = String;
}
}
Atom ()
{
}
TimePrimitive get() const
{
return __value;
}
private:
TimePrimitive __value;
};
typedef Atom<Type_t> TypeAtom;
enum class TypeOperator{LIST};
class TypeAnnotation
{
public:
TypeAnnotation (const Atom<Type_t>& typ);
TypeAnnotation (const TypeOperator& op, const TypeAnnotation& typ);
TypeAnnotation();
llvm::Type* toLLVMType();
private:
TimePrimitive __value;
};
enum class Operator
{
ADD, SUB, MUL, DIV, EQU, LSS, GTR, NEG, LIST, CALL, NONE, IMPL/* implication */
};
class Function;
class AST;
class Expression
{
+ friend class Function;
+ 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;
std::vector<Expression> operands;
std::string __valueS;
double __valueD;
enum {INVALID, COMPOUND, IDENT, NUMBER, STRING} __state;
};
-enum class AnnotationModifier
+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(std::string&& name, DomainAnnotation typ);
+ 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 ClaspLayer;
class RuleWarning: public MetaRuleAbstract
{
friend class ClaspLayer;
public:
- void compile(ClaspLayer& layer);
+ 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
{
friend class Expression;
friend class CFGPass;
public:
- Function(const std::wstring& name);
+ Function(const Atom<Identifier_t>& name);
void setReturnType(const TypeAnnotation& rtyp);
- void addArg(const std::wstring& vname, const TypeAnnotation& typ);
+ void addArg(const Atom<Identifier_t>& vname, const TypeAnnotation& typ);
void setBody(const Expression& body);
- void addAnnotation(const std::wstring& aname, const AnnotationModifier amod);
- const std::vector<std::pair<std::string, AnnotationModifier>>& getAnnotations() const;
+ void addTag(const Atom<Identifier_t>& aname, const TagModifier amod);
+ const std::vector<std::pair<std::string, TagModifier>>& getAnnotations() const;
- void addDeclaration(const std::wstring& vname, const TypeAnnotation& typ, const Expression& e);
- void addListDeclaration(const std::wstring& vname, const TypeAnnotation& typ, const Expression& e);
+ 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);
const std::string& getName() const;
llvm::Function* compile(LLVMLayer& l);
AST* root;
private:
std::string __name;
TypeAnnotation __retType;
std::vector<std::string> __args;
- std::vector<std::pair<std::string, AnnotationModifier>> __tags;
+ 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;
llvm::Function* __raw;
std::map<VID,llvm::Value*> __rawVars;
VID __vCounter;
VID registerVar(const std::string& vname);
- llvm::Value* compileExpression(Expression& expr, LLVMLayer& l, std::string* hintRetVar) const;
+ llvm::Value* compileExpression(const Expression& expr, LLVMLayer& l, std::string* hintRetVar);
};
typedef unsigned int FID;
class AST
{
- friend class Expression;
+ friend class Function;
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 a657703..fe75d6d 100644
--- a/cpp/src/clasplayer.cpp
+++ b/cpp/src/clasplayer.cpp
@@ -1,276 +1,306 @@
#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>
-#include <QString>
-#include <QStringList>
+
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);
+ }
+ }
+
+ for (auto warning: warnings)
+ {
+ cout << "Warning: "<< warning << endl;
}
}
QStringList multiplyLists(std::list<QStringList>&& lists)
{
- QStringList&& result = lists.front();
+ 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;
- StringList::const_iterator expr2I=list.begin();
+ 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);
}
}
return result;
}
void
ClaspLayer::addCFGData(CFGraph &&graph)
{
ostream& cout = __partGeneral;
cout <<endl<< "%\t\tStatic analysis: CFG" << endl;
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;
int tagsCount=0;
for(Tag tag: tags)
{
cout << QString("tag(%1, %2).").arg(function.c_str()).arg(tag.first.c_str()).toStdString() << endl;
++tagsCount;
}
if (tagsCount == 0)
{
cout << "%no tags at all" << endl;
}
}
void
-ClaspLayer::addRuleWarning(RuleWarning* rule)
+ClaspLayer::addRuleWarning(const RuleWarning& rule)
{
//__partGeneral << rule << endl;
- std::QStringList domains;
- std::transform(rule->__args.begin(), rule->__args.end(), std::inserter(domains, domains.begin()),
- [](const auto& argument) {
+ 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());
});
- std::QStringList vars;
- std::transform(rule->__args.begin(), rule->__args.end(), std::inserter(vars, vars.begin()),
- [](const auto& argument) {
+ 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::QStringList guards;
- std::transform(rule->__guards.begin(), rule->__guards.end(), std::inserter(guards, guards.begin()),
- [](const MetaExpression& guard) {
- return compile(guard)._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&& branches = compileNeg(rule->__condition);
+ QStringList guards = multiplyLists(std::move(guardsRaw));
+ QStringList&& branches = compileNeg(rule.__condition);
- for(const std::string& branch: branches)
+ for (const QString& guardsJoined: guards)
+ for(const QString& branch: branches)
{
- std::string listener = registerListener(rule->__message);
+ const std::string&& hook = registerHook(rule.__message);
- result = QString("%1(%2):-%3, %4, %5")
- .arg(listener.c_str())
+ QString result = QString("%1(%2):-%3, %4, %5.")
+ .arg(hook.c_str())
.arg(vars.join(", "))
- .arg(branch.c_str())
- .arg(guards.join(", "))
+ .arg(branch)
+ .arg(guardsJoined)
.arg(domains.join(", "));
- __partGeneral<< result << endl;
+ __partGeneral<< result.toStdString() << endl;
}
}
QStringList
ClaspLayer::compile(const Expression& e) const
{
QStringList result;
switch(e.__op)
{
case Operator::CALL:
- assert(e.__state == COMPOUND);
+ {
+ assert(e.__state == Expression::COMPOUND);
std::list<QStringList> operands;
- std::transform(e.operands.begin(), e.operands.end(), std::inserter(operands, operands().begin()),
- [](const Expression& e) {return compile(e);});
+ std::transform(e.operands.begin(), e.operands.end(), std::inserter(operands, operands.begin()),
+ [this](const Expression& e) {return compile(e);});
- QStringList&& operands_ = multiplyLists(operands);
+ QStringList&& operands_ = multiplyLists(std::move(operands));
result.append(QString("%1(%2)").arg(e.__valueS.c_str()).arg(operands_.join(", ")));
break;
+ }
case Operator::NONE:
+ {
switch (e.__state)
{
case Expression::IDENT:
- result.append(e.__valueS);
+ result.append(QString(e.__valueS.c_str()));
break;
case Expression::NUMBER:
- result.append(e.__valueD);
+ result.append(QString::number(e.__valueD));
break;
default:
assert(true);
}
break;
}
+ }
return result;
}
-QStringList compileNeg(const Expression& e) const
+QStringList
+ClaspLayer::compileNeg(const Expression& e) const
{
QStringList result;
- switch(__op)
+ switch(e.__op)
{
case Operator::IMPL:
- assert(e.__state == COMPOUND);
+ {
+ 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;
+ }
default:
assert(true);
}
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));
+
+ return hookId;
+}
+
void
ClaspLayer::run()
{
ostringstream program;
program << __partTags.str() << __partGeneral.str();
cout << program.str() << endl;
const char* argv[] = {nullptr, nullptr};
ClingoLib ctl(2, argv);
//prg.add("p", ["t"], "q(t).")
Gringo::FWStringVec vars{};
ctl.add("base", vars, program.str());
//prg.ground([("p", [2])])
Gringo::Control::GroundVec vals{std::make_pair("base", Gringo::FWValVec {})};
ctl.ground(vals, Gringo::Any());
//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;
}
}
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)));
}
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));
}
diff --git a/cpp/src/clasplayer.h b/cpp/src/clasplayer.h
index 7a8495e..c4ba9a5 100644
--- a/cpp/src/clasplayer.h
+++ b/cpp/src/clasplayer.h
@@ -1,44 +1,50 @@
#ifndef CLASPLAYER_H
#define CLASPLAYER_H
#include <string>
#include <gringo/control.hh>
#include <ast.h>
+#include <QStringList>
-typedef std::pair<std::string, AnnotationModifier> Tag;
+typedef std::pair<std::string, TagModifier> Tag;
class CFGraph;
class ClaspLayer
{
public:
ClaspLayer();
void addFunctionTags(const std::string& function, const std::vector<Tag>& tags);
void addCFGData(CFGraph&& graph);
- void addWarningRule(const char* rule);
+ void addRuleWarning(const RuleWarning& rule);
void run();
private:
+ std::map<std::string, std::string> __hooks;
std::ostringstream __partTags;
std::ostringstream __partGeneral;
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);
};
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;
private:
std::map<FID, FID> __relations;
std::map<FID, std::string> __nodes;
};
#endif
diff --git a/cpp/src/llvmlayer.cpp b/cpp/src/llvmlayer.cpp
index 99a16b7..97f5978 100644
--- a/cpp/src/llvmlayer.cpp
+++ b/cpp/src/llvmlayer.cpp
@@ -1,17 +1,13 @@
#include "llvmlayer.h"
using namespace llvm;
LLVMLayer::LLVMLayer()
:builder(getGlobalContext())
{
}
void
LLVMLayer::moveToGarbage(void *o)
{
__garbage.push_back(o);
}
-
-LLVMExpression::LLVMExpression(Expression &&e)
- : Delegate<Expression>(e)
-{}
diff --git a/cpp/src/pass/rulespass.cpp b/cpp/src/pass/rulespass.cpp
new file mode 100644
index 0000000..c97577c
--- /dev/null
+++ b/cpp/src/pass/rulespass.cpp
@@ -0,0 +1,14 @@
+#include "rulespass.h"
+
+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
new file mode 100644
index 0000000..eb7f8d4
--- /dev/null
+++ b/cpp/src/pass/rulespass.h
@@ -0,0 +1,16 @@
+#ifndef RULESPASS_H
+#define RULESPASS_H
+#include <ast.h>
+#include <clasplayer.h>
+
+class RulesPass
+{
+public:
+ RulesPass(const AST& ast);
+ void run(ClaspLayer& clasp);
+
+private:
+ const AST& __root;
+};
+
+#endif // RULESPASS_H
diff --git a/cpp/src/utils.h b/cpp/src/utils.h
new file mode 100644
index 0000000..965be11
--- /dev/null
+++ b/cpp/src/utils.h
@@ -0,0 +1,10 @@
+#ifndef UTILS_H
+#define UTILS_H
+/*
+template<class T>
+struct DdesctructableClass<T> {
+
+}
+*/
+
+#endif // UTILS_H
diff --git a/cpp/tests/tests.cpp b/cpp/tests/tests.cpp
index 726d165..e3cc471 100644
--- a/cpp/tests/tests.cpp
+++ b/cpp/tests/tests.cpp
@@ -1,61 +1,89 @@
#include "Scanner.h"
#include "Parser.h"
#include "ast.h"
#include <memory>
#include <iostream>
-#include "cfgpass.h"
+#include "pass/cfgpass.h"
+#include "pass/functiontagspass.h"
+#include "pass/rulespass.h"
+
#include "clasplayer.h"
-#include "functiontagspass.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).");
+
+ clasp.run();
+}
+
+void testUnsafeCode1()
+{
+ shared_ptr<Scanner> scanner(new Scanner(L"scripts/cases/unsafe-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);
- clasp.addRule(":- call(X, Y), tag(Y, unsafe), not tag(X, unsafe), function(X), function(Y).");
+ //clasp.addRule(":- call(X, Y), tag(Y, unsafe), not tag(X, unsafe), function(X), function(Y).");
clasp.run();
}
void tests_ListsMultiply()
{
}
int main()
{
- testClasp2();
+ testUnsafeCode1();
return 0;
}
diff --git a/scripts/cases/unsafe-code.xreate b/scripts/cases/unsafe-code.xreate
new file mode 100644
index 0000000..9705f31
--- /dev/null
+++ b/scripts/cases/unsafe-code.xreate
@@ -0,0 +1,23 @@
+
+//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
+{
+ x = a+b: num;
+ y = a - b: num;
+
+ (x + y) / 2;
+}
+
+testfunc2 = function: (a: num)->bool // since testfunc3 marked as unsafe code,
+ // testfunc2 should be marked so too
+{
+ b = testfunc3(a+1, a-1): num;
+ (b==0);
+}
diff --git a/scripts/input.xreate b/scripts/input.xreate
index 22294b3..20c792c 100644
--- a/scripts/input.xreate
+++ b/scripts/input.xreate
@@ -1,45 +1,42 @@
-/*
//unsafe code propagation rule
rule: (X: function, Y: function)
-case X calls Y
+case X call Y
{
- warning Y has unsafe --> X has unsafe
- message format("function A should not call unsafe code B", X as A, Y as B)
+ 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
{
x = a+b: num;
y = a - b: num;
(x + y) / 2;
}
-testfunc2 = function: (a: num)->bool // because of testfunc3 marked as unsafe code,
+testfunc2 = function: (a: num)->bool, unsafe // because of testfunc3 marked as unsafe code,
// testfunc2 should be marked so too
{
b = testfunc3(a+1, a-1): num;
(b==0);
}
-/*
+/*cl
find6 = function: bool
{
x = [1, 2, 3, 4, 5, 6, 7]: [num]; //эффективная инициализация
y = map (x) [el]-> {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