20 Commit

Autore SHA1 Messaggio Data
  MaximeBarniaudy c2da606329 Migrate everything to peg vm 10 mesi fa
  MaximeBarniaudy 06962d9a48 add do-while and f-string dynamic addition proofs of concepts 10 mesi fa
  MaximeBarniaudy 168631e246 Add emitByteCode functions to support using the peg VM, add support for @ actions, automatically generate the minproto.grammar file from minproto.leg and use that in the parser generator. Fix issue with backslashes being stupid. 10 mesi fa
  MaximeBarniaudy c3125a863f Move side effect of variable assignment in namespace out of grammar for logic and ease of use reasons 11 mesi fa
  MaximeBarniaudy 959c34b7b2 Remove old unused code, and measure parsing speed 11 mesi fa
  MaximeBarniaudy 3ef49024c5 Use newest primitives for character class and string matching 11 mesi fa
  MaximeBarniaudy b2e4198529 Build Grammar objects whose methods are expression representations of grammar rules 11 mesi fa
  MaximeBarniaudy d26d33bf3f Fix errors after SetVar behavior change and let removal 11 mesi fa
  MaximeBarniaudy d840010b55 Delare Stream object in C code and add primitive for stream string matching. Also refactor the rollback mechanism in the grammar parser to give responsibility to the right object. 11 mesi fa
  MaximeBarniaudy 090142c69c Make grammar_parser.meta use the entire grammar from minproto.leg 11 mesi fa
  MaximeBarniaudy b23a65dbb0 Add optional base argument to String.asInteger 11 mesi fa
  MaximeBarniaudy 1a7d31d66e Fix error after single quote semantics change 1 anno fa
  MaximeBarniaudy a5b9103da3 Add with and without functions for namespace manimulation, add namespace support to grammars, add test of parser circularity 1 anno fa
  MaximeBarniaudy 1ec2c7d8ef parser circularity 1 anno fa
  MaximeBarniaudy dfa680df47 dotdot got lost in merging 1 anno fa
  MaximeBarniaudy 9851f982cb Add Invoke and GetProp 1 anno fa
  MaximeBarniaudy 4eeaa54367 Minimal grammar parsing 1 anno fa
  MaximeBarniaudy d170f243ee Add an intern primitive for symbol creation 1 anno fa
  WitherFlower 561c1dcb80 Merge range access and grammar parser changes 1 anno fa
  Ian Piumarta 1acd725af0 Default grammar is part of PEG VM frame. RULE2 and CALL2 change the default grammar for the duration of the rule being called. 10 mesi fa
10 ha cambiato i file con 2538 aggiunte e 34 eliminazioni
  1. +4
    -1
      Makefile
  2. +53
    -0
      dowhile.meta
  3. +81
    -0
      fstring.meta
  4. +1437
    -0
      grammar_parser.meta
  5. +316
    -0
      minproto.grammar
  6. +210
    -33
      minproto.leg
  7. +73
    -0
      rawMetaGrammar.leg
  8. +83
    -0
      rawgrammar.leg
  9. +275
    -0
      rawminproto.leg
  10. +6
    -0
      test.txt

+ 4
- 1
Makefile Vedi File

@ -15,7 +15,7 @@ MAIN = minproto
all : $(MAIN) all : $(MAIN)
% : %.c
% : %.c %.grammar
$(CC) $(GFLAGS) $(CFLAGS) $(LDFLAGS) -o $@ $< $(LDLIBS) $(CC) $(GFLAGS) $(CFLAGS) $(LDFLAGS) -o $@ $< $(LDLIBS)
%-opt : %.c %-opt : %.c
@ -27,6 +27,9 @@ all : $(MAIN)
%.c : %.leg %.c : %.leg
leg -o $@ $< leg -o $@ $<
%.grammar : %.leg
( sed "/%{/,/%}/d" $< | sed "/%%/,\$$d" ) > $@
tests : .FORCE tests : .FORCE
$(MAKE) clean all GFLAGS="-Wno-unused -g -DTYPECODES=1 -DELOPT=1" $(MAKE) clean all GFLAGS="-Wno-unused -g -DTYPECODES=1 -DELOPT=1"
-./$(MAIN) test.txt > test.out 2>&1 -./$(MAIN) test.txt > test.out 2>&1

+ 53
- 0
dowhile.meta Vedi File

