Skip to content

Instantly share code, notes, and snippets.

@openorclose
Last active September 28, 2019 08:16
Show Gist options
  • Save openorclose/20ed33f18d60f6474b6c3e0731cb7f7e to your computer and use it in GitHub Desktop.
Save openorclose/20ed33f18d60f6474b6c3e0731cb7f7e to your computer and use it in GitHub Desktop.
grammar for Source
/* description: Parses end executes JediScript expressions. */
/* lexical grammar */
%lex
%x DoubleQuotedString
%x SingleQuotedString
%x QuotedStringEscape
%%
\/\/([^\n\r]*) /* skip single-line comments */
\/\*([\u0000-\uffff]*?)\*\/ /* skip multi-line comments */
\s+ /* skip whitespace */
"function" return 'function'
"return" return 'return'
"if" return 'if'
"else" return 'else'
"while" return 'while'
"for" return 'for'
"break" return 'break'
"continue" return 'continue'
"let" return 'let'
"const" return 'const'
"===" return '==='
"=>" return '=>'
"=" return '='
"{" return '{'
"}" return '}'
";" return ';'
"," return ','
"true" return 'true'
"false" return 'false'
"NaN" return 'NaN'
"Infinity" return 'Infinity'
"null" return 'emptylist'
"[" return '['
"]" return ']'
'""' return 'EmptyString'
"''" return 'EmptyString'
'"' this.begin('DoubleQuotedString');
"'" this.begin('SingleQuotedString');
<DoubleQuotedString,SingleQuotedString>\\ this.begin('QuotedStringEscape');
<DoubleQuotedString>'"' this.popState();
<SingleQuotedString>"'" this.popState();
<QuotedStringEscape>(.|\r\n|\n) { this.popState(); return 'QuotedStringEscape'; } /* The newlines are there because we can span strings across lines using \ */
<DoubleQuotedString>[^"\\]* return 'QuotedString';
<SingleQuotedString>[^'\\]* return 'QuotedString';
[A-Za-z_][A-Za-z0-9_]* return 'Identifier' /* TODO: non-ASCII identifiers */
[0-9]+("."[0-9]+)?([eE][\-+]?[0-9]+)?\b return 'FLOAT_NUMBER' /* 3.1, 3.1e-7 */
[0-9]+\b return 'INT_NUMBER'
"+" return '+'
"-" return '-'
"*" return '*'
"/" return '/'
"%" return '%'
"!==" return '!=='
"<=" return '<='
">=" return '>='
"<" return '<'
">" return '>'
"!" return '!'
"&&" return '&&'
"||" return '||'
"(" return '('
")" return ')'
"?" return '?'
":" return ':'
<<EOF>> return 'EOF'
. return 'INVALID'
/lex
/* operator associations and precedence */
%left ';'
%right '='
%left '=>' ARROW
%right '?' ':'
%left '||'
%left '&&'
%left '===' '!=='
%left '<' '>' '<=' '>='
%left '+' '-'
%left '*' '/' '%'
%right '!' UMINUS UPLUS
%left '[' ']'
%left '.'
%% /* language grammar */
program
: statements EOF
{ return $1; }
;
statements
:
{ $$ = ""; }
| statement statements
{ $$ = $1 + $2; }
;
statement
:
ifstatement
| whilestatement
| forstatement
| 'function ' identifier '(' identifiers ')' '{' statements '}'
{{
$$ = "function" + $2 + "(" + $4 + ") {" + $7 + "}" ;
}}
| constdeclaration
| letdeclaration
| '{' statements '}'
{{
$$ = "{" + $2 + "}";
}}
| assignment ';'
{{
$$ = $1 + ";";
}}
| expression ';'
{{
$$ = $1 + ";";
}}
| 'return' expression ';'
{{
$$ = "return " + $2 + ";";
}}
| break ';'
{{
$$ = "break;";
}}
| continue ';'
{{
$$ = "continue;";
}}
;
letdeclaration
:
'let' identifier '=' expression ';'
{{
$$ = "var " + $2 + "=" + $4 + ";";
}}
;
constdeclaration
:
'const' identifier '=' expression ';'
{{
$$ = "var " + $2 + "=" + $4 + ";";
}}
;
assignment
:
expression '=' expression
{{
$$ = $1 + "=" + $3;
}}
;
ifstatement
:
'if' '(' expression ')' '{' statements '}' 'else' '{' statements '}'
{{
$$ = "if (" + $3 + ") {" + $6 + "} else {" + $10 + "}";
}}
| 'if' '(' expression ')' '{' statements '}' 'else' ifstatement
{{
$$ = "if (" + $3 + ") {" + $6 + "} else " + $9;
}}
;
whilestatement
:
'while' '(' expression ')' '{' statements '}'
{{
$$ = "while (" + $3 + ") {" + $6 + "}";
}}
;
forstatement
:
'for' '(' forinitialiser expression ';' forfinaliser ')' '{' statements '}'
{{
$$ = "for (" + $3 + $4 + ";" + $6 + ") {" + $9 + "}";
}}
;
forinitialiser
:
letdeclaration
| assignment ';'
{{
$$ = $1 + ";";
}}
;
forfinaliser
:
assignment
;
expression
:
expression '+' expression
{{
$$ = $1 + "+" + $3;
}}
| expression '-' expression
{{
$$ = $1 + "-" + $3;
}}
| expression '*' expression
{{
$$ = $1 + "*" + $3;
}}
| expression '/' expression
{{
$$ = $1 + "/" + $3;
}}
| expression '%' expression
{{
$$ = $1 + "%" + $3;
}}
| '-' expression %prec UMINUS
{{
$$ = "-" + $1;
}}
| '+' expression %prec UPLUS
{{
$$ = "+" + $1;
}}
| '!' expression
{{
$$ = "!" + $1;
}}
| expression '&&' expression
{{
$$ = $1 + "&&" + $3;
}}
| expression '||' expression
{{
$$ = $1 + "||" + $3;
}}
| expression '===' expression
{{
$$ = $1 + "===" + $3;
}}
| expression '!==' expression
{{
$$ = $1 + "!==" + $3;
}}
| expression '>' expression
{{
$$ = $1 + ">" + $3;
}}
| expression '<' expression
{{
$$ = $1 + "<" + $3;
}}
| expression '>=' expression
{{
$$ = $1 + ">=" + $3;
}}
| expression '<=' expression
{{
$$ = $1 + "<=" + $3;
}}
| '(' identifiers ')' '=>' expression %prec ARROW
{{
$$ = "(function(" + $2 + "){ return " + $5 + ";})";
}}
| '(' identifiers ')' '=>' '{' statements '}' %prec ARROW
{{
$$ = "(function(" + $2 + "){ " + $6 + "})";
}}
| identifier '=>' expression
{{
$$ = "(function(" + $1 + "){ return " + $3 + ";})";
}}
| identifier '=>' '{' statements '}'
{{
$$ = "(function(" + $1 + "){ " + $4 + "})";
}}
| expression '[' expression ']'
{{
$$ = $1 + "[" + $3 + "]"
}}
| '(' expression ')'
{$$ = "(" + $2 + ")";}
| constants
{ $$ = $1; }
| identifier
{ $$ = $1; }
| '(' expression ')' '(' expressions ')'
{{
$$ = "(" + $2 + ")(" + $5 + ")";
}}
| '[' expressions ']'
{{
$$ = "[" + $2 + "]";
}}
| identifier '(' expressions ')'
{{
$$ = $1 + "(" + $3 + ")";
}}
| expression '?' expression ':' expression
{{
$$ = $1 + "?" + $3 + ":" + $5;
}}
;
constants
:
'FLOAT_NUMBER'
{ $$ = String(parseFloat(yytext)); }
| 'INT_NUMBER'
{ $$ = String(parseInt(yytext, 10)); }
| 'true'
{ $$ = 'true'; }
| 'false'
{ $$ = 'false'; }
| 'NaN'
{ $$ = 'NaN'; }
| 'Infinity'
{ $$ = 'Infinity'; }
| quotedstring
| 'emptylist'
{ $$ = 'null'; }
;
quotedstring
:
'EmptyString'
{
$$ = '""';
}
| 'QuotedString'
| 'QuotedStringEscape'
{
switch (yytext)
{
case 'b': $$ = '\b'; break;
case 'n': $$ = '\n'; break;
case 'r': $$ = '\r'; break;
case 't': $$ = '\t'; break;
case "'": $$ = "'"; break;
case '"': $$ = '"'; break;
case '\\': $$ = '\\'; break;
case '\n':
case '\r\n': $$ = ''; break;
default: $$ = '\\' + $1; break;
}
}
| 'QuotedStringEscape' quotedstring
{
switch ($1)
{
case 'b': $$ = '\b'; break;
case 'n': $$ = '\n'; break;
case 'r': $$ = '\r'; break;
case 't': $$ = '\t'; break;
case "'": $$ = "'"; break;
case '"': $$ = '"'; break;
case '\\': $$ = '\\'; break;
case '\n':
case '\r\n': $$ = ''; break;
default: $$ = '\\' + $1; break;
}
$$ += $2;
}
| 'QuotedString' quotedstring
{
$$ = $1 + $2;
}
;
expressions
:
nonemptyexpressions
{ $$ = $1; }
| /* NOTHING */
{ $$ = ""; }
;
nonemptyexpressions
:
expression ',' nonemptyexpressions
{ $$ = $1 + "," + $3; }
| expression
{ $$ = $1; }
;
identifiers
:
nonemptyidentifiers
{ $$ = $1; }
| /* NOTHING */
{ $$ = ""; }
;
nonemptyidentifiers
:
identifier ',' nonemptyidentifiers
{ $$ = $1 + "," + $3; }
| identifier
{ $$ = $1; }
;
identifier
:
'Identifier'
{{
$$ = yytext;
}}
;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment