diff --git a/grammar_parser.meta b/grammar_parser.meta new file mode 100644 index 0000000..5d11111 --- /dev/null +++ b/grammar_parser.meta @@ -0,0 +1,495 @@ +// Utils + +println = (x) { + if (!x) { + print("\n"); + } else { + print(x, "\n", full: 1); + } +}; + +Object.subtype(name) { self.new(__name__: name) } + +// Input stream + +Stream = Object.subtype(#Stream); + +newStream(string) { + self = Stream.new( + content: string, + position: 0, + limit: len(string) + ); + print("Created new stream object: { position: ", self.position, ", limit: ", self.limit, ", !atEnd(): ", !self.atEnd(), " }\n"); + self; +} + +Stream.atEnd() { self.position >= self.limit } +Stream.peek() { !self.atEnd() && self.content[self.position] } +Stream.inc() { !self.atEnd() && { self.position = self.position + 1; } } + +Stream.next() { + !self.atEnd() && { + c = self.content[self.position]; + self.position = self.position + 1; + c; + } +} + +Stream.setLastBegin = () { self.lastBegin = self.position; }; + +// Context + +Context = Object.subtype(#Context); +Context.init() { self.variables = []; self; } +Context.declareVariable(var) { self.variables[var] = nil } + +// ----- Grammar Constructs ----- + +// String Literal + +StringLiteral = Object.subtype(#StringLiteral); + +StringLiteral.match(stream, context, actions) { + + n = len(self.string); + i = 0; + success = 1; + if (stream.atEnd()) { success = 0; } + startPosition = stream.position; + + while(i < n && success == 1) { + if (self.string[i] != stream.peek()) { + success = 0; + stream.position = startPosition; + + } else { + i = i + 1; + stream.inc(); + } + } + success; +} + +// Character Class + +CharacterClass = Object.subtype(#CharacterClass); + +CharacterClass.match(stream, context, actions) { + + classLength = len(self.value); + i = 0; + prevChar = nil; + success = 0; + + while (i < classLength && success == 0 && !stream.atEnd()) { + + // [a] case + if (prevChar == nil) { + // println("[a] case"); + prevChar = self.value[i]; + + if (stream.peek() == self.value[i]) { + success = 1; + } + + } else if (prevChar != nil && self.value[i] == ord('-')) { + + // [a-z] case + if (i+1 < classLength) { + // println("[a-z] case"); + rangeStart = charValue(prevChar); + rangeEnd = charValue(self.value[i+1]); + // print("Range Start: ", rangeStart, " | "); + // print("Range End: ", rangeEnd, "\n"); + if (charValue(stream.peek()) >= rangeStart + && charValue(stream.peek()) <= rangeEnd + ) { + success = 1; + } + prevChar = nil; + i = i + 1; + + // [a-] case + } else { + // println("[a-] case"); + if (stream.peek() == ord('-')) { + success = 1; + } + } + + // [ab] case + } else if (prevChar != nil && self.value[i] != ord('-')) { + // println("[ab] case"); + prevChar = self.value[i]; + if (stream.peek() == self.value[i]) { + success = 1; + } + } + // print("prevChar: ", prevChar, "\n"); + i = i + 1; + } + + if (success == 1) { + stream.inc(); + } + + success; +} + +// Dot + +Dot = Object.subtype(#Dot); + +Dot.match(stream, context, actions) { + if (!stream.atEnd()) { + stream.inc(); + 1; + } else { + 0; + } +} + +// Begin + +Begin = Object.subtype(#Begin); + +Begin.match(stream, context, actions) { + stream.setLastBegin(); + 1; +} + +// End + +End = Object.subtype(#End); + +End.match(stream, context, actions) { + context.input = stream.string[stream.lastBegin..stream.position]; + 1; +} + +// Optional (? postfix operator) + +Optional = Object.subtype(#Optional); + +Optional.match(stream, context, actions) { + self.expression.match(stream, context, actions); + 1; +} + +// Star + +Star = Object.subtype(#Star); + +Star.match(stream, context, actions) { + while (self.expression.match(stream, context, actions) == 1) {} + 1; +} + +// Plus + +Plus = Object.subtype(#Plus); + +Plus.match(stream, context, actions) { + if (self.expression.match(stream, context, actions) == 1) { + while (self.expression.match(stream, context, actions) == 1) {} + 1; + } else { + 0; + } +} + +// And + +And = Object.subtype(#And); + +And.match(stream, context, actions) { + position = stream.position; + + if (self.expression.match(stream, context, actions) == 1) { + stream.position = position; + 1; + } else { + 0; + } +} + +// Not + +Not = Object.subtype(#Not); + +Not.match(stream, context, actions) { + position = stream.position; + + if (self.expression.match(stream, context, actions) == 1) { + stream.position = position; + 0; + } else { + 1; + } +} + +// Sequence + +Sequence = Object.subtype(#Sequence); + +Sequence.match(stream, context, actions) { + i = 0; + match = 1; + while (i < self.length() && match == 1) { + match = self[i].match(stream, context, actions); + i = i + 1; + } + match; +} + +// Alternation + +Alternation = Object.subtype(#Alternation); + +Alternation.match(stream, context, actions) { + i = 0; + success = 0; + while (i < self.length() && success == 0) { + initialActionCount = actions.length(); + startingPosition = stream.position; + success = self[i].match(stream, context, actions); + + if (success == 0) { + while (actions.length() > initialActionCount) { + actions.pop(); + } + stream.position = startingPosition; + } + + i = i + 1; + print(i, " | ", success, " | ", self.length(), "\n"); + } + success; +} + +// Action + +Action = Object.subtype(#Action); + +Action.match(stream, context, actions) { + actions.push(self); + self.context = context; + 1; +} + +Action.execute() { + + // Declare all variables that a value is set to in the context + for (statement in self.parseTree.body) { + if (statement.__name__ == "SetVar") { + self.context.declareVariable(statement.name); + } + } + + // Evaluate the parse tree and return to outer context if needed + returnValue = eval(self.parseTree, env: self.context.variables); + if (self.context.outerContext != nil) { + self.context.outerContext.variables[self.context.returnValueName] = returnValue; + } + +} + +// Assignment + +Assignment = Object.subtype(#Assignment); + +Assignment.match(stream, context, actions) { + context.declareVariable(self.variableName); + innerContext = Context.new(outerContext: context, returnValueName: self.variableName).init(); + self.rule.match(stream, innerContext, actions); +} + +// ----- Grammar of Grammars ----- + +// Whitespace + +// - = ( space | comment )* +// space = ' ' | '\t' | end-of-line +// comment = '#' ( !end-of-line . )* end-of-line +// end-of-line = '\r\n' | '\n' | '\r' +// end-of-file = !. + +end_of_file = Not.new(expression: Dot.new()); +end_of_line = Alternation.new() + .push(StringLiteral.new(string: "\r\n")) + .push(StringLiteral.new(string: "\n")) + .push(StringLiteral.new(string: "\r")); + +comment = Sequence.new() + .push(StringLiteral.new(string: "#")) + .push(Star.new(expression: + Sequence.new() + .push(Not.new(expression: end_of_line)) + .push(Dot.new()) + )) + .push(end_of_line); + +space = Alternation.new() + .push(StringLiteral.new(string: " ")) + .push(StringLiteral.new(string: "\t")) + .push(end_of_line); + +ws = Star.new(expression: Alternation.new() + .push(space) + .push(comment) +); + + +// Literal Terminators + +Terminators = []; + +// BAR = '|' - +// NOT = '!' - +// QUERY = '?' - +// BEGIN = '<' - +// END = '>' - +// TILDE = '~' - +// RPERCENT = '%}' - + +Terminators.bar = Sequence.new().push(StringLiteral.new(string: "|")).push(ws); +Terminators.not = Sequence.new().push(StringLiteral.new(string: "!")).push(ws); +Terminators.query = Sequence.new().push(StringLiteral.new(string: "?")).push(ws); +Terminators.begin = Sequence.new().push(StringLiteral.new(string: "<")).push(ws); +Terminators.end = Sequence.new().push(StringLiteral.new(string: ">")).push(ws); +Terminators.tilde = Sequence.new().push(StringLiteral.new(string: "~")).push(ws); +Terminators.rpercent = Sequence.new().push(StringLiteral.new(string: "%}")).push(ws); + +// DIGIT = [0-9] +// LETTER = [A-Za-z_] +// ALNUM = LETTER | DIGIT +// NIL = "nil" !ALNUM - + +digit = CharacterClass.new(value: "0-9"); +letter = CharacterClass.new(value: "A-Za-z_"); +alnum = Alternation.new().push(letter).push(digit); +nil = Sequence.new().push(StringLiteral.new(string: "nil")).push(Not.new(expression: alnum)).push(ws); + +// SEMI = ";" - +// COMMA = "," - +// COLON = ":" - +// LPAREN = "(" - +// RPAREN = ")" - +// LBRAK = "[" - +// RBRAK = "]" - +// LBRACE = "{" - +// RBRACE = "}" - +// ASSIGN = "=" ![=] - +// AND = "&" ![&=] - +// PLUS = "+" ![+=] - +// STAR = "*" ![=] - +// DOT = "." ![.] - + +Terminators.semi = Sequence.new().push(StringLiteral.new(string: ";")).push(ws); +Terminators.comma = Sequence.new().push(StringLiteral.new(string: ",")).push(ws); +Terminators.colon = Sequence.new().push(StringLiteral.new(string: ":")).push(ws); +Terminators.lparen = Sequence.new().push(StringLiteral.new(string: "(")).push(ws); +Terminators.rparen = Sequence.new().push(StringLiteral.new(string: ")")).push(ws); +Terminators.lbrak = Sequence.new().push(StringLiteral.new(string: "[")).push(ws); +Terminators.rbrak = Sequence.new().push(StringLiteral.new(string: "]")).push(ws); +Terminators.lbrace = Sequence.new().push(StringLiteral.new(string: "{")).push(ws); +Terminators.rbrace = Sequence.new().push(StringLiteral.new(string: "}")).push(ws); + +Terminators.assign = Sequence.new() + .push(StringLiteral.new(string: "=")) + .push(Not.new(expression: CharacterClass.new(value: "="))) + .push(ws); +Terminators.and = Sequence.new() + .push(StringLiteral.new(string: "&")) + .push(Not.new(expression: CharacterClass.new(value: "&="))) + .push(ws); +Terminators.plus = Sequence.new() + .push(StringLiteral.new(string: "+")) + .push(Not.new(expression: CharacterClass.new(value: "+="))) + .push(ws); +Terminators.star = Sequence.new() + .push(StringLiteral.new(string: "*")) + .push(Not.new(expression: CharacterClass.new(value: "="))) + .push(ws); +Terminators.dot = Sequence.new() + .push(StringLiteral.new(string: ".")) + .push(Not.new(expression: CharacterClass.new(value: "."))) + .push(ws); + +// ----- Main ----- + +// stream = newStream(readfile("input.txt")); +stream = newStream("baaababbaabaaa"); +context = Context.new(outerContext: nil).init(); +actions = []; + +// s = StringLiteral.new(string: "ab"); +// print("Success : ", s.match(stream), "\n"); + +// c = CharacterClass.new(value: " \n\t"); +// print("Parsing Character: ", stream.peek(), " | CharacterClass [", c.value,"] : ", c.match(stream), "\n"); + +// d = Dot.new(); +// print("Parsing Character: ", stream.peek(), " | Dot : ", d.match(stream, context), "\n"); + +println("\n--- Action Test ---\n"); + +actionParseTree = `{ + innerVar = 151; +}; + +act = Action.new(parseTree: actionParseTree); + +assign = Assignment.new(variableName: #outerVar, rule: act); +assign.match(stream, context, actions); + +actionParseTree2 = `{ + x = 69; +}; + +act2 = Action.new(parseTree: actionParseTree2); +act2.match(stream, context, actions); + +for (action in actions) { + action.execute(); +} + +print("global variable named innerVar => ", innerVar, " should be nil\n"); +print("global variable named x => ", x, " should be nil\n"); + +print(context, "\n", full: 1); + + + + +print("\nMatching : ", Terminators.bar.match(stream, context, actions), "\n"); +println(stream); + +print("\nMatching : ", Star.new(expression: Alternation.new() + .push(StringLiteral.new(string: "a")) + .push(StringLiteral.new(string: "b")) + ).match(stream, context, actions), "\n"); +println(stream); + +// print("\nMatching : ", ws.match(stream, context, actions), "\n"); +// println(stream); + +// c = CharacterClass.new(value: "a"); +// u = Not.new(expression: c); +// println(u.match(stream, context)); +// println(stream); +// +// println(); +// println(); +// println(); +// +// gensokyo = [buses: 0, inhabitants: 1337]; +// +// reimu = [location: gensokyo]; +// marisa = [location: gensokyo]; +// +// println(marisa.location); +// reimu.location.inhabitants = 42; +// println(marisa.location); + diff --git a/minproto.leg b/minproto.leg index 8de41cd..16e0e45 100644 --- a/minproto.leg +++ b/minproto.leg @@ -85,9 +85,9 @@ typedef oop (*prim_t)(oop func, oop self, oop args, oop env); #endif #if PRIMCLOSURE -#define doProtos(_) _(Object) _(GetVar) _(SetVar) _(GetProp) _(SetProp) _(GetArray) _(SetArray) _(Call) _(Invoke) _(Binop) _(Unyop) _(Let) _(If) _(While) _(Block) _(For) _(ForIn) _(ForFromTo) _(Literal) +#define doProtos(_) _(Object) _(GetVar) _(SetVar) _(GetProp) _(SetProp) _(GetArray) _(SetArray) _(Call) _(Invoke) _(Binop) _(Unyop) _(Let) _(If) _(While) _(Block) _(For) _(ForIn) _(ForFromTo) _(Literal) _(Range) #else -#define doProtos(_) _(Object) _(GetVar) _(SetVar) _(GetProp) _(SetProp) _(GetArray) _(SetArray) _(Call) _(Invoke) _(Binop) _(Unyop) _(Let) _(If) _(While) _(Block) _(For) _(ForIn) _(ForFromTo) _(Literal) _(Lambda) _(Closure) +#define doProtos(_) _(Object) _(GetVar) _(SetVar) _(GetProp) _(SetProp) _(GetArray) _(SetArray) _(Call) _(Invoke) _(Binop) _(Unyop) _(Let) _(If) _(While) _(Block) _(For) _(ForIn) _(ForFromTo) _(Literal) _(Lambda) _(Closure) _(Range) #endif #define declareProto(NAME) oop p##NAME = 0; @@ -114,7 +114,7 @@ doTypes(makeProto); doProperties(declareProp); #undef declareProp -#define doSymbols(_) _(t) _(name) _(expr) _(function) _(arguments) _(object) _(index) _(key) _(value) _(self) _(method) _(parameters) _(body) _(lambda) _(environment) _(operation) _(full) _(condition) _(consequent) _(alternate) _(expression) _(identifier) _(initialise) _(update) _(first) _(last) _(fixed) _(keyvals) +#define doSymbols(_) _(t) _(name) _(expr) _(function) _(arguments) _(object) _(index) _(key) _(value) _(self) _(method) _(parameters) _(body) _(lambda) _(environment) _(operation) _(full) _(condition) _(consequent) _(alternate) _(expression) _(identifier) _(initialise) _(update) _(first) _(last) _(fixed) _(keyvals) _(start) _(end) _(env) #define declareSym(NAME) oop sym_##NAME = 0; doSymbols(declareSym); @@ -1123,6 +1123,17 @@ oop GetArray_eval(oop exp, oop env) default: fatal("[]: %s is not indexable", storeString(obj, 0)); } } + if (getType(ind) == Object) { + switch (getType(obj)) { + case String: { + int start = integerValue(eval(Object_get(ind, sym_start), env), "[..]"); + int end = integerValue(eval(Object_get(ind, sym_end ), env), "[..]"); + oop slice = newStringLen(String_aref(obj, start), end - start); + return slice; + } + default: fatal("[]: %s is not range - indexable", storeString(obj, 0)); + } + } if (!is(Object, obj)) fatal("[]: %s is not an object", storeString(obj, 0)); return Object_getLocal(obj, ind); } @@ -1172,6 +1183,25 @@ void SetArray_codeOn(oop exp, oop str, oop env) codeOn(str, Object_get(exp, sym_value), 0); } +oop newRange(oop start, oop end) { + oop o = new(pRange); + Object_put(o, sym_start, start); + Object_put(o, sym_end, end); + return o; +} + +oop Range_eval(oop exp, oop env) +{ + return exp; +} + +void Range_codeOn(oop exp, oop str, oop env) +{ + codeOn(str, Object_get(exp, sym_start), 0); + String_appendAll(str, ".."); + codeOn(str, Object_get(exp, sym_end), 0); +} + oop newCall(oop function, oop arguments) { oop o = new(pCall); @@ -1977,10 +2007,13 @@ sum = l:prod ( PLUS r:prod { l = newBinop(opAdd, l, r) } | MINUS r:prod { l = newBinop(opSub, l, r) } )* { $$ = l } -prod = l:prefix ( STAR r:prefix { l = newBinop(opMul, l, r) } - | SLASH r:prefix { l = newBinop(opDiv, l, r) } - | PCENT r:prefix { l = newBinop(opMod, l, r) } - )* { $$ = l } +prod = l:range ( STAR r:range { l = newBinop(opMul, l, r) } + | SLASH r:range { l = newBinop(opDiv, l, r) } + | PCENT r:range { l = newBinop(opMod, l, r) } + ) * { $$ = l } + +range = i1:prefix ( DOTDOT i2:prefix { i1 = newRange(i1, i2) } + ) ? { $$ = i1 } prefix = PLING p:prefix { $$ = newUnyop(opNot, p) } | MINUS p:prefix { $$ = newUnyop(opNeg, p) } @@ -2035,8 +2068,7 @@ number = "-" u:unsign { $$ = neg(u) } | "+" n:number { $$ = u } | u:unsign { $$ = u } -unsign = < DIGIT+ '.' DIGIT* EXP? > - { $$ = newFloat(strtod(yytext, 0)) } - | < DIGIT* '.' DIGIT+ EXP? > - { $$ = newFloat(strtod(yytext, 0)) } +unsign = < DIGIT* '.' DIGIT+ EXP? > - { $$ = newFloat(strtod(yytext, 0)) } | "0" [bB] < BIGIT+ > - { $$ = newInteger(strtol(yytext, 0, 2)) } | "0" [xX] < HIGIT+ > - { $$ = newInteger(strtol(yytext, 0, 16)) } | "0" < OIGIT* > - { $$ = newInteger(strtol(yytext, 0, 8)) } @@ -2075,40 +2107,41 @@ FROM = "from" !ALNUM - TO = "to" !ALNUM - LET = "let" !ALNUM - -BQUOTE = "`" - -COMMAT = "@" - -HASH = "#" - -SEMI = ";" - -ASSIGN = "=" ![=] - -COMMA = "," - -COLON = ":" - -LPAREN = "(" - -RPAREN = ")" - -LBRAK = "[" - -RBRAK = "]" - -LBRACE = "{" - -RBRACE = "}" - -BARBAR = "||" ![=] - -ANDAND = "&&" ![=] - -OR = "|" ![|=] - -XOR = "^" ![=] - -AND = "&" ![&=] - -EQ = "==" - -NOTEQ = "!=" - -LESS = "<" ![<=] - -LESSEQ = "<=" - -GRTREQ = ">=" - -GRTR = ">" ![=] - -SHL = "<<" ![=] - -SHR = ">>" ![=] - -PLUS = "+" ![+=] - -MINUS = "-" ![-=] - -STAR = "*" ![=] - -SLASH = "/" ![/=] - -PCENT = "%" ![*=] - -DOT = "." - -PLING = "!" ![=] - -TILDE = "~" - +BQUOTE = "`" - +COMMAT = "@" - +HASH = "#" - +SEMI = ";" - +ASSIGN = "=" ![=] - +COMMA = "," - +COLON = ":" - +LPAREN = "(" - +RPAREN = ")" - +LBRAK = "[" - +RBRAK = "]" - +LBRACE = "{" - +RBRACE = "}" - +BARBAR = "||" ![=] - +ANDAND = "&&" ![=] - +OR = "|" ![|=] - +XOR = "^" ![=] - +AND = "&" ![&=] - +EQ = "==" - +NOTEQ = "!=" - +LESS = "<" ![<=] - +LESSEQ = "<=" - +GRTREQ = ">=" - +GRTR = ">" ![=] - +SHL = "<<" ![=] - +SHR = ">>" ![=] - +PLUS = "+" ![+=] - +MINUS = "-" ![-=] - +STAR = "*" ![=] - +SLASH = "/" ![/=] - +PCENT = "%" ![*=] - +DOT = "." ![.] - +DOTDOT = ".." - +PLING = "!" ![=] - +TILDE = "~" - %%; @@ -2342,6 +2375,11 @@ oop prim_eval(oop func, oop self, oop args, oop env) int argc = _get(args, Object,isize); oop *indexed = _get(args, Object,indexed); oop result = nil; + + if (nil != Object_getLocal(args, sym_env)) { + env = Object_getLocal(args, sym_env); + } + for (int i = 0; i < argc; ++i) result = eval(indexed[i], env); return result; }