Skip to content

Commit 1db4d9d

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

File tree

4 files changed

+168
-0
lines changed

4 files changed

+168
-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: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
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 ')' # parentheses
15+
| term '::' term # binary
16+
| term '.' term # binary
17+
| term '[' term (',' term)* ']' # subscript
18+
| term '(' (term (',' term)*)? ')' # function
19+
| <assoc=right> ('~' | '!' | '-' | '+' | '&' | '*') term # unary
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+
| term '^' term # binary
28+
| term '|' term # binary
29+
| term '&&' term # binary
30+
| term '||' term # binary
31+
| term '=' term # binary
32+
;
33+
34+
WHITESPACE
35+
: [ \t]+ -> skip
36+
;
37+
38+
COMMENT
39+
: '//' ~[\r\n]* -> skip
40+
;
41+
42+
NEWLINE
43+
: [\r\n]
44+
;
45+
46+
SYMBOL
47+
: ~[ \t\r\n,()]+
48+
;

g4/main.js

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

g4/main.py

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
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("-" * max(length, 4))
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 visitParentheses(self, ctx: DsParser.ParenthesesContext):
28+
return self.visit(ctx.term())
29+
30+
def visitSubscript(self, ctx: DsParser.SubscriptContext):
31+
return f"(subscript {' '.join(self.visit(t) for t in ctx.term())})"
32+
33+
def visitFunction(self, ctx: DsParser.FunctionContext):
34+
return f"(function {' '.join(self.visit(t) for t in ctx.term())})"
35+
36+
def visitUnary(self, ctx: DsParser.UnaryContext):
37+
return f"(unary {ctx.getChild(0).getText()} {self.visit(ctx.term())})"
38+
39+
def visitBinary(self, ctx: DsParser.BinaryContext):
40+
return f"(binary {ctx.getChild(1).getText()} {self.visit(ctx.term(0))} {self.visit(ctx.term(1))})"
41+
42+
43+
def parse(string):
44+
input_stream = InputStream(string)
45+
lexer = DsLexer(input_stream)
46+
stream = CommonTokenStream(lexer)
47+
parser = DsParser(stream)
48+
tree = parser.rule_pool()
49+
visitor = Visitor()
50+
return visitor.visit(tree)

0 commit comments

Comments
 (0)