// 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);