Skip to content

Commit e7a6422

Browse files
committed
Add a human friendly grammar.
1 parent 8d5baa9 commit e7a6422

File tree

4 files changed

+153
-0
lines changed

4 files changed

+153
-0
lines changed

g4/.gitignore

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
Ds.interp
2+
Ds.tokens
3+
DsLexer.interp
4+
DsLexer.tokens
5+
DsLexer.js
6+
DsLexer.py
7+
DsParser.js
8+
DsParser.py
9+
DsVisitor.js
10+
DsVisitor.py

g4/Ds.g4

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
grammar Ds;
2+
3+
rule_pool
4+
: NEWLINE* rule (NEWLINE+ rule)* NEWLINE* EOF
5+
;
6+
7+
rule
8+
: term
9+
| (term (',' term)*)? '->' term
10+
;
11+
12+
term
13+
: SYMBOL # symbol
14+
| term '(' (term (',' term)*)? ')' # function
15+
| '(' term ')' # parentheses
16+
| <assoc=right> ('~' | '!' | '-' | '+' | '&' | '*') term # unary
17+
| term ('*' | '/' | '%') term # binary
18+
| term ('+' | '-') term # binary
19+
| term ('<<' | '>>') term # binary
20+
| term ('<' | '>' | '<=' | '>=') term # binary
21+
| term ('==' | '!=') term # binary
22+
| term '&' term # binary
23+
| term '^' term # binary
24+
| term '|' term # binary
25+
| term '&&' term # binary
26+
| term '||' term # binary
27+
;
28+
29+
WHITESPACE
30+
: [ \t]+ -> skip
31+
;
32+
33+
COMMENT
34+
: '//' ~[\r\n]* -> skip
35+
;
36+
37+
NEWLINE
38+
: [\r\n]
39+
;
40+
41+
SYMBOL
42+
: ~[ \t\r\n,()]+
43+
;

g4/main.js

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import antlr4 from "antlr4";
2+
import DsLexer from "./DsLexer.js";
3+
import DsParser from "./DsParser.js";
4+
import DsVisitor from "./DsVisitor.js";
5+
6+
class Visitor extends DsVisitor {
7+
visitRule_pool(ctx) {
8+
return ctx.rule_().map(r => this.visit(r)).join("\n\n");
9+
}
10+
11+
visitRule(ctx) {
12+
const result = ctx.term().map(t => this.visit(t));
13+
if (result.length === 1) {
14+
return result[0];
15+
} else {
16+
const conclusion = result.pop();
17+
const length = Math.max(...result.map(premise => premise.length));
18+
result.push("-".repeat(length));
19+
result.push(conclusion);
20+
return result.join("\n");
21+
}
22+
}
23+
24+
visitSymbol(ctx) {
25+
return ctx.SYMBOL().getText();
26+
}
27+
28+
visitFunction(ctx) {
29+
return `(function ${ctx.term().map(t => this.visit(t)).join(" ")})`;
30+
}
31+
32+
visitParentheses(ctx) {
33+
return this.visit(ctx.term());
34+
}
35+
36+
visitUnary(ctx) {
37+
return `(unary ${ctx.getChild(0).getText()} ${this.visit(ctx.term())})`;
38+
}
39+
40+
visitBinary(ctx) {
41+
return `(binary ${ctx.getChild(1).getText()} ${this.visit(ctx.term(0))} ${this.visit(ctx.term(1))})`;
42+
}
43+
}
44+
45+
export function parse(input) {
46+
const chars = new antlr4.InputStream(input);
47+
const lexer = new DsLexer(chars);
48+
const tokens = new antlr4.CommonTokenStream(lexer);
49+
const parser = new DsParser(tokens);
50+
const tree = parser.rule_pool();
51+
const visitor = new Visitor();
52+
return visitor.visit(tree);
53+
}

g4/main.py

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
__all__ = ["parse"]
2+
3+
from antlr4 import InputStream, CommonTokenStream
4+
from DsLexer import DsLexer
5+
from DsParser import DsParser
6+
from DsVisitor import DsVisitor
7+
8+
9+
class Visitor(DsVisitor):
10+
def visitRule_pool(self, ctx: DsParser.Rule_poolContext):
11+
return "\n\n".join([self.visit(r) for r in ctx.rule_()])
12+
13+
def visitRule(self, ctx: DsParser.RuleContext):
14+
result = [self.visit(t) for t in ctx.term()]
15+
if len(result) == 1:
16+
return result[0]
17+
else:
18+
conclusion = result.pop()
19+
length = max(len(premise) for premise in result)
20+
result.append("-" * length)
21+
result.append(conclusion)
22+
return "\n".join(result)
23+
24+
def visitSymbol(self, ctx: DsParser.SymbolContext):
25+
return ctx.SYMBOL().getText()
26+
27+
def visitFunction(self, ctx: DsParser.FunctionContext):
28+
return f"(function {' '.join(self.visit(t) for t in ctx.term())})"
29+
30+
def visitParentheses(self, ctx: DsParser.ParenthesesContext):
31+
return self.visit(ctx.term())
32+
33+
def visitUnary(self, ctx: DsParser.UnaryContext):
34+
return f"(unary {ctx.getChild(0).getText()} {self.visit(ctx.term())})"
35+
36+
def visitBinary(self, ctx: DsParser.BinaryContext):
37+
return f"(binary {ctx.getChild(1).getText()} {self.visit(ctx.term(0))} {self.visit(ctx.term(1))})"
38+
39+
40+
def parse(string):
41+
input_stream = InputStream(string)
42+
lexer = DsLexer(input_stream)
43+
stream = CommonTokenStream(lexer)
44+
parser = DsParser(stream)
45+
tree = parser.rule_pool()
46+
visitor = Visitor()
47+
return visitor.visit(tree)

0 commit comments

Comments
 (0)