From 090142c69c05030b43b60dd32b8a52888378fc14 Mon Sep 17 00:00:00 2001 From: MaximeBarniaudy Date: Mon, 27 May 2024 09:43:23 +0900 Subject: [PATCH] Make grammar_parser.meta use the entire grammar from minproto.leg --- grammar_parser.meta | 70 +++++++++--- minproto.leg | 46 ++++++++ rawMetaGrammar.leg | 8 +- rawminproto.leg | 255 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 364 insertions(+), 15 deletions(-) create mode 100644 rawminproto.leg diff --git a/grammar_parser.meta b/grammar_parser.meta index 45b33f0..36d3213 100644 --- a/grammar_parser.meta +++ b/grammar_parser.meta @@ -219,7 +219,7 @@ CharacterClass.match(stream, context, actions) { // [a-] case } else { // println("[a-] case"); - if (stream.peek() == ord('-')) { + if (stream.peek() == '-') { success = 1; } } @@ -402,7 +402,7 @@ Action.execute(context) { } // Evaluate the parse tree and return to outer context if needed - returnValue = eval(self.parseTree, env: context.variables); + let returnValue = eval(self.parseTree, env: context.variables); if (context.outerContext != nil) { context.outerContext.variables[context.returnValueName] = returnValue; } @@ -467,7 +467,10 @@ metaStatement = Alternation.new() ) .push(Sequence.new() .push(Assignment.new(name: #e, rule: RuleCall.new(name: #metaExpression))) - .push(RuleCall.new(name: #semi)) + .push(Alternation.new() + .push(RuleCall.new(name: #semi)) + .push(And.new(expression: RuleCall.new(name: #rbrace))) + ) .push(Action.new(parseTree: `{ e; })) ); @@ -568,6 +571,7 @@ mklist = Action.new(parseTree: `{ Object.new(); }); metaPrimary = Alternation.new() .push(RuleCall.new(name: #nil)) + .push(RuleCall.new(name: #number)) .push(RuleCall.new(name: #metaVar)) .push(RuleCall.new(name: #metaSubExpr)); @@ -590,6 +594,29 @@ block = Sequence.new() .push(RuleCall.new(name: #rbrace)) .push(Action.new(parseTree: `{ Block.new(body: b); })); +number = Alternation.new() + .push(Sequence.new() + .push(StringLiteral.new(string: "-")) + .push(Assignment.new(name: #n, rule: RuleCall.new(name: #unsign))) + .push(Action.new(parseTree: `{ Unyop.new(operation: __opNeg).push(n) })) + ) + .push(Sequence.new() + .push(StringLiteral.new(string: "+")) + .push(Assignment.new(name: #n, rule: RuleCall.new(name: #number))) + .push(Action.new(parseTree: `{ n })) + ) + .push(Sequence.new() + .push(Assignment.new(name: #n, rule: RuleCall.new(name: #unsign))) + .push(Action.new(parseTree: `{ n })) + ); + +unsign = Sequence.new() + .push(Begin.new()) + .push(Plus.new(expression: RuleCall.new(name: #digit))) + .push(End.new()) + .push(RuleCall.new(name: #ws)) + .push(Action.new(parseTree: `{ yytext.asInteger(10); })); + metaVar = Sequence.new() .push(Assignment.new(name: #i, rule: RuleCall.new(name: #metaId))) .push(Action.new(parseTree: `{ GetVar.new(name: i); })); @@ -668,7 +695,7 @@ grammar = Sequence.new() .push(RuleCall.new(name: #ws)) .push(Plus.new(expression: Sequence.new() .push(Assignment.new(name: #d, rule: RuleCall.new(name: #definition))) - .push(Action.new(parseTree: `{ set(d.name, d.expression); })) + .push(Action.new(parseTree: `{ set(d.name, d.expression); print("Parsed rule ", d.name, "\n"); })) )) .push(RuleCall.new(name: #end_of_file)); @@ -823,14 +850,14 @@ literal = Alternation.new() .push(Action.new(parseTree: `{ StringLiteral.new(string: yytext); })) ) .push(Sequence.new() - .push(CharacterClass.new(value: '\"')) + .push(CharacterClass.new(value: "\"")) .push(Begin.new()) .push(Star.new(expression: Sequence.new() - .push(Not.new(expression: CharacterClass.new(value: '\"'))) + .push(Not.new(expression: CharacterClass.new(value: "\""))) .push(RuleCall.new(name: #char)) )) .push(End.new()) - .push(CharacterClass.new(value: '\"')) + .push(CharacterClass.new(value: "\"")) .push(RuleCall.new(name: #ws)) .push(Action.new(parseTree: `{ StringLiteral.new(string: yytext); })) ); @@ -936,24 +963,39 @@ ws = Star.new(expression: Alternation.new() with(#reading); -stream = newStream(readfile("rawMetaGrammar.leg")); + +stream = newStream(readfile("rawminproto.leg")); context = Context.new(outerContext: nil).init(); actions = []; -print("Matching : ", grammar.match(stream, context, actions), "\n"); +grammar.match(stream, context, actions); -// Execute all actions after all matching -// Open the namespace where rules will be declared with(#metaLanguage); - for (actionAndContext in actions) { actionAndContext.action.execute(actionAndContext.context); } - println("\n--------- META ---------\n\n"); println(__namespaces__.metaLanguage); without(#metaLanguage); +//stream = newStream(readfile("rawMetaGrammar.leg")); +//context = Context.new(outerContext: nil).init(); +//actions = []; +// +//print("Matching : ", grammar.match(stream, context, actions), "\n"); +// +//// Execute all actions after all matching +//// Open the namespace where rules will be declared +//with(#metaLanguage); +// +//for (actionAndContext in actions) { +// actionAndContext.action.execute(actionAndContext.context); +//} +// +//println("\n--------- META ---------\n\n"); +//println(__namespaces__.metaLanguage); +//without(#metaLanguage); + without(#reading); with(#reading); @@ -984,7 +1026,7 @@ with(#metaLanguage); with(#peg); with(#reading); -stream2 = newStream(readfile("rawMetaGrammar.leg")); +stream2 = newStream(readfile("rawminproto.leg")); //stream2 = newStream("a = b:c::d { print(a[b].c); }"); context2 = Context.new(outerContext: nil).init(); actions2 = []; diff --git a/minproto.leg b/minproto.leg index f980578..db7d518 100644 --- a/minproto.leg +++ b/minproto.leg @@ -3957,6 +3957,22 @@ oop prim_Object_initialise(oop func, oop self, oop args, oop env) return self; } +oop prim_newBinop(oop func, oop self, oop args, oop env) +{ assert(is(Object, args)); + int argc = _get(args, Object,isize); + if (argc != 3) fatal("newBinop: Expected 3 arguments, got %d\n", argc); + oop *indexed = _get(args, Object,indexed); + return newBinop(integerValue(indexed[0], "prim_newBinop"), indexed[1], indexed[2]); +} + +oop prim_newApply(oop func, oop self, oop args, oop env) +{ assert(is(Object, args)); + int argc = _get(args, Object,isize); + if (argc != 2) fatal("newApply: Expected 2 arguments, got %d\n", argc); + oop *indexed = _get(args, Object,indexed); + return newApply(indexed[0], indexed[1]); +} + oop prim_Object_push(oop func, oop self, oop args, oop env) { assert(is(Object, args)); int argc = _get(args, Object,isize); assert(is(Object, self)); @@ -5239,6 +5255,20 @@ oop prim_match(oop func, oop self, oop args, oop env) #endif // PEGVM +oop prim_lvalue(oop func, oop self, oop args, oop env) +{ assert(is(Object, args)); + int argc = _get(args, Object,isize); + if (argc != 1) fatal("lvalue: one argument expected\n"); + return lvalue(_get(args, Object,indexed)[0]); +} + +oop prim_assign(oop func, oop self, oop args, oop env) +{ assert(is(Object, args)); + int argc = _get(args, Object,isize); + if (argc != 2) fatal("assign: 2 arguments expected\n"); + return assign(_get(args, Object,indexed)[0], _get(args, Object,indexed)[1]); +} + oop replFile(FILE *in) { int oldline = lineno; @@ -5364,6 +5394,18 @@ int main(int argc, char **argv) Object_put(pObject, prop_eval, newPrimitive(prim___eval__, newString("Object.__eval__"))); // inherited by all objects +#define stringify(x) #x + +#define declareOp(NAME, OP) _set(intern(stringify(__op##NAME)), Symbol,value, newInteger(op##NAME)); + doBinops(declareOp) +#undef declareOp + +#define declareOp(NAME, OP) _set(intern(stringify(__##NAME)), Symbol,value, newInteger(NAME)); + doUnyops(declareOp) +#undef declareOp + +#undef stringify + #if TYPECODES # define defineEvaluator(NAME) \ @@ -5410,6 +5452,10 @@ int main(int argc, char **argv) prim(__extern__ , prim_extern); prim(__match__ , prim_match); prim(intern , prim_intern); + prim(newBinop , prim_newBinop); + prim(newApply , prim_newApply); + prim(lvalue , prim_lvalue); + prim(assign , prim_assign); # undef prim diff --git a/rawMetaGrammar.leg b/rawMetaGrammar.leg index b923850..ceab63a 100644 --- a/rawMetaGrammar.leg +++ b/rawMetaGrammar.leg @@ -28,7 +28,7 @@ args = LPAREN a:mklist mklist = { Object.new(); } -primary = nil | var | subExpr +primary = nil | number | var | subExpr subExpr = LPAREN e:expression RPAREN { e; } @@ -38,6 +38,12 @@ block = LBRACE b:mklist nil = NIL { nil; } +number = "-" n:unsign { Unyop.new(operation: __opNeg).push(n) } + | "+" n:number { n } + | n:unsign { n } + +unsign = < DIGIT+ > - { yytext.asInteger(10); } + var = i:id { GetVar.new(name: i); } id = < LETTER ALNUM* > - { intern(yytext); } diff --git a/rawminproto.leg b/rawminproto.leg new file mode 100644 index 0000000..e79c430 --- /dev/null +++ b/rawminproto.leg @@ -0,0 +1,255 @@ +start = - ( s:stmt # { yysval = s } + | !. # { yysval = 0 } + | < (!EOL .)* > # { fatal("syntax error near: %s", yytext) } + ) + +stmt = LET l:mklet k:id ASSIGN v:expr { l.keyvals.push(k); l.keyvals.push(v) } + ( COMMA k:id ASSIGN v:expr { l.keyvals.push(k); l.keyvals.push(v) } + )* SEMI { l } + | WHILE LPAREN c:expr RPAREN s:stmt { While.new(condition: c, body: s) } + | IF LPAREN c:expr RPAREN s:stmt + ( ELSE t:stmt { If.new(condition: c, consequent: s, alternate: t ) } + | { If.new(condition: c, consequent: s, alternate: nil) } + ) + | CONT EOS { Continue.new() } + | BREAK e:expr EOS { Break.new(value: e) } + | BREAK EOS { Break.new(value: nil) } + | RETURN e:expr EOS { Return.new(value: e) } + | RETURN EOS { Return.new(value: nil) } + | FOR LPAREN i:id IN e:expr RPAREN + s:stmt { ForIn.new(identifier: i, expression: e, body: s) } + | FOR LPAREN i:id FROM a:expr + TO b:expr RPAREN s:stmt { ForFromTo.new(identifier: i, first: a, last: b, body: s) } + | FOR LPAREN i:expr SEMI c:expr SEMI + u:expr RPAREN s:stmt { For.new(initialise: i, condition: c, update: u, body: s) } + | i:id p:params b:block { SetVar.new(name: i, value: Lambda.new(parameters: p, body: b)) } + | v:proto DOT i:id p:params b:block { SetProp.new(object: v, key: i, value: Lambda.new(parameters: p, body: b)) } + | v:proto CCOLON i:id p:params b:block { SetProp.new(object: v, key: i, value: Lambda.new(parameters: p, body: b)) } + | b:block { Block.new(body: b) } + | e:expr EOS { e } + +mklet = { Let.new() } + +proto = v:var ( DOT j:id !LPAREN { v = GetProp.new(object: v, key: j) } + )* { v } + +EOS = SEMI+ | &RBRACE | &ELSE + +expr = i:id ASSIGN e:expr { SetVar.new(name: i, value: e) } + | l:logor ( ASSIGN r:expr { l = assign(l, r) } + | PLUSEQ r:expr { l = newBinop(__opPreAdd, lvalue(l), r) } + | MINUSEQ r:expr { l = newBinop(__opPreSub, lvalue(l), r) } + | STAREQ r:expr { l = newBinop(__opPreMul, lvalue(l), r) } + | SLASHEQ r:expr { l = newBinop(__opPreDiv, lvalue(l), r) } + | PCENTEQ r:expr { l = newBinop(__opPreMod, lvalue(l), r) } + | SHLEQ r:expr { l = newBinop(__opPreShl, lvalue(l), r) } + | SHREQ r:expr { l = newBinop(__opPreShr, lvalue(l), r) } + | ANDEQ r:expr { l = newBinop(__opPreAnd, lvalue(l), r) } + | XOREQ r:expr { l = newBinop(__opPreXor, lvalue(l), r) } + | OREQ r:expr { l = newBinop(__opPreOr, lvalue(l), r) } + )? { l } + +logor = l:logand ( BARBAR r:logand { l = newBinop(__opLogOr, l, r) } + )* { l } + +logand = l:bitor ( ANDAND r:bitor { l = newBinop(__opLogAnd, l, r) } + )* { l } + +bitor = l:bitxor ( OR r:bitxor { l = newBinop(__opBitOr, l, r) } + )* { l } + +bitxor = l:bitand ( XOR r:bitand { l = newBinop(__opBitXor, l, r) } + )* { l } + +bitand = l:eq ( AND r:eq { l = newBinop(__opBitAnd, l, r) } + )* { l } + +eq = l:ineq ( EQ r:ineq { l = newBinop(__opEq, l, r) } + | NOTEQ r:ineq { l = newBinop(__opNotEq, l, r) } + )* { l } + +ineq = l:shift ( LESS r:shift { l = newBinop(__opLess, l, r) } + | LESSEQ r:shift { l = newBinop(__opLessEq, l, r) } + | GRTREQ r:shift { l = newBinop(__opGrtrEq, l, r) } + | GRTR r:shift { l = newBinop(__opGrtr, l, r) } + )* { l } + +shift = l:sum ( SHL r:sum { l = newBinop(__opShl, l, r) } + | SHR r:sum { l = newBinop(__opShr, l, r) } + )* { l } + +sum = l:prod ( PLUS r:prod { l = newBinop(__opAdd, l, r) } + | MINUS r:prod { l = newBinop(__opSub, 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 = Range.new(start: i1, end: i2) } + ) ? { i1 } + +prefix = PPLUS p:prefix { newBinop(__opPreAdd, lvalue(p), 1) } + | MMINUS p:prefix { newBinop(__opPreSub, lvalue(p), 1) } + | PLING p:prefix { Unyop.new(operation: __opNot).push(p) } + | MINUS p:prefix { Unyop.new(operation: __opNeg).push(p) } + | TILDE p:prefix { Unyop.new(operation: __opCom).push(p) } + | BQUOTE s:stmt { Unyop.new(operation: __opQuasiquote).push(s) } + | COMMAT e:expr { Unyop.new(operation: __opUnquote).push(e) } + | postfix + +postfix = p:primary + ( LBRAK e:expr RBRAK { p = GetArray.new(object: p, index: e) } + | DOT i:id ( a:args !LBRACE { p = Invoke.new(self: p, method: i, arguments: a) } + | { p = GetProp.new(object: p, key: i) } + ) + | a:args !LBRACE { p = newApply(p, a) } + | CCOLON i:id { p = GetProp.new(object: p, key: i) } + )* + ( PPLUS { p = newBinop(__opPostAdd, lvalue(p), 1) } + | MMINUS { p = newBinop(__opPostAdd, lvalue(p), -1) } + )? { p } + +args = LPAREN a:mkobj + ( RPAREN + | ( k:id COLON e:expr { a[k] = e } + | e:expr { a.push(e) } + ) + ( COMMA ( k:id COLON e:expr { a[k] = e } + | e:expr { a.push(e) } + ) )* RPAREN ) { a } + +params = LPAREN p:mkobj + ( RPAREN + | i:id ( COLON e:expr { p[i] = e } + | { p.push(i) } + ) + ( COMMA i:id ( COLON e:expr { p[i] = e } + | { p.push(i) } + ) + )* RPAREN ) { p } + +mkobj = { Object.new() } + +primary = nil | number | string | symbol | var | lambda | subexpr | literal + +lambda = p:params b:block { Lambda.new(parameters: p, body: b) } + +subexpr = LPAREN e:expr RPAREN { e } + | b:block { Block.new(body: b) } + +literal = LBRAK o:mkobj + ( RBRAK + | ( ( i:id COLON e:expr { o[i] = e } + | e:expr { o.push(e) } + ) ( COMMA ( i:id COLON e:expr { o[i] = e } + | e:expr { o.push(e) } + ) )* )? RBRAK ) { Literal.new(object: o) } + +block = LBRACE b:mkobj + ( e:stmt { b.push(e) } + )* RBRACE { Block.new(body: b) } + +nil = NIL { nil } + +number = "-" n:unsign { Unyop.new(operation: __opNeg).push(n) } + | "+" n:number { n } + | n:unsign { n } + +unsign = < DIGIT* '.' DIGIT+ EXP? > - { yytext.asFloat() } + | "0" [bB] < BIGIT+ > - { yytext.asInteger(2) } + | "0" [xX] < HIGIT+ > - { yytext.asInteger(16) } + | "0" < OIGIT* > - { yytext.asInteger(8) } + | < DIGIT+ > - { yytext.asInteger() } + +string = '"' < ( !'"' char )* > '"' - { yytext.unescaped() } + | "'" < ( !"'" char )* > "'" - { yytext.unescaped() } + +char = "\\" ( ["'\\abfnrtv] + | [xX] HIGIT* + | [0-7][0-7]?[0-7]? + ) + | . + +symbol = HASH i:id { i } + +var = i:id { GetVar.new(name: i) } + +id = < LETTER ALNUM* > - { intern(yytext) } + +BIGIT = [0-1] +OIGIT = [0-7] +DIGIT = [0-9] +HIGIT = [0-9A-Fa-f] +LETTER = [A-Za-z_] +ALNUM = LETTER | DIGIT +SIGN = [-+] +EXP = [eE] SIGN DIGIT+ + +- = SPACE* + +SPACE = [ \t] | EOL | '//' (!EOL .)* +EOL = [\n\r] # { ++lineno } + +NIL = "nil" !ALNUM - +WHILE = "while" !ALNUM - +IF = "if" !ALNUM - +ELSE = "else" !ALNUM - +FOR = "for" !ALNUM - +IN = "in" !ALNUM - +FROM = "from" !ALNUM - +TO = "to" !ALNUM - +LET = "let" !ALNUM - +CONT = "continue" !ALNUM - +BREAK = "break" !ALNUM - +RETURN = "return" !ALNUM - + +BQUOTE = "`" - +COMMAT = "@" - +HASH = "#" - +SEMI = ";" - +ASSIGN = "=" ![=] - +COMMA = "," - +COLON = ":" ![:] - +CCOLON = "::" - +LPAREN = "(" - +RPAREN = ")" - +LBRAK = "[" - +RBRAK = "]" - +LBRACE = "{" - +RBRACE = "}" - +BARBAR = "||" ![=] - +ANDAND = "&&" ![=] - +OR = "|" ![|=] - +OREQ = "|=" - +XOR = "^" ![=] - +XOREQ = "^=" - +AND = "&" ![&=] - +ANDEQ = "&=" - +EQ = "==" - +NOTEQ = "!=" - +LESS = "<" ![<=] - +LESSEQ = "<=" - +GRTREQ = ">=" - +GRTR = ">" ![=] - +SHL = "<<" ![=] - +SHLEQ = "<<=" - +SHR = ">>" ![=] - +SHREQ = ">>=" - +PLUS = "+" ![+=] - +PLUSEQ = "+=" - +PPLUS = "++" - +MINUS = "-" ![-=] - +MINUSEQ = "-=" - +MMINUS = "--" - +STAR = "*" ![=] - +STAREQ = "*=" - +SLASH = "/" ![/=] - +SLASHEQ = "/=" - +PCENT = "%" ![=] - +PCENTEQ = "%=" - +DOT = "." ![.] - +DOTDOT = ".." - +PLING = "!" ![=] - +TILDE = "~" -