7 Incheckningar

3 ändrade filer med 1050 tillägg och 17 borttagningar
Delad Vy
  1. +924
    -0
      grammar_parser.meta
  2. +94
    -17
      minproto.leg
  3. +32
    -0
      test.txt

+ 924
- 0
grammar_parser.meta Visa fil

@ -0,0 +1,924 @@
// 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) {
let 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() && {
let 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) {
let found = 0;
for (key in self.variables.keys()) {
if (key == var) {
found = 1;
}
}
if (found == 0) {
self.variables[var] = nil;
}
}
// ----- Grammar Constructs -----
// String Literal
StringLiteral = Object.subtype(#StringLiteral);
StringLiteral.match(stream, context, rules, actions) {
let n = len(self.string);
let i = 0;
let 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, rules, actions) {
let classLength = len(self.value);
let i = 0;
let prevChar = nil;
let 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 = prevChar;
rangeEnd = self.value[i+1];
// print("Range Start: ", rangeStart, " | ");
// print("Range End: ", rangeEnd, "\n");
if (stream.peek() >= rangeStart
&& 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, rules, actions) {
if (!stream.atEnd()) {
stream.inc();
1;
} else {
0;
}
}
// Begin
Begin = Object.subtype(#Begin);
Begin.match(stream, context, rules, actions) {
stream.setLastBegin();
1;
}
// End
End = Object.subtype(#End);
End.match(stream, context, rules, actions) {
context.variables.yytext = stream.content[stream.lastBegin..stream.position];
1;
}
// Optional (? postfix operator)
Optional = Object.subtype(#Optional);
Optional.match(stream, context, rules, actions) {
let initialActionCount = actions.length();
let startingPosition = stream.position;
let success = self.expression.match(stream, context, rules, actions);
if (success == 0) {
while (actions.length() > initialActionCount) {
actions.pop();
}
stream.position = startingPosition;
}
1;
}
// Star
Star = Object.subtype(#Star);
Star.match(stream, context, rules, actions) {
while (self.expression.match(stream, context, rules, actions) == 1) {}
1;
}
// Plus
Plus = Object.subtype(#Plus);
Plus.match(stream, context, rules, actions) {
if (self.expression.match(stream, context, rules, actions) == 1) {
while (self.expression.match(stream, context, rules, actions) == 1) {}
1;
} else {
0;
}
}
// And
And = Object.subtype(#And);
And.match(stream, context, rules, actions) {
let position = stream.position;
if (self.expression.match(stream, context, rules, actions) == 1) {
stream.position = position;
1;
} else {
0;
}
}
// Not
Not = Object.subtype(#Not);
Not.match(stream, context, rules, actions) {
let position = stream.position;
if (self.expression.match(stream, context, rules, actions) == 1) {
stream.position = position;
0;
} else {
1;
}
}
// Sequence
Sequence = Object.subtype(#Sequence);
Sequence.match(stream, context, rules, actions) {
let i = 0;
let match = 1;
while (i < self.length() && match == 1) {
match = self[i].match(stream, context, rules, actions);
i = i + 1;
}
match;
}
// Alternation
Alternation = Object.subtype(#Alternation);
Alternation.match(stream, context, rules, actions) {
let i = 0;
let success = 0;
while (i < self.length() && success == 0) {
let initialActionCount = actions.length();
let startingPosition = stream.position;
success = self[i].match(stream, context, rules, actions);
if (success == 0) {
while (actions.length() > initialActionCount) {
actions.pop();
}
stream.position = startingPosition;
}
i = i + 1;
}
success;
}
// Action
Action = Object.subtype(#Action);
Action.match(stream, context, rules, actions) {
actions.push([action: self, context: context]);
1;
}
Action.execute(context) {
// Declare all variables that a value is set to in the context
for (statement in self.parseTree.body) {
if (statement.__name__ == "SetVar") {
context.declareVariable(statement.name);
}
}
// Evaluate the parse tree and return to outer context if needed
returnValue = eval(self.parseTree, env: context.variables);
if (context.outerContext != nil) {
context.outerContext.variables[context.returnValueName] = returnValue;
}
}
// Assignment
Assignment = Object.subtype(#Assignment);
Assignment.match(stream, context, rules, actions) {
context.declareVariable(self.name);
innerContext = Context.new(outerContext: context, returnValueName: self.name).init();
self.rule.match(stream, innerContext, rules, actions);
}
// RuleCall
RuleCall = Object.subtype(#RuleCall);
RuleCall.match(stream, context, rules, actions) {
rules[self.name].match(stream, context, rules, actions);
}
// ----- Grammar of Grammars -----
rules = [];
// grammar = - g:mklist
// ( d:definition { g.push(d); }
// ) + end-of-file { print(g, full: Object.new()); }
rules.grammar = Sequence.new()
.push(RuleCall.new(name: #ws))
.push(Assignment.new(name: #g, rule: RuleCall.new(name: #mklist)))
.push(Plus.new(expression: Sequence.new()
.push(Assignment.new(name: #d, rule: RuleCall.new(name: #definition)))
.push(Action.new(parseTree: `{ g[d.name] = d.expression; }))
))
.push(RuleCall.new(name: #end_of_file))
.push(Action.new(parseTree: `{ print(g, full: Object.new()); }));
Definition = Object.subtype(#Definition);
// definition = i:identifier ASSIGN e:expression SEMI? { newDefinition(i, e); }
rules.definition = Sequence.new()
.push(Assignment.new(name: #i, rule: RuleCall.new(name: #identifier)))
.push(RuleCall.new(name: #assign))
.push(Assignment.new(name: #e, rule: RuleCall.new(name: #expression)))
.push(Optional.new(expression: RuleCall.new(name: #semi)))
.push(Action.new(parseTree: `{ Definition.new(name: i, expression: e); }));
// expression = s1:sequence ( BAR s2:sequence { s1 = newAlternation(s1, s2); }
// ) * { s1; }
rules.expression = Sequence.new()
.push(Assignment.new(name: #s1, rule: RuleCall.new(name: #sequence)))
.push(Action.new(parseTree: `{ s1 = Alternation.new().push(s1); }))
.push(Star.new(expression: Sequence.new()
.push(RuleCall.new(name: #bar))
.push(Assignment.new(name: #s2, rule: RuleCall.new(name: #sequence)))
.push(Action.new(parseTree: `{ s1.push(s2); }))
))
.push(Action.new(parseTree: `{ s1; }));
// sequence = p:prefix
// ( q:prefix { p = newSequence(p, q); }
// ) * { p; }
rules.sequence = Sequence.new()
.push(Assignment.new(name: #p, rule: RuleCall.new(name: #prefix)))
.push(Action.new(parseTree: `{ p = Sequence.new().push(p); }))
.push(Star.new(expression: Sequence.new()
.push(Assignment.new(name: #q, rule: RuleCall.new(name: #prefix)))
.push(Action.new(parseTree: `{ p.push(q); }))
))
.push(Action.new(parseTree: `{ p; }));
// prefix = AND action
// |
// ( AND s:suffix { newAnd(s); }
// | NOT s:suffix { newNot(s); }
// | s:suffix { s; }
// )
rules.prefix = Alternation.new()
.push(Sequence.new()
.push(RuleCall.new(name: #and))
.push(RuleCall.new(name: #action))
)
.push(Alternation.new()
.push(Sequence.new()
.push(RuleCall.new(name: #and))
.push(Assignment.new(name: #s, rule: RuleCall.new(name: #suffix)))
.push(Action.new(parseTree: `{ And.new(expression: s); }))
)
.push(Sequence.new()
.push(RuleCall.new(name: #not))
.push(Assignment.new(name: #s, rule: RuleCall.new(name: #suffix)))
.push(Action.new(parseTree: `{ Not.new(expression: s); }))
)
.push(Sequence.new()
.push(Assignment.new(name: #s, rule: RuleCall.new(name: #suffix)))
.push(Action.new(parseTree: `{ s; }))
)
);
// suffix = p:primary
// ( QUERY { p = newOptional(p); }
// | STAR { p = newStar(p); }
// | PLUS { p = newPlus(p); }
// ) ? { p; }
rules.suffix = Sequence.new()
.push(Assignment.new(name: #p, rule: RuleCall.new(name: #primary)))
.push(Optional.new(expression: Alternation.new()
.push(Sequence.new()
.push(RuleCall.new(name: #query))
.push(Action.new(parseTree: `{ p = Optional.new(expression: p); }))
)
.push(Sequence.new()
.push(RuleCall.new(name: #star))
.push(Action.new(parseTree: `{ p = Star.new(expression: p); }))
)
.push(Sequence.new()
.push(RuleCall.new(name: #plus))
.push(Action.new(parseTree: `{ p = Plus.new(expression: p); }))
)
))
.push(Action.new(parseTree: `{ p; }));
// primary = i1:identifier COLON i2:ruleCallIdent !ASSIGN { newAssignment(i1, i2); }
// | i:ruleCallIdent !ASSIGN { i; }
// | LPAREN e:expression RPAREN { e; }
// | l:literal { l; }
// | c:class { c; }
// | DOT { newDot(); }
// | a:action { a; }
// | BEGIN { newBegin(); }
// | END { newEnd(); }
rules.primary = Alternation.new()
.push(Sequence.new()
.push(Assignment.new(name: #i1, rule: RuleCall.new(name: #identifier)))
.push(RuleCall.new(name: #colon))
.push(Assignment.new(name: #i2, rule: RuleCall.new(name: #ruleCallIdent)))
.push(Not.new(expression: RuleCall.new(name: #assign)))
.push(Action.new(parseTree: `{ Assignment.new(name: i1, rule: i2); }))
)
.push(Sequence.new()
.push(Assignment.new(name: #i, rule: RuleCall.new(name: #ruleCallIdent)))
.push(Not.new(expression: RuleCall.new(name: #assign)))
.push(Action.new(parseTree: `{ i; }))
)
.push(Sequence.new()
.push(RuleCall.new(name: #lparen))
.push(Assignment.new(name: #e, rule: RuleCall.new(name: #expression)))
.push(RuleCall.new(name: #rparen))
.push(Action.new(parseTree: `{ e; }))
)
.push(Sequence.new()
.push(Assignment.new(name: #l, rule: RuleCall.new(name: #literal)))
.push(Action.new(parseTree: `{ l; }))
)
.push(Sequence.new()
.push(Assignment.new(name: #c, rule: RuleCall.new(name: #class)))
.push(Action.new(parseTree: `{ c; }))
)
.push(Sequence.new()
.push(RuleCall.new(name: #dot))
.push(Action.new(parseTree: `{ Dot.new(); }))
)
.push(Sequence.new()
.push(Assignment.new(name: #a, rule: RuleCall.new(name: #action)))
.push(Action.new(parseTree: `{ a; }))
)
.push(Sequence.new()
.push(RuleCall.new(name: #begin))
.push(Action.new(parseTree: `{ Begin.new(); }))
)
.push(Sequence.new()
.push(RuleCall.new(name: #end))
.push(Action.new(parseTree: `{ End.new(); }))
);
// identifier = < [-a-zA-Z_][-a-zA-Z_0-9]* > - { newStringEscaped(yytext); }
rules.identifier = Sequence.new()
.push(Begin.new())
.push(CharacterClass.new(value: "-a-zA-Z_"))
.push(Star.new(expression: CharacterClass.new(value: "-a-zA-Z_0-9")))
.push(End.new())
.push(RuleCall.new(name: #ws))
.push(Action.new(parseTree: `{ yytext }));
// ruleCallIdent = < [-a-zA-Z_][-a-zA-Z_0-9]* > - { newIdentifier(yytext); }
rules.ruleCallIdent = Sequence.new()
.push(Begin.new())
.push(CharacterClass.new(value: "-a-zA-Z_"))
.push(Star.new(expression: CharacterClass.new(value: "-a-zA-Z_0-9")))
.push(End.new())
.push(RuleCall.new(name: #ws))
.push(Action.new(parseTree: `{ RuleCall.new(name: intern(yytext)); }));
// literal = ['] < ( !['] char )* > ['] - { newStringEscaped(yytext); }
// | ["] < ( !["] char )* > ["] - { newStringEscaped(yytext); }
rules.literal = Alternation.new()
.push(Sequence.new()
.push(CharacterClass.new(value: "\'"))
.push(Begin.new())
.push(Star.new(expression: Sequence.new()
.push(Not.new(expression: CharacterClass.new(value: "\'")))
.push(RuleCall.new(name: #char))
))
.push(End.new())
.push(CharacterClass.new(value: "\'"))
.push(RuleCall.new(name: #ws))
.push(Action.new(parseTree: `{ StringLiteral.new(value: yytext); }))
)
.push(Sequence.new()
.push(CharacterClass.new(value: '\"'))
.push(Begin.new())
.push(Star.new(expression: Sequence.new()
.push(Not.new(expression: CharacterClass.new(value: '\"')))
.push(RuleCall.new(name: #char))
))
.push(End.new())
.push(CharacterClass.new(value: '\"'))
.push(RuleCall.new(name: #ws))
.push(Action.new(parseTree: `{ StringLiteral.new(value: yytext); }))
);
// class = '[' < ( !']' range )* > ']' - { newCharacterClass(yytext); }
rules.class = Sequence.new()
.push(StringLiteral.new(string: "["))
.push(Begin.new())
.push(Star.new(expression: Sequence.new()
.push(Not.new(expression: StringLiteral.new(string: "]")))
.push(RuleCall.new(name: #range))
))
.push(End.new())
.push(StringLiteral.new(string: "]"))
.push(RuleCall.new(name: #ws))
.push(Action.new(parseTree: `{ CharacterClass.new(value: yytext); }));
// range = char '-' char | char
rules.range = Alternation.new()
.push(Sequence.new()
.push(RuleCall.new(name: #char))
.push(StringLiteral.new(string: "-"))
.push(RuleCall.new(name: #char))
)
.push(
RuleCall.new(name: #char)
);
// char = '\\' [abefnrtv'"\[\]\\]
// | '\\' [0-3][0-7][0-7]
// | '\\' [0-7][0-7]?
// | !'\\' .
rules.char = Alternation.new()
.push(Sequence.new()
.push(StringLiteral.new(string: "\\"))
.push(Alternation.new()
.push(CharacterClass.new(value: "abefnrtv\'[]\\"))
.push(CharacterClass.new(value: '\"')) // I hate this
)
)
.push(Sequence.new()
.push(StringLiteral.new(string: "\\"))
.push(CharacterClass.new(value: "0-3"))
.push(CharacterClass.new(value: "0-7"))
.push(CharacterClass.new(value: "0-7"))
)
.push(Sequence.new()
.push(StringLiteral.new(string: "\\"))
.push(CharacterClass.new(value: "0-7"))
.push(Optional.new(expression: CharacterClass.new(value: "0-7")))
)
.push(Sequence.new()
.push(Not.new(expression: StringLiteral.new(string: "\\")))
.push(Dot.new())
);
// action = m:metaBlock - { newAction(m); }
rules.action = Sequence.new()
.push(Assignment.new(name: #m, rule: RuleCall.new(name: #metaBlock)))
.push(RuleCall.new(name: #ws))
.push(Action.new(parseTree: `{ Action.new(parseTree: m); }));
// metaStatement = b:metaBlock { newBlock(b); }
// | e:metaExpression SEMI { e; }
rules.metaStatement = Alternation.new()
.push(Sequence.new()
.push(Assignment.new(name: #b, rule: RuleCall.new(name: #metaBlock)))
.push(Action.new(parseTree: `{ Block.new(b); }))
)
.push(Sequence.new()
.push(Assignment.new(name: #e, rule: RuleCall.new(name: #metaExpression)))
.push(RuleCall.new(name: #semi))
.push(Action.new(parseTree: `{ e; }))
);
// metaExpression = p:metaPrimary
// ( DOT i:metaId ASSIGN e:metaExpression # { $$ = newSetProp(p, i, e) }
// | LBRAK i:metaExpression RBRAK ASSIGN e:metaExpression # { $$ = newSetArray(p, i, e) }
// )
// | i:metaId ASSIGN e:metaExpression { newSetVar(i, e); }
// | pf:metaPostfix { pf; }
rules.metaExpression = Alternation.new(id: 1234)
.push(Sequence.new()
.push(Assignment.new(name: #p, rule: RuleCall.new(name: #metaPrimary)))
.push(Alternation.new()
.push(Sequence.new()
.push(RuleCall.new(name: #dot))
.push(Assignment.new(name: #i, rule: RuleCall.new(name: #metaId)))
.push(RuleCall.new(name: #assign))
.push(Assignment.new(name: #e, rule: RuleCall.new(name: #metaExpression)))
)
.push(Sequence.new()
.push(RuleCall.new(name: #lbrak))
.push(Assignment.new(name: #i, rule: RuleCall.new(name: #metaExpression)))
.push(RuleCall.new(name: #rbrak))
.push(RuleCall.new(name: #assign))
.push(Assignment.new(name: #e, rule: RuleCall.new(name: #metaExpression)))
.push(Action.new(parseTree: `{ SetArray.new(object: p, index: i, value: e); }))
)
)
)
.push(Sequence.new()
.push(Assignment.new(name: #i, rule: RuleCall.new(name: #metaId)))
.push(RuleCall.new(name: #assign))
.push(Assignment.new(name: #e, rule: RuleCall.new(name: #metaExpression)))
.push(Action.new(parseTree: `{ SetVar.new(name: i, expr: e); }))
)
.push(Sequence.new()
.push(Assignment.new(name: #pf, rule: RuleCall.new(name: #metaPostfix)))
.push(Action.new(parseTree: `{ pf; }))
);
// metaPostfix = p:metaPrimary
// ( DOT i:id a:args !ASSIGN !LBRACE { p = newInvoke(p, i, a) }
// | DOT i:id !ASSIGN { p = newGetProp(p, i) }
// | a:args !ASSIGN !LBRACE { p = newCall(p, a); }
// ) * { p; }
rules.metaPostfix = Sequence.new()
.push(Assignment.new(name: #p, rule: RuleCall.new(name: #metaPrimary)))
.push(Star.new(expression: Alternation.new()
.push(Sequence.new()
.push(RuleCall.new(name: #dot))
.push(Assignment.new(name: #i, rule: RuleCall.new(name: #metaId)))
.push(Assignment.new(name: #a, rule: RuleCall.new(name: #args)))
.push(Not.new(expression: RuleCall.new(name: #assign)))
.push(Not.new(expression: RuleCall.new(name: #lbrace)))
.push(Action.new(parseTree: `{ p = Invoke.new(self: p, method: i, arguments: a); }))
)
.push(Sequence.new()
.push(RuleCall.new(name: #dot))
.push(Assignment.new(name: #i, rule: RuleCall.new(name: #metaId)))
.push(Not.new(expression: RuleCall.new(name: #assign)))
.push(Action.new(parseTree: `{ p = GetProp.new(object: p, key: i); }))
)
.push(Sequence.new()
.push(Assignment.new(name: #a, rule: RuleCall.new(name: #args)))
.push(Not.new(expression: RuleCall.new(name: #assign)))
.push(Not.new(expression: RuleCall.new(name: #lbrace)))
.push(Action.new(parseTree: `{ p = Call.new(function: p, arguments: a); }))
// TODO: Voir si c'est toujours bon avec le newApply()
)
))
.push(Action.new(parseTree: `{ p; }));
// args = LPAREN a:mklist
// (
// ( k:metaId COLON e:metaExpression { Object_put(a, k, e); }
// | e:metaExpression { Object_push(a, e); }
// )
// ( COMMA
// ( k:metaId COLON e:metaExpression { Object_put(a, k, e); }
// | e:metaExpression { Object_push(a, e); }
// )
// ) *
// ) ? RPAREN { a; }
rules.args = Sequence.new()
.push(RuleCall.new(name: #lparen))
.push(Assignment.new(name: #a, rule: RuleCall.new(name: #mklist)))
.push(Optional.new(expression: Sequence.new()
.push(Alternation.new()
.push(Sequence.new()
.push(Assignment.new(name: #k, rule: RuleCall.new(name: #metaId)))
.push(RuleCall.new(name: #colon))
.push(Assignment.new(name: #e, rule: RuleCall.new(name: #metaExpression)))
.push(Action.new(parseTree: `{ a[k] = e; }))
)
.push(Sequence.new()
.push(Assignment.new(name: #e, rule: RuleCall.new(name: #metaExpression)))
.push(Action.new(parseTree: `{ a.push(e); }))
)
)
.push(Star.new(expression: Sequence.new()
.push(RuleCall.new(name: #comma))
.push(Alternation.new()
.push(Sequence.new()
.push(Assignment.new(name: #k, rule: RuleCall.new(name: #metaId)))
.push(RuleCall.new(name: #colon))
.push(Assignment.new(name: #e, rule: RuleCall.new(name: #metaExpression)))
.push(Action.new(parseTree: `{ a[k] = e; }))
)
.push(Sequence.new()
.push(Assignment.new(name: #e, rule: RuleCall.new(name: #metaExpression)))
.push(Action.new(parseTree: `{ a.push(e); }))
)
)
))
))
.push(RuleCall.new(name: #rparen))
.push(Action.new(parseTree: `{ a; }));
// mklist = { new(pObject); }
// metaPrimary = nil | metaVar | metaSubExpr
// metaSubExpr = LPAREN e:metaExpression RPAREN { e; }
rules.mklist = Action.new(parseTree: `{ Object.new(); });
rules.metaPrimary = Alternation.new()
.push(RuleCall.new(name: #nil))
.push(RuleCall.new(name: #metaVar))
.push(RuleCall.new(name: #metaSubExpr));
rules.metaSubExpr = Sequence.new()
.push(RuleCall.new(name: #lparen))
.push(Assignment.new(name: #e, rule: RuleCall.new(name: #metaExpression)))
.push(RuleCall.new(name: #rparen))
.push(Action.new(parseTree = `{ e; }));
// metaBlock = LBRACE b:mklist
// ( e:metaStatement { b.push(e); }
// ) * RBRACE { b; }
rules.metaBlock = Sequence.new()
.push(RuleCall.new(name: #lbrace))
.push(Assignment.new(name: #b, rule: RuleCall.new(name: #mklist)))
.push(
Star.new(
expression: Sequence.new()
.push(Assignment.new(name: #e, rule: RuleCall.new(name: #metaStatement)))
.push(Action.new(parseTree: `{ b.push(e); }))
)
)
.push(RuleCall.new(name: #rbrace))
.push(Action.new(parseTree: `{ b; }));
// metaVar = i:metaId { newGetVar(i); }
// metaId = < LETTER ALNUM* > - { intern(yytext); }
rules.metaVar = Sequence.new()
.push(Assignment.new(name: #i, rule: RuleCall.new(name: #metaId)))
.push(Action.new(parseTree: `{ GetVar.new(name: i); }));
rules.metaId = Sequence.new()
.push(Begin.new())
.push(RuleCall.new(name: #letter))
.push(Star.new(expression: RuleCall.new(name: #alnum)))
.push(End.new())
.push(RuleCall.new(name: #ws))
.push(Action.new(parseTree: `{ intern(yytext); }));
// Literal Terminators
// BAR = '|' -
// NOT = '!' -
// QUERY = '?' -
// BEGIN = '<' -
// END = '>' -
// TILDE = '~' -
// RPERCENT = '%}' -
rules.bar = Sequence.new().push(StringLiteral.new(string: "|")).push(RuleCall.new(name: #ws));
rules.not = Sequence.new().push(StringLiteral.new(string: "!")).push(RuleCall.new(name: #ws));
rules.query = Sequence.new().push(StringLiteral.new(string: "?")).push(RuleCall.new(name: #ws));
rules.begin = Sequence.new().push(StringLiteral.new(string: "<")).push(RuleCall.new(name: #ws));
rules.end = Sequence.new().push(StringLiteral.new(string: ">")).push(RuleCall.new(name: #ws));
rules.tilde = Sequence.new().push(StringLiteral.new(string: "~")).push(RuleCall.new(name: #ws));
rules.rpercent = Sequence.new().push(StringLiteral.new(string: "%}")).push(RuleCall.new(name: #ws));
// DIGIT = [0-9]
// LETTER = [A-Za-z_]
// ALNUM = LETTER | DIGIT
// NIL = "nil" !ALNUM -
rules.digit = CharacterClass.new(value: "0-9");
rules.letter = CharacterClass.new(value: "A-Za-z_");
rules.alnum = Alternation.new()
.push(RuleCall.new(name: #letter))
.push(RuleCall.new(name: #digit));
rules.nil = Sequence.new()
.push(StringLiteral.new(string: "nil"))
.push(Not.new(expression: RuleCall.new(name: #alnum)))
.push(RuleCall.new(name: #ws));
// SEMI = ";" -
// COMMA = "," -
// COLON = ":" -
// LPAREN = "(" -
// RPAREN = ")" -
// LBRAK = "[" -
// RBRAK = "]" -
// LBRACE = "{" -
// RBRACE = "}" -
// ASSIGN = "=" ![=] -
// AND = "&" ![&=] -
// PLUS = "+" ![+=] -
// STAR = "*" ![=] -
// DOT = "." ![.] -
rules.semi = Sequence.new().push(StringLiteral.new(string: ";")).push(RuleCall.new(name: #ws));
rules.comma = Sequence.new().push(StringLiteral.new(string: ",")).push(RuleCall.new(name: #ws));
rules.colon = Sequence.new().push(StringLiteral.new(string: ":")).push(RuleCall.new(name: #ws));
rules.lparen = Sequence.new().push(StringLiteral.new(string: "(")).push(RuleCall.new(name: #ws));
rules.rparen = Sequence.new().push(StringLiteral.new(string: ")")).push(RuleCall.new(name: #ws));
rules.lbrak = Sequence.new().push(StringLiteral.new(string: "[")).push(RuleCall.new(name: #ws));
rules.rbrak = Sequence.new().push(StringLiteral.new(string: "]")).push(RuleCall.new(name: #ws));
rules.lbrace = Sequence.new().push(StringLiteral.new(string: "{")).push(RuleCall.new(name: #ws));
rules.rbrace = Sequence.new().push(StringLiteral.new(string: "}")).push(RuleCall.new(name: #ws));
rules.assign = Sequence.new()
.push(StringLiteral.new(string: "="))
.push(Not.new(expression: CharacterClass.new(value: "=")))
.push(RuleCall.new(name: #ws));
rules.and = Sequence.new()
.push(StringLiteral.new(string: "&"))
.push(Not.new(expression: CharacterClass.new(value: "&=")))
.push(RuleCall.new(name: #ws));
rules.plus = Sequence.new()
.push(StringLiteral.new(string: "+"))
.push(Not.new(expression: CharacterClass.new(value: "+=")))
.push(RuleCall.new(name: #ws));
rules.star = Sequence.new()
.push(StringLiteral.new(string: "*"))
.push(Not.new(expression: CharacterClass.new(value: "=")))
.push(RuleCall.new(name: #ws));
rules.dot = Sequence.new()
.push(StringLiteral.new(string: "."))
.push(Not.new(expression: CharacterClass.new(value: ".")))
.push(RuleCall.new(name: #ws));
// 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 = !.
rules.end_of_file = Not.new(expression: Dot.new());
rules.end_of_line = Alternation.new()
.push(StringLiteral.new(string: "\r\n"))
.push(StringLiteral.new(string: "\n"))
.push(StringLiteral.new(string: "\r"));
rules.comment = Sequence.new()
.push(StringLiteral.new(string: "#"))
.push(Star.new(expression:
Sequence.new()
.push(Not.new(expression: RuleCall.new(name: #end_of_line)))
.push(Dot.new())
))
.push(RuleCall.new(name: #end_of_line));
rules.space = Alternation.new()
.push(StringLiteral.new(string: " "))
.push(StringLiteral.new(string: "\t"))
.push(RuleCall.new(name: #end_of_line));
rules.ws = Star.new(expression: Alternation.new()
.push(RuleCall.new(name: #space))
.push(RuleCall.new(name: #comment))
);
// ----- Main -----
stream = newStream(readfile("rawgrammar.leg"));
//stream = newStream("rule1 = rule2* | b:rule3 {a = b;} rule4 = 'hello' ");
context = Context.new(outerContext: nil).init();
actions = [];
print("\nMatching : ", rules.grammar.match(stream, context, rules, actions), "\n");
// Execute all actions after all matching
for (actionAndContext in actions) {
//println(actionAndContext.action.parseTree);
actionAndContext.action.execute(actionAndContext.context);
}
println();

+ 94
- 17
minproto.leg Visa fil

@ -1,6 +1,6 @@
# minproto.leg -- minimal prototype langauge for semantic experiments
#
# last edited: 2024-05-14 06:33:02 by piumarta on m1mbp
# last edited: 2024-05-14 12:14:06 by piumarta on zora
%{
;
@ -97,9 +97,9 @@ oop printOn(oop buf, oop obj, int indent);
#endif
#if PRIMCLOSURE
#define doProtos(_) _(Object) _(RefVar) _(GetVar) _(SetVar) _(RefProp) _(GetProp) _(SetProp) _(RefArray) _(GetArray) _(SetArray) _(Call) _(Invoke) _(Continue) _(Break) _(Return) _(Binop) _(Unyop) _(Let) _(If) _(While) _(Block) _(For) _(ForIn) _(ForFromTo) _(Literal)
#define doProtos(_) _(Object) _(RefVar) _(GetVar) _(SetVar) _(RefProp) _(GetProp) _(SetProp) _(RefArray) _(GetArray) _(SetArray) _(Call) _(Invoke) _(Continue) _(Break) _(Return) _(Binop) _(Unyop) _(Let) _(If) _(While) _(Block) _(For) _(ForIn) _(ForFromTo) _(Literal) _(Range)
#else
#define doProtos(_) _(Object) _(RefVar) _(GetVar) _(SetVar) _(RefProp) _(GetProp) _(SetProp) _(RefArray) _(GetArray) _(SetArray) _(Call) _(Invoke) _(Continue) _(Break) _(Return) _(Binop) _(Unyop) _(Let) _(If) _(While) _(Block) _(For) _(ForIn) _(ForFromTo) _(Literal) _(Lambda) _(Closure)
#define doProtos(_) _(Object) _(RefVar) _(GetVar) _(SetVar) _(RefProp) _(GetProp) _(SetProp) _(RefArray) _(GetArray) _(SetArray) _(Call) _(Invoke) _(Continue) _(Break) _(Return) _(Binop) _(Unyop) _(Let) _(If) _(While) _(Block) _(For) _(ForIn) _(ForFromTo) _(Literal) _(Lambda) _(Closure) _(Range)
#endif
#define declareProto(NAME) oop p##NAME = 0;
@ -127,7 +127,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) _(__globals__) _(start) _(end) _(env)
#define declareSym(NAME) oop sym_##NAME = 0;
doSymbols(declareSym);
@ -155,11 +155,10 @@ int nnlrs = 0;
int maxnlrs = 0;
oop valnlr = 0;
#define nlrPush() ({ \
if (nnlrs == maxnlrs) nlrs = realloc(nlrs, sizeof(jmp_buf) * ++maxnlrs); \
++nnlrs; \
nlrs[nnlrs - 1].ntrace = _get(trace, Object,isize); \
setjmp(nlrs[nnlrs - 1].env); \
#define nlrPush() ({ \
if (++nnlrs >= maxnlrs) nlrs = realloc(nlrs, sizeof(struct NLR) * ++maxnlrs); \
nlrs[nnlrs - 1].ntrace = _get(trace, Object,isize); \
setjmp(nlrs[nnlrs - 1].env); \
})
#define nlrReturn(VAL, TYPE) { \
@ -1353,6 +1352,17 @@ oop GetArray_eval(oop exp, oop env)
default: fatal("[]: %s is not indexable", storeString(obj, 0));
}
}
if (getType(ind) == Object && Object_get(ind, prop_name) == Object_get(pRange, prop_name)) {
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);
}
@ -1402,6 +1412,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);
@ -2573,10 +2602,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 = PPLUS l:lvalue { $$ = newBinop(opPreAdd, l, newInteger(1)) }
| MMINUS l:lvalue { $$ = newBinop(opPreSub, l, newInteger(1)) }
@ -2649,8 +2681,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)) }
@ -2735,7 +2766,8 @@ SLASH = "/" ![/=] -
SLASHEQ = "/=" -
PCENT = "%" ![=] -
PCENTEQ = "%=" -
DOT = "." -
DOT = "." ![.] -
DOTDOT = ".." -
PLING = "!" ![=] -
TILDE = "~" -
@ -2931,6 +2963,26 @@ oop prim_length(oop func, oop self, oop args, oop env)
return newInteger(_get(self, Object,isize));
}
oop sortObject(oop obj, char *who)
{
int limit = _get(obj, Object,isize);
oop *elts = _get(obj, Object,indexed);
for (int i = 0; i < limit - 1; ++i) {
int mindex = i;
oop minobj = elts[i];
for (int j = i + 1; j < limit; ++j) {
oop newobj = elts[j];
if (cmp(newobj, minobj, who) < 0) mindex = j, minobj = newobj;
}
if (mindex != i) {
oop tmpobj = elts[i];
elts[i] = minobj;
elts[mindex] = tmpobj;
}
}
return obj;
}
oop prim_keys(oop func, oop self, oop args, oop env)
{
oop keys = new(pObject);
@ -2944,6 +2996,7 @@ oop prim_keys(oop func, oop self, oop args, oop env)
int size = _get(self, Object,psize);
struct property *kvs = _get(self, Object,properties);
for (int i = 0; i < size; ++i) Object_push(keys, kvs[i].key);
sortObject(keys, "keys");
break;
}
# if PRIMCLOSURE
@ -2973,6 +3026,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;
}
@ -2982,6 +3040,22 @@ oop prim___eval__(oop func, oop self, oop args, oop env)
return self;
}
oop prim_intern(oop func, oop self, oop args, oop env)
{
int argc = _get(args, Object,isize);
oop *indexed = _get(args, Object,indexed);
oop result = nil;
if (argc != 1) {
fatal("intern: invalid number of arguments");
}
if (getType(indexed[0]) != String) {
fatal("intern: argument is not of type String, got %s instead", getTypeName(indexed[0]));
}
return intern(_get(indexed[0], String, value));
}
oop prim_print(oop func, oop self, oop args, oop env)
{
int argc = _get(args, Object,isize);
@ -3133,7 +3207,7 @@ oop replFile(FILE *in)
printf(">>> ");
(opt_d ? println : codeln)(yysval, opt_v >2);
}
result = eval(yysval, nil);
result = eval(yysval, _get(sym___globals__, Symbol,value));
if (opt_v) {
printf("==> ");
if (opt_v >= 3) storeln(result, 1);
@ -3223,6 +3297,7 @@ int main(int argc, char **argv)
_set(intern("chr" ), Symbol,value, newPrimitive(prim_chr));
_set(intern("readfile" ), Symbol,value, newPrimitive(prim_readfile));
_set(intern("exit" ), Symbol,value, newPrimitive(prim_exit));
_set(intern("intern" ), Symbol,value, newPrimitive(prim_intern));
Object_put(pObject, intern("new"), newPrimitive(prim_new ));
Object_put(pObject, intern("push"), newPrimitive(prim_push ));
@ -3230,6 +3305,8 @@ int main(int argc, char **argv)
Object_put(pObject, intern("length"), newPrimitive(prim_length));
Object_put(pObject, intern("keys"), newPrimitive(prim_keys ));
_set(sym___globals__, Symbol,value, nil);
trace = new(pObject);
signal(SIGINT, sigint);

+ 32
- 0
test.txt Visa fil

@ -159,6 +159,38 @@ nil && ({ print("fail\n"); exit(1) });
nil || print("ok\n");
1 && print("ok\n");
i = 40;
assert(i++ == 40); assert(i == 41);
assert(i-- == 41); assert(i == 40);
assert(++i == 41); assert(i == 41);
assert(--i == 40); assert(i == 40);
assert((i *= 2) == 80); assert(i == 80);
assert((i /= 2) == 40); assert(i == 40);
assert((i %= 7) == 5); assert(i == 5);
assert((i <<= 4) == 80); assert(i == 80);
assert((i >>= 3) == 10); assert(i == 10);
i = 0;
assert((i |= 7) == 7); assert(i == 7);
assert((i |= 14) == 15); assert(i == 15);
assert((i ^= 6) == 9); assert(i == 9);
assert((i ^= 6) == 15); assert(i == 15);
assert((i &= 14) == 14); assert(i == 14);
assert((i &= 7) == 6); assert(i == 6);
i = [1, 2, 3];
assert(codeString(i) == "[1, 2, 3]");
assert(++i[1] == 3); assert(codeString(i) == "[1, 3, 3]");
assert(--i[2] == 2); assert(codeString(i) == "[1, 3, 2]");
assert(i[0]++ == 1); assert(codeString(i) == "[2, 3, 2]");
assert(i[2]-- == 2); assert(codeString(i) == "[2, 3, 1]");
print(eval(42), "\n");
MyType = Object.new(__name__: #MyType);

Laddar…
Avbryt
Spara