From 4ac0ac96eb3c768dcf210cbc0880a48eb4061f76 Mon Sep 17 00:00:00 2001 From: Michael Date: Sun, 5 Jan 2025 17:12:09 +0100 Subject: [PATCH] add files --- SL3a.txt | 6 + SL3b.txt | 4 + SL3c.txt | 7 + SL3d.txt | 9 + SL3e.txt | 24 ++ SL3f.txt | 16 ++ arden_types.py | 294 ++++++++++++++++++++++ grammar.y | 664 +++++++++++++++++++++++++++++++++++++++++++++++++ interpreter.py | 222 +++++++++++++++++ parser.py | 11 + run.py | 21 ++ tokenizer.py | 59 +++++ 12 files changed, 1337 insertions(+) create mode 100644 SL3a.txt create mode 100644 SL3b.txt create mode 100644 SL3c.txt create mode 100644 SL3d.txt create mode 100644 SL3e.txt create mode 100644 SL3f.txt create mode 100644 arden_types.py create mode 100644 grammar.y create mode 100644 interpreter.py create mode 100644 parser.py create mode 100644 run.py create mode 100644 tokenizer.py diff --git a/SL3a.txt b/SL3a.txt new file mode 100644 index 0000000..ff88af0 --- /dev/null +++ b/SL3a.txt @@ -0,0 +1,6 @@ +write 1 & 1; +write "Hallo Welt"; +write "Hallo" & "Welt"; +write 1 & "Welt"; +x := 4711; +write x; \ No newline at end of file diff --git a/SL3b.txt b/SL3b.txt new file mode 100644 index 0000000..a75a88a --- /dev/null +++ b/SL3b.txt @@ -0,0 +1,4 @@ +write 1+"1"; +write 1+true; +write 1 & "1"; +write "1"&false; \ No newline at end of file diff --git a/SL3c.txt b/SL3c.txt new file mode 100644 index 0000000..898dc8e --- /dev/null +++ b/SL3c.txt @@ -0,0 +1,7 @@ +testlist := [1,2,"Hallo",4,5,null,false,true]; +trace testlist; +trace testlist is number; +trace testlist is list; +trace testlist is not list; +trace count testlist; +trace first testlist; \ No newline at end of file diff --git a/SL3d.txt b/SL3d.txt new file mode 100644 index 0000000..f6568dc --- /dev/null +++ b/SL3d.txt @@ -0,0 +1,9 @@ +a := 4711; +trace time a; +b := 2020-01-01T12:00:00; +time a := b; +c := a; +time c := now; +trace time c; +trace time a; +trace time [1,2,3]; \ No newline at end of file diff --git a/SL3e.txt b/SL3e.txt new file mode 100644 index 0000000..2bf9372 --- /dev/null +++ b/SL3e.txt @@ -0,0 +1,24 @@ +testlist := [100, 200, 50, 120, 150, 90] ; + +trace testlist where [true, false, false, true, true, false]; +trace testlist where it is less than or equal 100; +trace testlist where it is within 80 to 120; +trace testlist where it is within 100 to [100,110,120,130,140,150]; + +trace testlist where 2 * it / 3 is within 80 to 120; + +testlist[2] := 199; +trace testlist; + +x := 100; +y := 200; +z := 300; + +time of x := 2020-06-08T15:15:15; +time of y := 2020-06-09T11:11:00; +time of z := 2020-06-10T12:00:00; + +xyz := [x,y,z]; + +trace xyz where it occurs before time of z; +trace xyz where they occurred after time of x; diff --git a/SL3f.txt b/SL3f.txt new file mode 100644 index 0000000..0d60a90 --- /dev/null +++ b/SL3f.txt @@ -0,0 +1,16 @@ +for x in 12 ... 18 do + + bmi := x * 2.3; + + if bmi is greater than or equal 40 then + trace "Adipositas III"; + elseif bmi is greater than or equal 35 then + trace "Adipositas II"; + elseif bmi is greater than or equal 30 then + trace "Adipositas I"; + else + trace "Keine Adipositas"; + endif; +enddo; + +//trace bmi; \ No newline at end of file diff --git a/arden_types.py b/arden_types.py new file mode 100644 index 0000000..cee8992 --- /dev/null +++ b/arden_types.py @@ -0,0 +1,294 @@ +from abc import ABC, abstractmethod +from datetime import date + +class BaseType(ABC): + @abstractmethod + def __str__(self): + pass + + def __init__(self): + self.time = NullType(False) + + def __repr__(self): + return str(self) + + #def __eq__(self,b): + # return BoolType(str(type(self).__name__) is b) + + def __and__(self,other): + if isinstance(other, StrType): + return StrType(str(self) + str(other)) + return NullType() + + def IS(self,b,invert=False): + if b is type(self): + return BoolType(True) + return BoolType(False) + + def NOT(self,b,invert=False): + return NullType() + + def ISNOT(self,b,invert=False): + return ~self.IS(b) + + def LISTACCESS(self,b): + return NullType() + + def TIME(self): + return self.time + + +class NumType(BaseType): + def __init__(self, value: (int, float)): + super().__init__() + if isinstance(value, str): + try: + value = int(value) + except ValueError: + value = float(value) + if not isinstance(value, (int, float)): + raise TypeError(f"Expected a number, got {type(value)}") + self.value = value + + def __mul__(self,other): + if isinstance(other, NumType): + return NumType(self.value * other.value) + if isinstance(other, ListType): + return ListType([item * self for item in other.value]) + return NullType() + + def __truediv__(self,other): + if isinstance(other, NumType): + return NumType(self.value / other.value) + if isinstance(other, ListType): + return ListType([item / self for item in other.value]) + return NullType() + + def __add__(self,other): + if isinstance(other, NumType): + return NumType(self.value + other.value) + return NullType() + + def __sub__(self,other): + if isinstance(other, NumType): + return NumType(self.value - other.value) + return NullType() + + def __gt__(self, other): + if isinstance(other, NumType): + return BoolType(self.value > other.value) + return NullType + + def __lt__(self, other): + if isinstance(other, NumType): + return BoolType(self.value < other.value) + return NullType + + def __ge__(self, other): + if isinstance(other, NumType): + return BoolType(self.value >= other.value) + if isinstance(other, ListType): + return ListType([self >= item for item in other.value]) + return NullType + + def __le__(self, other): + if isinstance(other, NumType): + return BoolType(self.value <= other.value) + if isinstance(other, ListType): + return ListType([self <= item for item in other.value]) + return NullType + + def __pow__(self, other): + if isinstance(other, NumType): + return NumType(self.value ** other.value) + return NullType + + def __neg__(self): + return NumType(-self.value) + + def __str__(self): + return str(self.value) + + def IS(self,b,invert=False): + if b is type(self): + return BoolType(True) + if type(b) is self: + return BoolType(self.value == b.value) + if type(b) is Condition: + return b.value(self) + return BoolType(False) + +class StrType(BaseType): + def __init__(self, value: str): + super().__init__() + if not isinstance(value, str): + raise TypeError(f"Expected a string, got {type(value)}") + self.value = value + + def __and__(self,other): + return StrType(str(self) + str(other)) + + def __str__(self): + return self.value + +class BoolType(BaseType): + def __init__(self, value: bool): + super().__init__() + if not isinstance(value, bool): + raise TypeError(f"Expected a boolean, got {type(value)}") + self.value = value + + def __eq__(self, other): + return self.value == other.value + + def __bool__(self): + return self.value + + def __invert__(self): + return BoolType(not self.value) + + def __str__(self): + if self.value: + return "true" + else: + return "false" + + def __and__(self,other): + if isinstance(other, BoolType): + return BoolType(self.value and other.value) + return NullType + + def NOT(self): + return ~self + +class ListType(BaseType): + def __init__(self, value: list): + super().__init__() + if not isinstance(value, list): + raise TypeError(f"Expected a list, got {type(value)}") + self.value = value + + def __str__(self): + return f"[{', '.join(str(item) for item in self.value)}]" + + def __gt__(self, other): + if isinstance(other, NumType): + return ListType([item > other for item in self.value]) + return NullType + + def __lt__(self, other): + if isinstance(other, NumType): + return ListType([item < other for item in self.value]) + return NullType + + def __ge__(self, other): + if isinstance(other, NumType): + return ListType([item >= other for item in self.value]) + if isinstance(other, ListType) and len(self.value) == len(other.value): + return ListType([a_item >= b_item for a_item, b_item in zip(self.value, other.value)]) + return NullType + + def __le__(self, other): + if isinstance(other, NumType): + return ListType([item <= other for item in self.value]) + if isinstance(other, ListType) and len(self.value) == len(other.value): + return ListType([a_item <= b_item for a_item, b_item in zip(self.value, other.value)]) + return NullType + + def __and__(self,other): + if isinstance(other, BoolType) or isinstance(other, NumType): + return ListType([item and other for item in self.value]) + if isinstance(other, ListType) and len(self.value) == len(other.value): + return ListType([a_item and b_item for a_item, b_item in zip(self.value, other.value)]) + return NullType + + def __or__(self,other): + if isinstance(other, BoolType) or isinstance(other, NumType): + return ListType([item or other for item in self.value]) + if isinstance(other, ListType) and len(self.value) == len(other.value): + return ListType([a_item or b_item for a_item, b_item in zip(self.value, other.value)]) + return NullType + + def __truediv__(self,other): + if isinstance(other, NumType): + return ListType([item / other for item in self.value]) + if isinstance(other, ListType) and len(self.value) == len(other.value): + return ListType([a_item / b_item for a_item, b_item in zip(self.value, other.value)]) + return NullType + + def WHERE(self,other): + if isinstance(other, ListType) and len(self.value) == len(other.value): + return ListType([a_item for a_item, b_item in zip(self.value, other.value) if b_item]) + return NullType + + def IS(self,a,invert=False): + if a is NumType: + return ListType([item.IS(a) for item in self.value]) + if a is type(self): + return BoolType(True^invert) + if type(a) is Condition: + return a.value(self) + else: + return BoolType(False^invert) + + def OCCURS(self,a): + if type(a) is Condition: + return ListType([a.value(item.time) for item in self.value]) + + def NOT(self): + return ListType([~item for item in self.value]) + + def LISTACCESS(self,a): + if type(a) is NumType: + return self.value[a.value] + return NullType() + + def LISTINDEXASSIGN(self,a,b): + if type(a) is NumType: + self.value[a.value-1] = b + #self.value.insert(a.value,b) + return NullType() + + def TIME(self): + return ListType([item.time for item in self.value]) + +class DateType(BaseType): + def __init__(self, value: date): + super().__init__() + if not isinstance(value, date): + raise TypeError(f"Expected a date, got {type(value)}") + self.value = value + + def __gt__(self, other): + if isinstance(other, DateType): + return BoolType(self.value > other.value) + return NullType + + def __lt__(self, other): + if isinstance(other, DateType): + return BoolType(self.value < other.value) + return NullType + + def __str__(self): + return self.value.strftime('%Y-%m-%dT%H:%M:%S') + +class Condition(BaseType): + def __init__(self, condition): + self.value = condition + + def __and__(self, other): + return Condition(lambda x: self.value(x) and other.value(x)) + + def __or__(self,other): + return Condition(lambda x: self.value(x) or other.value(x)) + + def __str__(self): + return str(self.value) + +class NullType(BaseType): + def __init__(self, has_time=True): + if has_time: + super().__init__() + + def __str__(self): + return "Null" \ No newline at end of file diff --git a/grammar.y b/grammar.y new file mode 100644 index 0000000..c75cfcc --- /dev/null +++ b/grammar.y @@ -0,0 +1,664 @@ +%include { + +#include "grammar.h" +#include +#include +#include +#include +#include +#include "cJSON.h" + + +using namespace std; +int get_token_id (char*); +const char *getValue (cJSON *token); +const char *getLine (cJSON *token); +cJSON *unary (char *fname, cJSON *a); +cJSON *binary (char *fname, cJSON *a, cJSON *b); +cJSON *ternary (char *fname, cJSON *a, cJSON *b, cJSON *c); +char *linenumber; +char *curtoken; +char *curtype; +} + + +%code { + +using namespace std; +typedef struct {char *value; int line;} token; + +token* create_token (char *value, int line) { + token *t = (token*) malloc (sizeof (token)); + t->value = strdup (value); + t->line = line; + return t; +} + +const char * getValue (cJSON* token) { + return cJSON_GetObjectItem (token, "value")->valuestring; +} + + +const char * getLine (cJSON* token) { + return cJSON_GetObjectItem (token, "line")->valuestring; +} + + +int main(int argc, char* argv[]) { + char *result; + std::string line; + std::string input = ""; + while (std::getline(std::cin, line)) { + input += line + "\n"; + } + if (input == "") { + cout << "Empty input"; + exit(0); + } + + cJSON *root = cJSON_Parse(input.c_str()); + + if (!root) { + cout << "JSON invalid\n"; + exit(0); + } + + void* pParser = ParseAlloc (malloc); + int num = cJSON_GetArraySize (root); + + for (int i = 0; i < num; i++ ) { + + // Knoten im Token-Stream auslesen + cJSON *node = cJSON_GetArrayItem(root,i); + + char *line = cJSON_GetArrayItem(node,0)->valuestring; + char *type = cJSON_GetArrayItem(node,1)->valuestring; + char *value = cJSON_GetArrayItem(node,2)->valuestring; + + cJSON *tok = cJSON_CreateObject(); + cJSON_AddStringToObject(tok, "value", value); + cJSON_AddStringToObject(tok, "line", line); + + linenumber = line; + curtoken = value; + curtype = type; + // THE und Kommentare werden ueberlesen + if (strcmp(type, "THE") == 0) continue; + if (strcmp(type, "COMMENT") == 0) continue; + if (strcmp(type, "MCOMMENT") == 0) continue; + + int tokenid = get_token_id (type); + Parse (pParser, tokenid, tok); + + } + Parse (pParser, 0, 0); + ParseFree(pParser, free ); +} + + + + +/////////////////////// +/////////////////////// +// TOKENS +/////////////////////// +/////////////////////// + +int get_token_id (char *token) { + if (strcmp(token, "AMBERSAND") == 0) return AMBERSAND; + if (strcmp(token, "ASSIGN") == 0) return ASSIGN; + if (strcmp(token, "AND") == 0) return AND; + if (strcmp(token, "AFTER") == 0) return AFTER; + if (strcmp(token, "BEFORE") == 0) return BEFORE; + if (strcmp(token, "BETWEEN") == 0) return BETWEEN; + if (strcmp(token, "COS") == 0) return COS; + if (strcmp(token, "COMMA") == 0) return COMMA; + if (strcmp(token, "COUNT") == 0) return COUNT; + if (strcmp(token, "DIVIDE") == 0) return DIVIDE; + if (strcmp(token, "DO") == 0) return DO; + if (strcmp(token, "EQUAL") == 0) return EQUAL; + if (strcmp(token, "ENDDO") == 0) return ENDDO; + if (strcmp(token, "ENDIF") == 0) return ENDIF; + if (strcmp(token, "ELSE") == 0) return ELSE; + if (strcmp(token, "ELSEIF") == 0) return ELSEIF; + if (strcmp(token, "FIRST") == 0) return FIRST; + if (strcmp(token, "FOR") == 0) return FOR; + if (strcmp(token, "GT") == 0) return GT; + if (strcmp(token, "GREATER") == 0) return GREATER; + if (strcmp(token, "IDENTIFIER") == 0) return IDENTIFIER; + if (strcmp(token, "IS") == 0) return IS; + if (strcmp(token, "ISNOT") == 0) return ISNOT; + if (strcmp(token, "IF") == 0) return IF; + if (strcmp(token, "IT") == 0) return IT; + if (strcmp(token, "THEY") == 0) return IT; + if (strcmp(token, "IN") == 0) return IN; + if (strcmp(token, "LIST") == 0) return LIST; + if (strcmp(token, "LPAR") == 0) return LPAR; + if (strcmp(token, "RPAR") == 0) return RPAR; + if (strcmp(token, "LSPAR") == 0) return LSPAR; + if (strcmp(token, "RSPAR") == 0) return RSPAR; + if (strcmp(token, "LT") == 0) return LT; + if (strcmp(token, "LESS") == 0) return LESS; + if (strcmp(token, "MINUS") == 0) return MINUS; + if (strcmp(token, "NUMBER") == 0) return NUMBER; + if (strcmp(token, "NUMTOKEN") == 0) return NUMTOKEN; + if (strcmp(token, "NULLTOKEN") == 0) return NULLTOKEN; + if (strcmp(token, "OR") == 0) return OR; + if (strcmp(token, "OF") == 0) return OF; + if (strcmp(token, "OCCURS") == 0) return OCCURS; + if (strcmp(token, "OCCURRED") == 0) return OCCURS; + if (strcmp(token, "PLUS") == 0) return PLUS; + if (strcmp(token, "POWER") == 0) return POWER; + if (strcmp(token, "SEMICOLON") == 0) return SEMICOLON; + if (strcmp(token, "SIN") == 0) return SIN; + if (strcmp(token, "STRTOKEN") == 0) return STRTOKEN; + if (strcmp(token, "TIMETOKEN") == 0) return TIMETOKEN; + if (strcmp(token, "TIMES") == 0) return TIMES; + if (strcmp(token, "TIME") == 0) return TIME; + if (strcmp(token, "TRACE") == 0) return TRACE; + if (strcmp(token, "THAN") == 0) return THAN; + if (strcmp(token, "THEN") == 0) return THEN; + if (strcmp(token, "TO") == 0) return TO; + if (strcmp(token, "RANGE") == 0) return RANGE; + if (strcmp(token, "WRITE") == 0) return WRITE; + if (strcmp(token, "WHERE") == 0) return WHERE; + if (strcmp(token, "NOW") == 0) return NOW; + if (strcmp(token, "NOT") == 0) return NOT; + if (strcmp(token, "TRUE") == 0) return TRUE; + if (strcmp(token, "FALSE") == 0) return FALSE; + if (strcmp(token, "WITHIN") == 0) return WITHIN; + + printf ("{\"error\" : true, \"message\": \"UNKNOWN TOKEN TYPE %s\"}\n", token); + exit(0); +} + + + +cJSON* unary (char* fname, cJSON* a) +{ + cJSON *res = cJSON_CreateObject(); + cJSON *arg = cJSON_CreateArray(); + cJSON_AddItemToArray(arg, a); + cJSON_AddStringToObject(res, "type", fname); + cJSON_AddItemToObject(res, "arg", arg); + return res; +} + + + +cJSON* binary (char *fname, cJSON *a, cJSON *b) +{ + cJSON *res = cJSON_CreateObject(); + cJSON *arg = cJSON_CreateArray(); + cJSON_AddItemToArray(arg, a); + cJSON_AddItemToArray(arg, b); + cJSON_AddStringToObject(res, "type", fname); + cJSON_AddItemToObject(res, "arg", arg); + return res; +} + + + +cJSON* ternary (char *fname, cJSON *a, cJSON *b, cJSON *c) +{ + cJSON *res = cJSON_CreateObject(); + cJSON *arg = cJSON_CreateArray(); + cJSON_AddItemToArray(arg, a); + cJSON_AddItemToArray(arg, b); + cJSON_AddItemToArray(arg, c); + cJSON_AddStringToObject(res, "type", fname); + cJSON_AddItemToObject(res, "arg", arg); + return res; +} + + + +} + +%syntax_error { + printf ("{\"error\" : true, \"message\": \"Syntax Error: Compiler reports unexpected token \\\"%s\\\" of type \\\"%s\\\" in line %s\"}\n", curtoken, curtype, linenumber); + exit(0); +} + +%token_type {cJSON *} +%default_type {cJSON *} + +/////////////////////// +/////////////////////// +// PRECEDENCE +/////////////////////// +/////////////////////// +%left WHERE . +%left OR . +%left AND . +%left AMBERSAND . +%right NOT . +%left IS ISNOT GT LT LESS GREATER LESSEQUAL GREATEREQUAL WITHIN OCCURS AFTER BEFORE BETWEEN RANGE . +%left PLUS MINUS . +%left TIMES DIVIDE . +%right POWER . +%right SIN COS . +%right UMINUS . +%right TIME FIRST LAST COUNT LISTACCESS LSPAR . + + + +/////////////////////// +// CODE +/////////////////////// + + + +code ::= statementblock(sb) . +{ + printf (cJSON_Print(sb)); +} + + + +/////////////////////// +// STATEMENTBLOCK +/////////////////////// + + +statementblock(sb) ::= . +{ + cJSON *res = cJSON_CreateObject(); + cJSON_AddStringToObject(res, "type", "STATEMENTBLOCK"); + cJSON *arg = cJSON_CreateArray(); + cJSON_AddItemToObject(res, "statements", arg); + sb = res; +} + + +statementblock(sb) ::= statementblock(a) statement(b) . +{ + cJSON_AddItemToArray(cJSON_GetObjectItem ( a, "statements"), b); + sb = a; +} + + + + +/////////////////////////// +// WRITE +/////////////////////////// + +statement(r) ::= WRITE ex(e) SEMICOLON . +{ + cJSON *res = cJSON_CreateObject(); + cJSON_AddStringToObject(res, "type", "WRITE"); + cJSON_AddItemToObject(res, "arg", e); + r = res; +} + +/////////////////////////// +// Trace +/////////////////////////// +statement(r) ::= TRACE(a) ex(e) SEMICOLON . +{ + cJSON *res = cJSON_CreateObject(); + cJSON_AddStringToObject(res, "type", "TRACE"); + cJSON_AddItemToObject(res, "arg", e); + cJSON_AddStringToObject(res, "line", getLine(a)); + r = res; +} + + +/////////////////////////// +// ASSIGN +/////////////////////////// +statement(r) ::= IDENTIFIER(a) ASSIGN ex(e) SEMICOLON . +{ + cJSON *res = cJSON_CreateObject(); + cJSON_AddStringToObject(res, "type", "ASSIGN"); + cJSON_AddStringToObject(res, "varname", getValue(a)); + cJSON_AddItemToObject(res, "arg", e); + r = res; +} + + +/////////////////////////// +// ASSIGN TIME OF +/////////////////////////// +statement(r) ::= TIME of IDENTIFIER(a) ASSIGN ex(e) SEMICOLON . +{ + cJSON *res = cJSON_CreateObject(); + cJSON_AddStringToObject(res, "type", "TIMEASSIGN"); + cJSON_AddStringToObject(res, "varname", getValue(a)); + cJSON_AddItemToObject(res, "arg", e); + r = res; +} + +statement(r) ::= IDENTIFIER(a) LSPAR ex(b) RSPAR ASSIGN ex(e) SEMICOLON . +{ + cJSON *res = cJSON_CreateObject(); + cJSON *arg = cJSON_CreateArray(); + cJSON_AddStringToObject(res, "type", "LISTINDEXASSIGN"); + cJSON_AddStringToObject(res, "varname", getValue(a)); + cJSON_AddItemToArray(arg, b); + cJSON_AddItemToArray(arg, e); + cJSON_AddItemToObject(res, "arg", arg); + r = res; +} +statement(r) ::= TIME of IDENTIFIER(a) LSPAR ex(b) RSPAR ASSIGN ex(e) SEMICOLON . +{ + cJSON *res = cJSON_CreateObject(); + cJSON *arg = cJSON_CreateArray(); + cJSON_AddStringToObject(res, "type", "LISTINDEXTIMEASSIGN"); + cJSON_AddStringToObject(res, "varname", getValue(a)); + cJSON_AddItemToArray(arg, b); + cJSON_AddItemToArray(arg, e); + cJSON_AddItemToObject(res, "arg", arg); + r = res; +} + + +/////////////////////////// +// IF +/////////////////////////// +ifconditionstatement ::= ifstartstatement . +ifconditionstatement ::= elseifstatement . + +ifstatement ::= ifstartstatement . +ifstatement ::= elseifstatement . +ifstatement ::= elsestatement . + + +statement ::= ifstatement ENDIF SEMICOLON . + + +ifstartstatement(r) ::= IF ex(c) THEN +statementblock(s) +. +{ + cJSON *res = cJSON_CreateObject(); + cJSON_AddStringToObject(res, "type", "IF"); + cJSON_AddItemToObject(res, "arg", c); + cJSON_AddItemToObject(res, "statements", s); + cJSON *elseifs = cJSON_CreateArray(); + cJSON_AddItemToObject(res, "elseif", elseifs); + r = res; +} + + +elseifstatement(r) ::= ifconditionstatement(i) +ELSEIF ex(c) THEN +statementblock(s) +. +{ + cJSON *res = cJSON_CreateObject(); + cJSON_AddStringToObject(res, "type", "ELSEIF"); + cJSON_AddItemToObject(res, "arg", c); + cJSON_AddItemToObject(res, "statements", s); + cJSON *elseifArray = cJSON_GetObjectItem(i, "elseif"); + cJSON_AddItemToArray(elseifArray, res); + r = i; +} + +elsestatement(r) ::= ifconditionstatement(i) +ELSE +statementblock(s) +. +{ + cJSON *res = cJSON_CreateObject(); + cJSON_AddStringToObject(res, "type", "ELSE"); + cJSON_AddItemToObject(res, "statements", s); + cJSON_AddItemToObject(i, "else", res); + r = i; +} + + + +/////////////////////////// +// FOR +/////////////////////////// +statement(r) ::= FOR IDENTIFIER(a) IN ex(e) DO +statementblock(s) +ENDDO SEMICOLON +. +{ + cJSON *res = cJSON_CreateObject(); + cJSON *arg = cJSON_CreateArray(); + cJSON_AddStringToObject(res, "type", "FOR"); + cJSON_AddStringToObject(res, "varname", getValue(a)); + cJSON_AddItemToObject(res, "arg", e); + cJSON_AddItemToObject(res, "statements", s); + r = res; +} + + + + + +ex(r) ::= LPAR ex(a) RPAR . +{ + r = a; +} + +ex(r) ::= LSPAR RSPAR . +{ + cJSON *res = cJSON_CreateObject(); + cJSON_AddStringToObject(res, "type", "EMPTYLIST"); + r = res; +} + +ex(r) ::= LSPAR exlist(a) RSPAR . +{ + cJSON *res = cJSON_CreateObject(); + cJSON_AddStringToObject(res, "type", "LIST"); + cJSON_AddItemToObject(res, "elements", a); + r = res; +} + +exlist(r) ::= ex(a) . +{ + cJSON *elem = cJSON_CreateArray(); + cJSON_AddItemToArray(elem, a); + r = elem; +} + +exlist(r) ::= exlist(a) COMMA ex(b) . +{ + cJSON_AddItemToArray(a,b); + r = a; +} + + +ex(r) ::= NUMTOKEN (a). +{ + cJSON *res = cJSON_CreateObject(); + cJSON_AddStringToObject(res, "type", "NUMTOKEN"); + cJSON_AddStringToObject(res, "value", getValue(a)); + cJSON_AddStringToObject(res, "line", getLine(a)); + r = res; +} + + +ex(r) ::= STRTOKEN (a). +{ + cJSON *res = cJSON_CreateObject(); + cJSON_AddStringToObject(res, "type", "STRTOKEN"); + cJSON_AddStringToObject(res, "value", getValue(a)); + cJSON_AddStringToObject(res, "line", getLine(a)); + r = res; +} + + +ex(r) ::= IDENTIFIER(a) . +{ + cJSON *res = cJSON_CreateObject(); + cJSON_AddStringToObject(res, "type", "VARIABLE"); + cJSON_AddStringToObject(res, "name", getValue(a)); + cJSON_AddStringToObject(res, "line", getLine(a)); + r = res; +} + +ex(r) ::= TIMETOKEN(a) . +{ + cJSON *res = cJSON_CreateObject(); + cJSON_AddStringToObject(res, "type", "TIMETOKEN"); + cJSON_AddStringToObject(res, "value", getValue(a)); + cJSON_AddStringToObject(res, "line", getLine(a)); + r = res; +} + +ex(r) ::= NULLTOKEN(a) . +{ + cJSON *res = cJSON_CreateObject(); + cJSON_AddStringToObject(res, "type", "NULLTOKEN"); + r = res; +} + +ex(r) ::= LIST(a) . +{ + cJSON *res = cJSON_CreateObject(); + cJSON_AddStringToObject(res, "type", "LISTTYPE"); + cJSON_AddStringToObject(res, "value", getValue(a)); + cJSON_AddStringToObject(res, "line", getLine(a)); + r = res; +} + +ex(r) ::= NUMBER(a) . +{ + cJSON *res = cJSON_CreateObject(); + cJSON_AddStringToObject(res, "type", "NUMTYPE"); + cJSON_AddStringToObject(res, "name", getValue(a)); + cJSON_AddStringToObject(res, "line", getLine(a)); + r = res; +} + +ex(r) ::= NOW(a) . +{ + cJSON *res = cJSON_CreateObject(); + cJSON_AddStringToObject(res, "type", "NOW"); + r = res; +} + +ex(r) ::= IT(a) . +{ + cJSON *res = cJSON_CreateObject(); + cJSON_AddStringToObject(res, "type", "IT"); + r = res; +} + +ex(r) ::= TRUE(a) . +{ + cJSON *res = cJSON_CreateObject(); + cJSON_AddStringToObject(res, "type", "BOOL"); + cJSON_AddStringToObject(res, "value", "1"); + r = res; +} + +ex(r) ::= FALSE(a) . +{ + cJSON *res = cJSON_CreateObject(); + cJSON_AddStringToObject(res, "type", "BOOL"); + cJSON_AddStringToObject(res, "value", "0"); + r = res; +} + +of ::= . +of ::= OF . +is ::= . +is ::= IS . + +ex(r) ::= COS ex(a) . +{r = unary ("COS", a); } + +ex(r) ::= FIRST ex(a) . +{r = unary ("FIRST", a); } + +ex(r) ::= COUNT ex(a) . +{r = unary ("COUNT", a); } + +ex(r) ::= TIME of ex(a) . +{r = unary ("TIME", a); } + +ex(r) ::= NOT ex(a) . +{r = unary ("NOT", a); } + +ex(r) ::= SIN ex(a) . +{r = unary ("SIN", a); } + +ex(r) ::= LESS THAN ex(a) . +{r = unary ("LESS", a); } + +ex(r) ::= BEFORE ex(a) . +{r = unary ("BEFORE", a); } + +ex(r) ::= GREATER THAN ex(a) . +{r = unary ("GREATER", a); } + +ex(r) ::= AFTER ex(a) . +{r = unary ("AFTER", a); } + +ex(r) ::= LESS THAN OR EQUAL ex(a) . +{r = unary ("LESSEQUAL", a); } + +ex(r) ::= GREATER THAN OR EQUAL ex(a) . +{r = unary ("GREATEREQUAL", a); } + +ex(r) ::= WITHIN ex(a) TO ex(b). +{r = binary ("WITHIN", a, b); } + +ex(r) ::= BETWEEN ex(a) AND ex(b). +{r = binary ("BETWEEN", a, b); } + +ex(r) ::= ex(a) AMBERSAND ex(b) . +{r = binary ("AMBERSAND", a, b); } + +ex(r) ::= ex(a) AND ex(b) . +{r = binary ("AND", a, b); } + +ex(r) ::= ex(a) OR ex(b) . +{r = binary ("OR", a, b); } + +ex(r) ::= ex(a) WHERE ex(b) . +{r = binary ("WHERE", a, b); } + +ex(r) ::= ex(a) OCCURS ex(b) . +{r = binary ("OCCURS", a, b); } + +ex(r) ::= ex(a) IS ex(b) . +{r = binary ("IS", a, b); } + +ex(r) ::= ex(a) IS NOT ex(b) . +{r = binary ("ISNOT", a, b); } + +ex(r) ::= ex(a) PLUS ex(b) . +{r = binary ("PLUS", a, b); } + +ex(r) ::= ex(a) MINUS ex(b) . +{r = binary ("MINUS", a, b); } + +ex(r) ::= MINUS ex(a) . [UMINUS] +{r = unary ("UMINUS", a); } + +ex(r) ::= ex(a) TIMES ex(b) . +{r = binary ("TIMES", a, b); } + +ex(r) ::= ex(a) DIVIDE ex(b) . +{r = binary ("DIVIDE", a, b); } + +ex(r) ::= ex(a) POWER ex(b) . +{r = binary ("POWER", a, b); } + +ex(r) ::= ex(a) GT ex(b) . +{r = binary ("GT", a, b); } + +ex(r) ::= ex(a) LT ex(b) . +{r = binary ("LT", a, b); } + +ex(r) ::= ex(a) LSPAR ex(b) RSPAR . +{r = binary ("LISTACCESS", a, b); } + +ex(r) ::= ex(a) RANGE ex(b) . +{r = binary ("RANGE", a, b); } + + + + + + + \ No newline at end of file diff --git a/interpreter.py b/interpreter.py new file mode 100644 index 0000000..3e8a9d3 --- /dev/null +++ b/interpreter.py @@ -0,0 +1,222 @@ +from datetime import datetime +from collections import deque +from arden_types import StrType, NumType, DateType, ListType, NullType, BoolType, Condition +import math +import copy +class InterpreterError(Exception): + pass + +class Interpreter: + def __init__(self): + self.variables = {} + self.it_queue = deque() + + def interpret(self, node): + node_type = node["type"] + args = node.get('arg', []) + if node_type == "WHERE": + self.it_queue.append(self.interpret(args[0])) + evaluated_args = [self.interpret(arg) for arg in (args if isinstance(args, list) else [args])] + return getattr(self, node_type)(node, *evaluated_args) + + def STATEMENTBLOCK(self,node): + for stmt in node.get("statements"): + self.interpret(stmt) + + #Statements + def WRITE(self,node,a): + print(a) + + def TRACE(self,node,a): + print(f"LINE {node['line']}: {a}") + + def ASSIGN(self,node,a): + #self.variables.update({node.get("varname"): (self.variables.get(node.get("varname")[0],NullType()),a)}) + self.variables.update({node.get("varname"): copy.copy(a)}) + + def TIMEASSIGN(self,node,a): + #self.variables.update({node.get("varname"): (a,self.variables.get(node.get("varname"))[1])}) + value = self.variables[node.get("varname")] + value.time = a + self.variables.update({node.get("varname"): copy.copy(value)}) + + def LISTINDEXASSIGN(self,node,a,b): + value = self.variables[node.get("varname")] + return value.LISTINDEXASSIGN(a,b) + + def LISTINDEXTIMEASSIGN(self,node,a,b): + value = self.variables[node.get("varname")] + return value.LISTINDEXASSIGN(a,b) + + def IF(self,node,a): + if a: + self.interpret(node.get("statements")) + return + for elseif in node.get("elseif"): + if self.interpret(elseif): + return + else: + if node.get("else"): + self.interpret(node.get("else")) + + def ELSEIF(self,node,a): + if a: + self.interpret(node.get("statements")) + return True + return False + + def ELSE(self,node): + self.interpret(node.get("statements")) + + def FOR(self,node,a): + for x in a.value: + self.variables[node.get("varname")] = x + self.interpret(node.get("statements")) + del self.variables[node.get("varname")] + + #Types + def NUMTOKEN(self,node): + return NumType(node.get("value")) + + def STRTOKEN(self,node): + return StrType(node.get("value")) + + def TIMETOKEN(self,node): + try: + return DateType(datetime.strptime(node.get("value"), "%Y-%m-%dT%H:%M:%S")) + except ValueError: + return DateType(datetime.strptime(node.get("value"), "%Y-%m-%d")) + + def NULLTOKEN(self,node): + return NullType() + + def NOW(self,node): + return DateType(datetime.now()) + + def VARIABLE(self,node): + return self.variables.get(node.get("name")) + + def TIME(self,node,a): + return a.TIME() + + def LIST(self,node): + return ListType([self.interpret(node) for node in node["elements"]]) + + def BOOL(self,node): + return BoolType(True) if node.get("value") == "1" else BoolType(False) + + def NULLTYPE(self,node): + return NullType + + def NUMTYPE(self,node): + return NumType + + def LISTTYPE(self,node): + return ListType + + def TRUE(self,node): + return True + + def FALSE(self,node): + return False + + def IT(self,node): + if self.it_queue: + return self.it_queue[-1] + return NullType() + + def LISTACCESS(self,node,a,b): + return a.LISTACCESS(b) + + #Binary Operators + def AMBERSAND(self,node,a,b): + return a & b + + def PLUS(self,node,a,b): + return a + b + + def MINUS(self,node,a,b): + return a - b + + def TIMES(self,node,a,b): + return a * b + + def DIVIDE(self,node,a,b): + return a / b + + def POWER(self,node,a,b): + return a ** b + + def WHERE(self,node,a,b): + res = a.WHERE(b) + self.it_queue.pop() + return res + + def GT(self,node,a,b): + return a > b + + def LT(self,node,a,b): + return a < b + + def AND(self,node,a,b): + return a & b + + def OR(self,node,a,b): + return a | b + + def RANGE(self,node,a,b): + rangelist = [] + x = range(a.value,b.value+1) + for i in x: + rangelist.append(NumType(i)) + return ListType(rangelist) + + #Unary Operators + def UMINUS(self,node,a): + return -a + + def COS(self,node,a): + return NumType(math.cos(a)) + + def SIN(self,node,a): + return NumType(math.sin(a)) + + def IS(self,node,a,b): + return a.IS(b) + + def ISNOT(self,node,a,b): + return a.IS(b).NOT() + + def OCCURS(self,node,a,b): + return a.OCCURS(b) + + def NOT(self,a): + return ~a + + def FIRST(self,node,a): + return a.value[0] + + def COUNT(self,node, a): + return NumType(len(a.value)) + + #Conditions + def LESS(self,node,a): + return Condition(lambda x: x < a) + + def BEFORE(self,node,a): + return Condition(lambda x: x < a) + + def GREATER(self,node,a): + return Condition(lambda x: x > a) + + def AFTER(self,node,a): + return Condition(lambda x: x > a) + + def LESSEQUAL(self,node,a): + return Condition(lambda x: x <= a) + + def GREATEREQUAL(self,node,a): + return Condition(lambda x: x >= a) + + def WITHIN(self,node,a,b): + return Condition(lambda x: (a <= x) & (x <= b)) \ No newline at end of file diff --git a/parser.py b/parser.py new file mode 100644 index 0000000..62b3a7b --- /dev/null +++ b/parser.py @@ -0,0 +1,11 @@ +import subprocess +import json +class ParserError(Exception): + pass +class Parser: + def parse(self,tokens): + result = subprocess.run(['./parse.exe'], input=json.dumps(tokens, indent=4).encode('utf-8'),stdout=subprocess.PIPE) + ast = json.loads(result.stdout.decode('utf-8')) + if "error" in ast: + raise ParserError(f"{ast['message']}") + return json.loads(result.stdout.decode('utf-8')) \ No newline at end of file diff --git a/run.py b/run.py new file mode 100644 index 0000000..f9705fb --- /dev/null +++ b/run.py @@ -0,0 +1,21 @@ +import argparse +from tokenizer import Tokenizer +from parser import Parser +from interpreter import Interpreter +import json + +arg_parser = argparse.ArgumentParser(description="DSM") +arg_parser.add_argument("input_file", type=str, help="The input file to process") +args = arg_parser.parse_args() + +tokenizer = Tokenizer() +parser = Parser() +interpreter = Interpreter() +#try: +tokens = tokenizer.tokenize(args.input_file) +#print(json.dumps(tokens, indent=4)) +ast = parser.parse(tokens) +#print(json.dumps(ast, indent=4)) +interpreter.interpret(ast) +#except Exception as e: +# print(f"{type(e).__name__}: {e}") \ No newline at end of file diff --git a/tokenizer.py b/tokenizer.py new file mode 100644 index 0000000..5dffdea --- /dev/null +++ b/tokenizer.py @@ -0,0 +1,59 @@ +import re +import json +class TokenizerError(Exception): + pass +class Tokenizer: + def __init__(self): + self.reserved = [ + 'READ', 'WRITE', 'IF', 'THEN', 'ELSEIF', 'ELSE', 'ENDIF', 'FOR', + 'IN', 'DO', 'ENDDO', 'NOW', 'CURTIME', 'MINIMUM', 'MAXIMUM', + 'FIRST', 'LAST', 'SUM', 'AVERAGE', 'EARLIEST', 'LATEST', 'COS', 'SIN', 'TIME', 'OF', 'TRACE', 'TRUE', 'FALSE', 'IS', 'LIST', 'NUMBER', 'NOT', 'COUNT', + 'WHERE', 'IT', 'THEY', 'AND', 'OR', 'LESS', 'GREATER', 'THAN', 'TO', 'WITHIN', 'EQUAL', 'OCCURS', 'OCCURRED', 'AFTER', 'BEFORE' + ] + self.regex_patterns = { + "STRTOKEN": r'(".*?")', + "TIMETOKEN": r'\d{4}-\d{2}-\d{2}(T\d{2}:\d{2}:\d{2})?', + "COMMENT": r'//.*$', + "SEMICOLON": r';', + "COMMA": r',', + "ASSIGN": r':=', + "PLUS": r'\+', + "MINUS": r'\-', + "POWER": r'\*\*', + "TIMES": r'\*', + "DIVIDE": r'\/', + "LPAR": r'\(', + "RPAR": r'\)', + "LSPAR": r'\[', + "RSPAR": r'\]', + "AMBERSAND": r'&', + "NEQ": r'<>', + "LT": r'<', + "GT": r'>', + "LTEQ": r'<=', + "GTEQ": r'>=', + "EQ": r'=', + "RANGE": r'\.\.\.' + } + self.regex_patterns |= { + "NULLTOKEN": r'\bNULL\b' + } + self.regex_patterns |= {i: rf'\b{i}\b' for i in self.reserved} + self.regex_patterns |= { + "NUMTOKEN": r'\d+(\.\d*)?', + "IDENTIFIER": r'\w+' + } + self.combined_pattern = '|'.join(f'(?P<{name}>{pattern})' for name, pattern in self.regex_patterns.items()) + self.regex = re.compile(self.combined_pattern, re.IGNORECASE) + + def tokenize(self, input_file): + tokens = [] + with open(input_file, 'r') as file: + for i, line in enumerate(file): + for match in self.regex.finditer(line): + token_type = match.lastgroup + token_value = match.group(token_type) + if token_type == "STRTOKEN": + token_value = token_value.replace('"','') + tokens.append([str(i + 1), token_type, token_value]) + return tokens \ No newline at end of file