@ -0,0 +1,53 @@
Do = Object.subtype(#Do);
Do.new(body, cond) {
self = super.new();
self.body = body;
self.cond = cond;
self;
}
Do.__eval__(env) {
local result = self.body.__eval__(env);
while (self.cond.__eval__(env)) {
result = self.body.__eval__(env);
}
result;
}
Do.__codeon__(str) {
str.push("do ");
self.body.__codeon__(str);
str.push(" while ( ");
self.cond.__codeon__(str);
str.push(" )");
}
// parse the grammar expression
// put it at the beginning of stmt (which is an alternation)
metaGrammar.stmt.prepend("\"whatever i want\" - b:stmt WHILE LPAREN c:expr RPAREN EOS { $$ = Do.new(b, c); }");
{
local i = 1;
{
whatever i want {
i *= 2;
print(i, "\n");
} while (i < 1000);
whatever i want {
i *= 2;
print(i, "\n");
} while (i < 1000);
whatever i want {
i *= 2;
print(i, "\n");
} while (i < 1000);
}
}

+ 81
- 0
fstring.meta Vedi File

@ -0,0 +1,81 @@
FormatString = Object.subtype(#FormatString);
FormatString.new(elements) {
self = super.new();
self.elements = elements;
self;
}
FormatString.__eval__(env) {
local result = "";
for(elem in self.elements) {
local elemval = elem.__eval__(env);
if (elemval.__name__ == #String) {
result.push(elemval);
} else {
elemval.__codeon__(result);
}
}
result;
}
FormatString.__codeon__(str) {
str.push("f\"");
for(elem in self.elements) {
if (elem.__name__ == #String) {
str.push(elem.escaped());
} else {
str.push("$");
elem.__codeon__(str);
}
}
str.push("\"");
}
nonSpaceEatingId = parseDefinition(
"nonSpaceEatingId = < LETTER ALNUM* > { $$ = intern(yytext) }
");
nonSpaceEatingBlock = parseDefinition(
"nonSpaceEatingBlock = LBRACE b:mkobj
( e:stmt { $$ = b.push(e) }
)* \"}\" { $$ = b }
");
fStringChar = parseDefinition(
"fStringChar = < (!\"\\\"\" !\"$\" char )+ > { $$ = yytext.unescaped() }
| \"\\\\$\" { $$ = \"$\" }
");
fStringRule = parseDefinition(
"fstring = \"f\\\"\" elements:mkobj
( \"$\" i:nonSpaceEatingId { $$ = elements.push(GetVar.new(name: i)) }
| \"$\" b:nonSpaceEatingBlock { $$ = elements.push(Block.new(body: b)) }
| c:fStringChar { $$ = elements.push(c) }
)* \"\\\"\" { $$ = FormatString.new(elements) }
");
// regenerate the expression to be executed
metaGrammar.addRule(nonSpaceEatingBlock.name, nonSpaceEatingBlock.expression);
metaGrammar.addRule(nonSpaceEatingId.name, nonSpaceEatingId.expression);
metaGrammar.addRule(fStringChar.name, fStringChar.expression);
metaGrammar.addRule(fStringRule.name, fStringRule.expression);
metaGrammar.primary.prepend("fstring");
formatInt(integer) {
if (integer > 1000) {
return f"${formatInt((integer - integer % 1000) / 1000)},${integer % 1000}";
}
return f"$integer";
}
a = 69;
print(f"Reimu has $a power and ${6*7} point items and \$${ formatInt(1 << 32) } money.\n");
n = 100;
print(f"Sum of integers from 1 to $n : ${local sum = 0; for (i in n + 1) sum += i}\n");
print(f"${formatInt.function}\n");
//{
// print(f"${__env__()}\n");
//}

+ 1437
- 0
grammar_parser.meta
File diff soppresso perché troppo grande
Vedi File


+ 316
- 0
minproto.grammar Vedi File

@ -0,0 +1,316 @@
# minproto.leg -- minimal prototype langauge for semantic experiments
#
# last edited: 2024-07-10 11:28:02 by piumarta on zora-1034.local
start = - ( s:stmt { global yysval = s }
| !. { global yysval = 0 }
| < (!EOL .)* > { syntaxError(yytext) }
)
stmt = WHILE LPAREN c:expr RPAREN s:stmt { $$ = newWhile(c, s) }
| IF LPAREN c:expr RPAREN s:stmt
( ELSE t:stmt { $$ = newIf(c, s, t ) }
| { $$ = newIf(c, s, nil) }
)
| CONT EOS { $$ = newContinue() }
| BREAK e:expr EOS { $$ = newBreak(e) }
| BREAK EOS { $$ = newBreak(nil) }
| RETURN e:expr EOS { $$ = newReturn(e) }
| RETURN EOS { $$ = newReturn(nil) }
| FOR LPAREN i:id IN e:expr RPAREN
s:stmt { $$ = newForIn(i, e, s) }
| FOR LPAREN i:id FROM a:expr
TO b:expr RPAREN s:stmt { $$ = newForFromTo(i, a, b, s) }
| FOR LPAREN i:expr SEMI c:expr SEMI
u:expr RPAREN s:stmt { $$ = newFor(i, c, u, s) }
| TRY t:stmt
( CATCH LPAREN i:id RPAREN c:stmt { $$ = newTryCatch(t, i, c) }
| ENSURE e:stmt { $$ = newTryEnsure(t, e) }
)
| RAISE e:expr EOS { $$ = newRaise(e) }
| LOCAL i:id p:params b:block { $$ = newSetLocal (i, newLambda(p, b, nil, i)) }
| GLOBAL i:id p:params b:block { $$ = newSetGlobal(i, newLambda(p, b, nil, i)) }
| i:id p:params b:block { $$ = newSetVar (i, newLambda(p, b, nil, i)) }
| v:proto DOT i:id p:params b:block { $$ = newSetProp(v, i, newLambda(p, b, v, i)) }
| b:block { $$ = newBlock(b) }
| e:expr EOS { $$ = e }
proto = v:var ( DOT j:id !LPAREN { v = newGetProp(v, j) }
)* { $$ = v }
EOS = SEMI+ | &RBRACE | &ELSE | &CATCH
expr = LOCAL i:id ASSIGN e:expr { $$ = newSetLocal (i, e) }
| GLOBAL i:id ASSIGN e:expr { $$ = newSetGlobal(i, e) }
| i:id ASSIGN e:expr { $$ = newSetVar (i, 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: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 }
prefix = PPLUS p:prefix { $$ = newBinop(opPreAdd, lvalue(p), newInteger(1)) }
| MMINUS p:prefix { $$ = newBinop(opPreSub, lvalue(p), newInteger(1)) }
| PLING p:prefix { $$ = newUnyop(opNot, p) }
| MINUS p:prefix { $$ = newUnyop(opNeg, p) }
| TILDE p:prefix { $$ = newUnyop(opCom, p) }
| BQUOTE s:stmt { $$ = newUnyop(opQuasiquote, s) }
| COMMAT e:expr { $$ = newUnyop(opUnquote, e) }
| postfix
postfix = SUPER DOT i:id a:args { $$ = newSuper(i, a) }
| p:primary
( LBRAK
( COLON ( RBRAK { p = newGetSlice(p, nil, nil) }
| e:xexpr RBRAK { p = newGetSlice(p, nil, e) }
)
| s:xexpr ( COLON ( RBRAK { p = newGetSlice(p, s, nil) }
| e:xexpr RBRAK { p = newGetSlice(p, s, e) }
)
| RBRAK { p = newGetArray(p, s) }
)
)
| DOT i:id ( a:args !LBRACE { p = newInvoke(p, i, a) }
| { p = newGetProp(p, i) }
)
| a:args !LBRACE { p = newApply(p, a) }
)*
( PPLUS { p = newBinop(opPostAdd, lvalue(p), newInteger( 1)) }
| MMINUS { p = newBinop(opPostAdd, lvalue(p), newInteger(-1)) }
)? { $$ = p }
args = LPAREN a:mkobj
( RPAREN
| ( k:id COLON e:xexpr { Object_put(a, k, e) }
| e:xexpr { Object_push(a, e) }
)
( COMMA ( k:id COLON e:xexpr { Object_put(a, k, e) }
| e:xexpr { Object_push(a, e) }
) )* RPAREN ) { $$ = a }
params = LPAREN p:mkobj
( RPAREN
| i:id ( COLON e:expr { Object_put(p, i, e) }
| { Object_push(p, i) }
)
( COMMA i:id ( COLON e:expr { Object_put(p, i, e) }
| { Object_push(p, i) }
)
)* RPAREN ) { $$ = p }
mkobj = { $$ = (global new)(pObject) }
primary = nil | number | string | symbol | var | lambda | subexpr | literal # | regex
lambda = p:params b:block { $$ = newLambda(p, b, nil, nil) }
subexpr = LPAREN e:expr RPAREN { $$ = e }
| b:block { $$ = newBlock(b) }
literal = LBRAK o:mkobj
( RBRAK
| ( ( i:id COLON e:expr { Object_put(o, i, e) }
| e:expr { Object_push(o, e) }
) ( COMMA ( i:id COLON e:expr { Object_put(o, i, e) }
| e:expr { Object_push(o, e) }
) )* )? RBRAK ) { $$ = newLiteral(o) }
block = LBRACE b:mkobj
( e:stmt { Object_push(b, e) }
)* ( RBRACE { $$ = b }
| error @{ expected("statement or \x7D", yytext) }
)
nil = NIL { $$ = nil }
number = "-" n:unsign { $$ = neg(n) }
| "+" n:number { $$ = n }
| n:unsign { $$ = n }
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)) }
| < DIGIT+ > - { $$ = newInteger(strtol(yytext, 0, 10)) }
| "'" < char > "'" - { $$ = newInteger(_get(newStringUnescaped(yytext), String,value)[0]) }
string = '"' < ( !'"' char )* > '"' - { $$ = newStringUnescaped(yytext) }
char = '\\' [abefnrtv'"\[\]\\]
| '\\' [0-3][0-7][0-7]
| '\\' [xX] HIGIT*
| '\\' [0-7][0-7]?
| !'\\' .
# char = "\\" ( ["'\\abfnrtv]
# | [xX] HIGIT*
# | [0-7][0-7]?[0-7]?
# )
# | .
symbol = HASH i:id { $$ = i }
var = LOCAL i:id { $$ = newGetLocal (i) }
| GLOBAL i:id { $$ = newGetGlobal(i) }
| i:id { $$ = newGetVar (i) }
id = < LETTER ALNUM* > - { $$ = intern(yytext) }
# regex = SLASH a:alts SLASH { $$ = a }
# alts = s:seq ( OR t:seq { s = Alt_append(t) }
# )* { $$ = s }
# seq = p:pre ( q:pre { s = Seq_append(t) }
# )* { $$ = s }
# elt = action | pre
# action = b:block { $$ = newAction(b) }
# pre = PLING p:pre { $$ = newNot(p) }
# | AND p:pre { $$ = newAnd(p) }
# | post
# post = a:atom ( STAR { a = newMany(a) }
# | PLUS { a = newMore(a) }
# | QUERY { a = newMore(a) }
# )? { $$ = a }
# atom = DOT { $$ = newDot() }
# | "[" ( !"]" "\\"? . )* "]" - { $$ = newClass(yytext) }
# | '"' xxxxxx
# class = LBRAK
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 | SLC | MLC
EOL = [\n\r] { ++lineno }
SLC = "//" (!EOL .)*
MLC = "/*" ( MLC | !"*/" (EOL | .))* "*/" -
NIL = "nil" !ALNUM -
WHILE = "while" !ALNUM -
IF = "if" !ALNUM -
ELSE = "else" !ALNUM -
FOR = "for" !ALNUM -
IN = "in" !ALNUM -
FROM = "from" !ALNUM -
TO = "to" !ALNUM -
CONT = "continue" !ALNUM -
BREAK = "break" !ALNUM -
RETURN = "return" !ALNUM -
TRY = "try" !ALNUM -
CATCH = "catch" !ALNUM -
ENSURE = "ensure" !ALNUM -
RAISE = "raise" !ALNUM -
GLOBAL = "global" !ALNUM -
LOCAL = "local" !ALNUM -
SUPER = "super" !ALNUM -
BQUOTE = "`" -
COMMAT = "@" -
HASH = "#" -
SEMI = ";" -
ASSIGN = "=" ![=] -
COMMA = "," -
COLON = ":" ![:] -
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 = "." ![.] -
PLING = "!" ![=] -
TILDE = "~" -
error = - < (!EOL .)* >
xexpr = expr | error @{ expected("expression", yytext) }

+ 210
- 33
minproto.leg Vedi File

@ -1,6 +1,6 @@
# minproto.leg -- minimal prototype langauge for semantic experiments # minproto.leg -- minimal prototype langauge for semantic experiments
# #
# last edited: 2024-07-05 17:16:16 by piumarta on zora-1034.local
# last edited: 2024-07-10 11:28:02 by piumarta on zora-1034.local
%{ %{
; ;
@ -121,9 +121,9 @@ oop printOn(oop buf, oop obj, int indent);
#endif #endif
#if PRIMCLOSURE #if PRIMCLOSURE
#define doProtos(_) _(Object) _(RefLocal) _(GetLocal) _(SetLocal) _(RefGlobal) _(GetGlobal) _(SetGlobal) _(RefVar) _(GetVar) _(SetVar) _(RefProp) _(GetProp) _(SetProp) _(RefArray) _(GetArray) _(SetArray) _(GetSlice) _(Call) _(Invoke) _(Super) _(Continue) _(Break) _(Return) _(TryCatch) _(TryEnsure)_(Raise)_(Binop) _(Unyop) _(If) _(While) _(Block) _(For) _(ForIn) _(ForFromTo) _(Literal)
#define doProtos(_) _(Object) _(RefLocal) _(GetLocal) _(SetLocal) _(RefGlobal) _(GetGlobal) _(SetGlobal) _(RefVar) _(GetVar) _(SetVar) _(RefProp) _(GetProp) _(SetProp) _(RefArray) _(GetArray) _(SetArray) _(GetSlice) _(Call) _(Invoke) _(Super) _(Continue) _(Break) _(Return) _(TryCatch) _(TryEnsure)_(Raise)_(Binop) _(Unyop) _(If) _(While) _(Block) _(For) _(ForIn) _(ForFromTo) _(Literal) _(Stream)
#else #else
#define doProtos(_) _(Object) _(RefLocal) _(GetLocal) _(SetLocal) _(RefGlobal) _(GetGlobal) _(SetGlobal) _(RefVar) _(GetVar) _(SetVar) _(RefProp) _(GetProp) _(SetProp) _(RefArray) _(GetArray) _(SetArray) _(GetSlice) _(Call) _(Invoke) _(Super) _(Continue) _(Break) _(Return) _(TryCatch) _(TryEnsure) _(Raise) _(Binop) _(Unyop) _(If) _(While) _(Block) _(For) _(ForIn) _(ForFromTo) _(Literal) _(Lambda) _(Closure)
#define doProtos(_) _(Object) _(RefLocal) _(GetLocal) _(SetLocal) _(RefGlobal) _(GetGlobal) _(SetGlobal) _(RefVar) _(GetVar) _(SetVar) _(RefProp) _(GetProp) _(SetProp) _(RefArray) _(GetArray) _(SetArray) _(GetSlice) _(Call) _(Invoke) _(Super) _(Continue) _(Break) _(Return) _(TryCatch) _(TryEnsure) _(Raise) _(Binop) _(Unyop) _(If) _(While) _(Block) _(For) _(ForIn) _(ForFromTo) _(Literal) _(Lambda) _(Closure) _(Stream)
#endif #endif
#define declareProto(NAME) oop p##NAME = 0; #define declareProto(NAME) oop p##NAME = 0;
@ -147,7 +147,7 @@ doTypes(makeProto);
doProperties(declareProp); doProperties(declareProp);
#undef 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) _(__namespaces__) _(O) _(d) _(p) _(v) _(statement) _(handler) _(kind) _(message) _(operand1) _(operand2) _(profile) _(parent) _(count) _(stamp) _(time) _(start) _(stop) _($$) _(yytext) _(yyleng)
#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) _(__namespaces__) _(O) _(d) _(p) _(v) _(statement) _(handler) _(kind) _(message) _(operand1) _(operand2) _(profile) _(parent) _(count) _(stamp) _(time) _(start) _(stop) _($$) _(yytext) _(yyleng) _(env) _(content) _(position) _(limit) _(lastBegin)
#define declareSym(NAME) oop sym_##NAME = 0; #define declareSym(NAME) oop sym_##NAME = 0;
doSymbols(declareSym); doSymbols(declareSym);
@ -501,6 +501,8 @@ oop newStringUnescaped(char *string)
case 'r' : c = '\r'; break; case 'r' : c = '\r'; break;
case 't' : c = '\t'; break; case 't' : c = '\t'; break;
case 'v' : c = '\v'; break; case 'v' : c = '\v'; break;
case '[' : c = '[' ; break;
case ']' : c = ']' ; break;
case 'X' : case 'X' :
case 'x' : c = readCharValue(&string, 16, -1); break; case 'x' : c = readCharValue(&string, 16, -1); break;
case '0'...'7': --string; c = readCharValue(&string, 8, 3); break; case '0'...'7': --string; c = readCharValue(&string, 8, 3); break;
@ -3340,6 +3342,26 @@ void Literal_codeOn(oop exp, oop str, oop env)
# endif # endif
} }
oop newStream(oop content)
{
oop o = new(pStream);
Object_put(o, sym_content , content);
Object_put(o, sym_position , newInteger(0));
Object_put(o, sym_limit , newInteger(_get(content, String, length)));
Object_put(o, sym_lastBegin, newInteger(0));
return o;
}
oop Stream_eval(oop exp, oop env)
{
return exp;
}
void Stream_codeOn(oop exp, oop str, oop env)
{
Object_codeOn(exp, str, env);
}
oop lvalue(oop rval) oop lvalue(oop rval)
{ {
if (!is(Object,rval)) valueError("=", "non-assignable value", rval); if (!is(Object,rval)) valueError("=", "non-assignable value", rval);
@ -3372,10 +3394,12 @@ void expected(char *what, char *where)
fatal("syntax error: %s expected near: %s", what, where); fatal("syntax error: %s expected near: %s", what, where);
} }
#define global
%} %}
start = - ( s:stmt { yysval = s }
| !. { yysval = 0 }
start = - ( s:stmt { global yysval = s }
| !. { global yysval = 0 }
| < (!EOL .)* > { syntaxError(yytext) } | < (!EOL .)* > { syntaxError(yytext) }
) )
@ -3461,10 +3485,10 @@ sum = l:prod ( PLUS r:prod { l = newBinop(opAdd, l, r) }
| MINUS r:prod { l = newBinop(opSub, l, r) } | MINUS r:prod { l = newBinop(opSub, l, r) }
)* { $$ = l } )* { $$ = 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: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 }
prefix = PPLUS p:prefix { $$ = newBinop(opPreAdd, lvalue(p), newInteger(1)) } prefix = PPLUS p:prefix { $$ = newBinop(opPreAdd, lvalue(p), newInteger(1)) }
| MMINUS p:prefix { $$ = newBinop(opPreSub, lvalue(p), newInteger(1)) } | MMINUS p:prefix { $$ = newBinop(opPreSub, lvalue(p), newInteger(1)) }
@ -3515,7 +3539,7 @@ params = LPAREN p:mkobj
) )
)* RPAREN ) { $$ = p } )* RPAREN ) { $$ = p }
mkobj = { $$ = new(pObject) }
mkobj = { $$ = (global new)(pObject) }
primary = nil | number | string | symbol | var | lambda | subexpr | literal # | regex primary = nil | number | string | symbol | var | lambda | subexpr | literal # | regex
@ -3544,8 +3568,7 @@ number = "-" n:unsign { $$ = neg(n) }
| "+" n:number { $$ = n } | "+" n:number { $$ = n }
| n:unsign { $$ = n } | n:unsign { $$ = n }
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" [bB] < BIGIT+ > - { $$ = newInteger(strtol(yytext, 0, 2)) }
| "0" [xX] < HIGIT+ > - { $$ = newInteger(strtol(yytext, 0, 16)) } | "0" [xX] < HIGIT+ > - { $$ = newInteger(strtol(yytext, 0, 16)) }
| "0" < OIGIT* > - { $$ = newInteger(strtol(yytext, 0, 8)) } | "0" < OIGIT* > - { $$ = newInteger(strtol(yytext, 0, 8)) }
@ -3554,11 +3577,16 @@ unsign = < DIGIT+ '.' DIGIT* EXP? > - { $$ = newFloat(strtod(yytext, 0
string = '"' < ( !'"' char )* > '"' - { $$ = newStringUnescaped(yytext) } string = '"' < ( !'"' char )* > '"' - { $$ = newStringUnescaped(yytext) }
char = "\\" ( ["'\\abfnrtv]
| [xX] HIGIT*
| [0-7][0-7]?[0-7]?
)
| .
char = '\\' [abefnrtv'"\[\]\\]
| '\\' [0-3][0-7][0-7]
| '\\' [xX] HIGIT*
| '\\' [0-7][0-7]?
| !'\\' .
# char = "\\" ( ["'\\abfnrtv]
# | [xX] HIGIT*
# | [0-7][0-7]?[0-7]?
# )
# | .
symbol = HASH i:id { $$ = i } symbol = HASH i:id { $$ = i }
@ -3673,7 +3701,7 @@ SLASH = "/" ![/=] -
SLASHEQ = "/=" - SLASHEQ = "/=" -
PCENT = "%" ![=] - PCENT = "%" ![=] -
PCENTEQ = "%=" - PCENTEQ = "%=" -
DOT = "." -
DOT = "." ![.] -
PLING = "!" ![=] - PLING = "!" ![=] -
TILDE = "~" - TILDE = "~" -
@ -3683,6 +3711,7 @@ xexpr = expr | error @{ expected("expression", yytext) }
%% %%
; ;
#undef global
#if PROFILE #if PROFILE
@ -3955,6 +3984,22 @@ oop prim_Object_initialise(oop func, oop self, oop args, oop env)
return self; 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) oop prim_Object_push(oop func, oop self, oop args, oop env)
{ assert(is(Object, args)); { assert(is(Object, args));
int argc = _get(args, Object,isize); assert(is(Object, self)); int argc = _get(args, Object,isize); assert(is(Object, self));
@ -4008,10 +4053,21 @@ oop prim_String_pop(oop func, oop self, oop args, oop env)
} }
oop prim_String_asInteger(oop func, oop self, oop args, oop env) oop prim_String_asInteger(oop func, oop self, oop args, oop env)
{ assert(is(String, self));
{ assert(is(Object, args));
int argc = _get(args, Object,isize); assert(is(String, self));
if (argc > 1) fatal("String.asInteger: expected either 0 or 1 arguments, got %d\n", argc);
char *str = String_content(self); // ensure nul terminator char *str = String_content(self); // ensure nul terminator
char *end = 0; char *end = 0;
long value = strtol(str, &end, 0);
long value;
if (argc == 1) {
oop base = _get(args, Object,indexed)[0];
value = strtol(str, &end, integerValue(base, "String.asInteger"));
} else {
value = strtol(str, &end, 0);
}
if (*end) return nil; if (*end) return nil;
return newInteger(value); return newInteger(value);
} }
@ -4243,6 +4299,47 @@ oop prim_Symbol_asString(oop func, oop self, oop args, oop env)
return newString(_get(self, Symbol,name)); return newString(_get(self, Symbol,name));
} }
oop prim_newStream(oop func, oop self, oop args, oop env)
{ assert(is(Object, args));
int argc = _get(args, Object,isize);
if (argc != 1) fatal("newStream: Expected 1 argument, got %d\n", argc);
oop arg = _get(args, Object, indexed)[0];
if (!is(String, arg)) fatal("newStream: expected an argument of type String, got type %s instead\n", getType(arg));
return newStream(arg);
}
oop prim_Stream_atEnd(oop func, oop self, oop args, oop env)
{
return newBoolean(_integerValue(Object_get(self, sym_position)) >= _integerValue(Object_get(self, sym_limit)));
}
oop prim_Stream_inc(oop func, oop self, oop args, oop env)
{
if (_integerValue(Object_get(self, sym_position)) < _integerValue(Object_get(self, sym_limit))) {
// There has to be a better way of just adding 1
Object_put(self, sym_position, newInteger(_integerValue(Object_get(self, sym_position)) + 1));
}
return Object_get(self, sym_position);
}
oop prim_Stream_setLastBegin(oop func, oop self, oop args, oop env)
{
return Object_put(self, sym_lastBegin, newInteger(_integerValue(Object_get(self, sym_position))));
}
oop prim_Stream_match(oop func, oop self, oop args, oop env)
{ assert(is(Object, args));
int argc = _get(args, Object,isize);
if (argc != 1) fatal("Stream.match: Expected 1 argument, got %d\n", argc);
oop arg = _get(args, Object, indexed)[0]; assert(is(String, arg));
return newBoolean(strncmp(
String_content(Object_get(self, sym_content)) + _integerValue(Object_get(self, sym_position)),
String_content(arg),
strlen(String_content(arg))
) == 0);
}
oop prim_length(oop func, oop self, oop args, oop env) oop prim_length(oop func, oop self, oop args, oop env)
{ assert(is(Object, args)); { assert(is(Object, args));
if (!is(Object, self)) valueError("length", "not an object", self); if (!is(Object, self)) valueError("length", "not an object", self);
@ -4298,6 +4395,12 @@ oop prim_eval(oop func, oop self, oop args, oop env)
int argc = _get(args, Object,isize); int argc = _get(args, Object,isize);
oop *indexed = _get(args, Object,indexed); oop *indexed = _get(args, Object,indexed);
oop result = nil; oop result = nil;
//if (nil != Object_getLocal(args, sym_env)) {
if (Object_find(args, sym_env) >= 0) {
env = Object_getLocal(args, sym_env);
}
for (int i = 0; i < argc; ++i) result = eval(indexed[i], env); for (int i = 0; i < argc; ++i) result = eval(indexed[i], env);
return result; return result;
} }
@ -4307,6 +4410,22 @@ oop prim___eval__(oop func, oop self, oop args, oop env)
return self; 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(String_content(indexed[0]));
}
oop prim_print(oop func, oop self, oop args, oop env) oop prim_print(oop func, oop self, oop args, oop env)
{ {
int argc = _get(args, Object,isize); int argc = _get(args, Object,isize);
@ -4770,12 +4889,12 @@ oop applyThunkIn(oop func, oop env)
typedef unsigned char byte; typedef unsigned char byte;
typedef enum op_t { typedef enum op_t {
PUSH, DROP, POP, DOT, CLASS, STRING, TEST, RULE2, RULE, CALL,
PUSH, DROP, POP, DOT, CLASS, STRING, TEST, RULE2, RULE, CALL, CALL2,
SUCCEED, FAIL, ACTION, BEGIN, END, UNEND, SET, SUCCEED, FAIL, ACTION, BEGIN, END, UNEND, SET,
} op_t; } op_t;
char *op_n[] = { char *op_n[] = {
"PUSH", "DROP", "POP", "DOT", "CLASS", "STRING", "TEST", "RULE2", "RULE", "CALL",
"PUSH", "DROP", "POP", "DOT", "CLASS", "STRING", "TEST", "RULE2", "RULE", "CALL", "CALL2",
"SUCCEED", "FAIL", "ACTION", "BEGIN", "END", "UNEND", "SET", "SUCCEED", "FAIL", "ACTION", "BEGIN", "END", "UNEND", "SET",
}; };
@ -4797,7 +4916,7 @@ typedef struct vmState
oop variables; oop variables;
} vmState; } vmState;
#define VM_STATE_INITIALISER { nil, nil }
#define VM_STATE_INITIALISER { nil, new(pObject) }
void vmEnter(vmState *state, oop obj, char *yytext, int yyleng) void vmEnter(vmState *state, oop obj, char *yytext, int yyleng)
{ {
@ -4812,7 +4931,7 @@ void vmSet(vmState *state, oop obj, char *yytext, int yyleng)
void vmAction(vmState *state, oop obj, char *yytext, int yyleng) void vmAction(vmState *state, oop obj, char *yytext, int yyleng)
{ {
oop text = yyleng ? newStringLen(yytext, yyleng) : nil;
oop text = yyleng >= 0 ? newStringLen(yytext, yyleng) : nil;
Object_put(state->variables, sym_yytext, text); Object_put(state->variables, sym_yytext, text);
Object_put(state->variables, sym_yyleng, newInteger(yyleng)); Object_put(state->variables, sym_yyleng, newInteger(yyleng));
applyThunkIn(obj, state->variables); applyThunkIn(obj, state->variables);
@ -4822,6 +4941,7 @@ void vmLeave(vmState *state, oop obj, char *yytext, int yyleng)
{ {
state->result = Object_getLocal(state->variables, sym_$$); state->result = Object_getLocal(state->variables, sym_$$);
state->variables = _getDelegate(state->variables); state->variables = _getDelegate(state->variables);
Object_put(state->variables, sym_$$, state->result);
} }
void vmDisassemble(vmInsn *code, int pc) void vmDisassemble(vmInsn *code, int pc)
@ -4838,6 +4958,10 @@ void vmDisassemble(vmInsn *code, int pc)
printf("%03d %-7s %p %2d %2d %2d\n", printf("%03d %-7s %p %2d %2d %2d\n",
pc, op_n[i->op], i->arg.code, i->arg2.len, i->ok, i->ko); pc, op_n[i->op], i->arg.code, i->arg2.len, i->ok, i->ko);
break; break;
case CALL2:
printf("%03d %-7s %p %2d %2d %2d\n",
pc, op_n[i->op], i->arg.code, i->arg2.len, i->ok, i->ko);
break;
default: default:
printf("%03d %-7s %s %2d %2d %2d\n", printf("%03d %-7s %s %2d %2d %2d\n",
pc, op_n[i->op], codeString(i->arg.obj, 0), i->arg2.len, i->ok, i->ko); pc, op_n[i->op], codeString(i->arg.obj, 0), i->arg2.len, i->ok, i->ko);
@ -4906,6 +5030,10 @@ vmInsn *vmCompile(oop grammar, oop symbol)
valueError("__match__", "program contains explicit CALL opcode", program); valueError("__match__", "program contains explicit CALL opcode", program);
break; break;
} }
case CALL2: {
valueError("__match__", "program contains explicit CALL2 opcode", program);
break;
}
case ACTION: { case ACTION: {
if (!isClosure(code[cpc].arg.obj)) valueError("__match__", "ACTION argument must be a closure", program); if (!isClosure(code[cpc].arg.obj)) valueError("__match__", "ACTION argument must be a closure", program);
break; break;
@ -4944,12 +5072,10 @@ vmInsn *vmCacheGet(oop grammar, oop symbol)
return vmCompile(grammar, symbol); return vmCompile(grammar, symbol);
} }
int vmRun(oop grammar, oop symbol, char *text, int start, int length)
int vmRun(oop grammar0, oop symbol, char *text, int start, int length)
{ {
vmCache = new(pObject); vmCache = new(pObject);
vmInsn *code = vmCacheGet(grammar, symbol);
int maxactions = 32; int maxactions = 32;
struct Action { struct Action {
@ -4977,7 +5103,10 @@ int vmRun(oop grammar, oop symbol, char *text, int start, int length)
actions[context.nactions++] = (struct Action){ ACT, OBJ, BEG, LEN }; \ actions[context.nactions++] = (struct Action){ ACT, OBJ, BEG, LEN }; \
} }
//vmInsn *code = vmCacheGet(frame.grammar, symbol);
struct Frame { struct Frame {
oop grammar;
oop symbol; oop symbol;
vmInsn *code; vmInsn *code;
int pc; int pc;
@ -4986,8 +5115,9 @@ int vmRun(oop grammar, oop symbol, char *text, int start, int length)
int rsp = 0, nrstack = 32; int rsp = 0, nrstack = 32;
rstack = xmalloc(sizeof(*rstack) * nrstack); rstack = xmalloc(sizeof(*rstack) * nrstack);
frame.grammar = grammar0;
frame.symbol = symbol; frame.symbol = symbol;
frame.code = vmCacheGet(grammar, symbol);
frame.code = vmCacheGet(grammar0, symbol);
frame.pc = 0; frame.pc = 0;
frame.nactions = context.nactions; frame.nactions = context.nactions;
@ -5009,6 +5139,8 @@ int vmRun(oop grammar, oop symbol, char *text, int start, int length)
C##stack[--C##sp]; \ C##stack[--C##sp]; \
}) })
saveAction(vmEnter, nil, 0, 0);
for (;;) { for (;;) {
if (opt_d) vmDisassemble(frame.code, frame.pc); if (opt_d) vmDisassemble(frame.code, frame.pc);
vmInsn *i = frame.code + frame.pc++; vmInsn *i = frame.code + frame.pc++;
@ -5054,8 +5186,19 @@ int vmRun(oop grammar, oop symbol, char *text, int start, int length)
continue; continue;
} }
case RULE2: { case RULE2: {
i->op = CALL;
i->op = CALL2;
i->arg.code = vmCacheGet(i->arg2.obj, i->arg.obj); i->arg.code = vmCacheGet(i->arg2.obj, i->arg.obj);
goto doCall2; // (just in case they are not consecutive ;-))
case CALL2: { doCall2:
frame.pc--; // save pc of call insn
push(r, frame);
frame.grammar = i->arg2.obj;
frame.code = i->arg.code;
frame.pc = 0;
saveAction(vmEnter, nil, 0, 0);
frame.nactions = context.nactions;
continue;
}
goto doCall; goto doCall;
} }
case RULE: { case RULE: {
@ -5072,7 +5215,7 @@ int vmRun(oop grammar, oop symbol, char *text, int start, int length)
//i->arglen = ((Node *)i->arg)->Symbol.nvars; //i->arglen = ((Node *)i->arg)->Symbol.nvars;
//i->arg = ((Node *)i->arg)->Symbol.code; assert(i->arg); //i->arg = ((Node *)i->arg)->Symbol.code; assert(i->arg);
i->op = CALL; i->op = CALL;
i->arg.code = vmCacheGet(grammar, i->arg.obj);
i->arg.code = vmCacheGet(frame.grammar, i->arg.obj);
goto doCall; // (just in case they are not consecutive ;-)) goto doCall; // (just in case they are not consecutive ;-))
} }
case CALL: { doCall: case CALL: { doCall:
@ -5146,8 +5289,6 @@ int vmRun(oop grammar, oop symbol, char *text, int start, int length)
break; break;
} }
saveAction(vmLeave, nil, 0, 0);
#undef pop #undef pop
#undef drop #undef drop
#undef push #undef push
@ -5184,6 +5325,20 @@ oop prim_match(oop func, oop self, oop args, oop env)
#endif // PEGVM #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) oop replFile(FILE *in)
{ {
int oldline = lineno; int oldline = lineno;
@ -5309,6 +5464,18 @@ int main(int argc, char **argv)
Object_put(pObject, prop_eval, newPrimitive(prim___eval__, newString("Object.__eval__"))); // inherited by all objects 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
#undef stringify
#define declareOp(NAME, OP) _set(intern(#NAME), Symbol,value, newInteger(NAME));
doUnyops(declareOp)
#undef declareOp
#if TYPECODES #if TYPECODES
# define defineEvaluator(NAME) \ # define defineEvaluator(NAME) \
@ -5354,6 +5521,12 @@ int main(int argc, char **argv)
prim(defined , prim_defined); prim(defined , prim_defined);
prim(__extern__ , prim_extern); prim(__extern__ , prim_extern);
prim(__match__ , prim_match); prim(__match__ , prim_match);
prim(intern , prim_intern);
prim(newBinop , prim_newBinop);
prim(newApply , prim_newApply);
prim(lvalue , prim_lvalue);
prim(assign , prim_assign);
prim(newStream , prim_newStream);
# undef prim # undef prim
@ -5396,6 +5569,10 @@ int main(int argc, char **argv)
method(Symbol,define, prim_Symbol_define ); method(Symbol,define, prim_Symbol_define );
method(Symbol,value, prim_Symbol_value ); method(Symbol,value, prim_Symbol_value );
method(Symbol,allInstances, prim_Symbol_allInstances); method(Symbol,allInstances, prim_Symbol_allInstances);
method(Stream,atEnd, prim_Stream_atEnd );
method(Stream,inc, prim_Stream_inc );
method(Stream,setLastBegin, prim_Stream_setLastBegin);
method(Stream,match, prim_Stream_match );
# undef method # undef method

+ 73
- 0
rawMetaGrammar.leg Vedi File

@ -0,0 +1,73 @@
statement = b:block { b; }
| e:expression SEMI { e; }
expression = p:primary
( DOT i:id ASSIGN e:expression # { $$ = newSetProp(p, i, e) }
| LBRAK i:expression RBRAK ASSIGN e:expression { SetArray.new(object: p, index: i, value: e); }
)
| i:id ASSIGN e:expression { SetVar.new(name: i, value: e); }
| pf:postfix { pf; }
postfix = p:primary
( DOT i:id a:args !ASSIGN !LBRACE { p = Invoke.new(self: p, method: i, arguments: a); }
| DOT i:id !ASSIGN { p = GetProp.new(object: p, key: i); }
| a:args !ASSIGN !LBRACE { p = Call.new(function: p, arguments: a); }
) * { p; }
args = LPAREN a:mklist
(
( k:id COLON e:expression { a[k] = e; }
| e:expression { a.push(e); }
)
( COMMA
( k:id COLON e:expression { a[k] = e; }
| e:expression { a.push(e); }
)
) *
) ? RPAREN { a; }
mklist = { Object.new(); }
primary = nil | number | var | subExpr
subExpr = LPAREN e:expression RPAREN { e; }
block = LBRACE b:mklist
( e:statement { 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+ > - { yytext.asInteger(10); }
var = i:id { GetVar.new(name: i); }
id = < LETTER ALNUM* > - { intern(yytext); }
DIGIT = [0-9]
LETTER = [A-Za-z_]
ALNUM = LETTER | DIGIT
NIL = "nil" !ALNUM -
SEMI = ";" -
COMMA = "," -
LPAREN = "(" -
RPAREN = ")" -
LBRAK = "[" -
RBRAK = "]" -
LBRACE = "{" -
RBRACE = "}" -
COLON = ":" ![:] -
ASSIGN = "=" ![=] -
DOT = "." ![.] -
- = ( space | comment )*
space = ' ' | '\t' | end-of-line
comment = '//' ( !end-of-line . )* end-of-line
end-of-line = '\r\n' | '\n' | '\r'
end-of-file = !.

+ 83
- 0
rawgrammar.leg Vedi File

@ -0,0 +1,83 @@
grammar = - ( d:definition { global yysval = d; }
| end-of-file { global yysval = nil; }
)
definition = i:identifier ASSIGN e:expression SEMI? { $$ = Definition.new(name: i, expression: e); }
expression = s:sequence !BAR { $$ = s; }
| s1:sequence { s1 = Alternation.new().push(s1); }
( BAR s2:sequence { s1.push(s2); }
) * { $$ = s1; }
startSequence = - s:sequence { global yysval = s; }
sequence = p:prefix ( q:prefix { p = Sequence.new().push(p).push(q); }
( q:prefix { p.push(q); }
) * ) ? { $$ = p; }
prefix = AND a:action { $$ = ParseTimeAction.new(action: a); }
| AT a:action { $$ = ExecuteAction.new(action: a); }
|
( AND s:suffix { $$ = And.new(expression: s); }
| NOT s:suffix { $$ = Not.new(expression: s); }
| s:suffix { $$ = s; }
)
suffix = p:primary
( QUERY { p = Optional.new(expression: p); }
| STAR { p = Star.new(expression: p); }
| PLUS { p = Plus.new(expression: p); }
) ? { $$ = p; }
primary = i1:identifier COLON i2:ruleCall !ASSIGN { $$ = Assignment.new(name: i1, rule: i2); }
| i:ruleCall !ASSIGN { $$ = i; }
| LPAREN e:expression RPAREN { $$ = e; }
| l:literal { $$ = l; }
| c:class { $$ = c; }
| DOT { $$ = Dot.new(); }
| a:action { $$ = a; }
| BEGIN e:expression END { $$ = Capture.new(expression: e); }
identifier = < [-a-zA-Z_][-a-zA-Z_0-9]* > - { $$ = intern(yytext); }
ruleCall = n:identifier CCOLON r:identifier { $$ = NamespacedRuleCall
.new(namespace: GetVar.new(name: n).__eval__(), name: r);
}
| i:identifier { $$ = RuleCall.new(name: i); }
literal = ['] < ( !['] char )* > ['] - { $$ = StringLiteral.new(string: yytext.unescaped()); }
| ["] < ( !["] char )* > ["] - { $$ = StringLiteral.new(string: yytext.unescaped()); }
class = '[' < ( !']' range )* > ']' - { $$ = CharacterClass.new(value: yytext.unescaped()); }
range = char '-' char | char
char = '\\' [abefnrtv'"\[\]\\]
| '\\' [0-3][0-7][0-7]
| '\\' [0-7][0-7]?
| !'\\' .
action = m:metaGrammar::block - { $$ = Action.new(parseTree: Block.new(body: m)); }
- = ( space | comment )*
space = ' ' | '\t' | end-of-line
comment = '#' ( !end-of-line . )* end-of-line
end-of-line = '\r\n' | '\n' | '\r'
end-of-file = !.
BAR = '|' -
NOT = '!' -
QUERY = '?' -
BEGIN = '<' -
END = '>' -
SEMI = ";" -
CCOLON = "::" -
LPAREN = "(" -
RPAREN = ")" -
ASSIGN = "=" ![=] -
AND = "&" ![&=] -
PLUS = "+" ![+=] -
STAR = "*" ![=] -
DOT = "." ![.] -
COLON = ":" ![:] -
AT = "@" -

+ 275
- 0
rawminproto.leg Vedi File

@ -0,0 +1,275 @@
start = - ( s:stmt { s; }
| !. # { yysval = 0 }
| < (!EOL .)* > # { fatal("syntax error near: %s", yytext) }
)
stmt = 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) }
| TRY t:stmt
( CATCH LPAREN i:id RPAREN c:stmt { TryCatch.new(statement: t, identifier: i, handler: c) }
| ENSURE e:stmt { TryEnsure.new(statement: t, handler: e) }
)
| RAISE e:expr EOS { Raise.new(value: e) }
| LOCAL i:id p:params b:block { SetLocal.new(name: i, value: Lambda.new(parameters: p, body: b)) }
| GLOBAL i:id p:params b:block { SetGlobal.new(name: i, value: Lambda.new(parameters: p, body: b)) }
| 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)) }
| b:block { Block.new(body: b) }
| e:expr EOS { e }
proto = v:var ( DOT j:id !LPAREN { v = GetProp.new(object: v, key: j) }
)* { v }
EOS = SEMI+ | &RBRACE | &ELSE | &CATCH
expr = LOCAL i:id ASSIGN e:expr { SetLocal.new(name: i, value: e) }
| GLOBAL i:id ASSIGN e:expr { SetGlobal.new(name: i, value: e) }
| 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 = SUPER DOT i:id a:args { Super.new(method: i, arguments: a) }
| 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) }
)*
( 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 { 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() }
| "'" < char > "'" - { ord(yytext.unescaped()) }
string = '"' < ( !'"' char )* > '"' - { yytext }
# Version originale, qui ne parse pas deux antislash pour une raison obscure
# char = "\\" ( ["'\\abfnrtv]
# | [xX] HIGIT*
# | [0-7][0-7]?[0-7]?
# )
# | .
# Version de rawgrammar.leg, qui fonctionne sans problème
char = '\\' [abefnrtv'"\[\]\\]
| '\\' [0-3][0-7][0-7]
| '\\' [0-7][0-7]?
| '\\' [xX] HIGIT+
| !'\\' .
symbol = HASH i:id { i }
var = LOCAL i:id { GetLocal.new(name: i) }
| GLOBAL i:id { GetGlobal.new(name: i) }
| 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 | SLC | MLC
EOL = [\n\r] # { ++lineno }
SLC = "//" (!EOL .)*
MLC = "/*" ( MLC | !"*/" (EOL | .))* "*/" -
NIL = "nil" !ALNUM -
WHILE = "while" !ALNUM -
IF = "if" !ALNUM -
ELSE = "else" !ALNUM -
FOR = "for" !ALNUM -
IN = "in" !ALNUM -
FROM = "from" !ALNUM -
TO = "to" !ALNUM -
CONT = "continue" !ALNUM -
BREAK = "break" !ALNUM -
RETURN = "return" !ALNUM -
TRY = "try" !ALNUM -
CATCH = "catch" !ALNUM -
ENSURE = "ensure" !ALNUM -
RAISE = "raise" !ALNUM -
GLOBAL = "global" !ALNUM -
LOCAL = "local" !ALNUM -
SUPER = "super" !ALNUM -
BQUOTE = "`" -
COMMAT = "@" -
HASH = "#" -
SEMI = ";" -
ASSIGN = "=" ![=] -
COMMA = "," -
COLON = ":" ![:] -
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 = "~" -

+ 6
- 0
test.txt Vedi File

@ -378,6 +378,12 @@ ast = (`6 * @myNode;); // user-defined node in AST
print("AST eval => ", eval(ast), "\n"); print("AST eval => ", eval(ast), "\n");
print("String to int conversion\n");
print("11111111".asInteger(2), "\n");
print("377".asInteger(8), "\n");
print("255".asInteger(), "\n");
print("FF".asInteger(16), "\n");
for (i from 0 to 10) print(i, " "); print("\n"); for (i from 0 to 10) print(i, " "); print("\n");
for (i from 10 to 0) print(i, " "); print("\n"); for (i from 10 to 0) print(i, " "); print("\n");
for (i in 10) print(i, " "); print("\n"); for (i in 10) print(i, " "); print("\n");

Caricamento…
Annulla
Salva