Skip to content

Commit d92249a

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

File tree

4 files changed

+165
-0
lines changed

4 files changed

+165
-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: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
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(Math.max(length, 4)));
19+
result.push(conclusion);
20+
return result.join("\n");
21+
}
22+
}
23+
24+
visitSymbol(ctx) {
25+
return ctx.SYMBOL().getText();
26+
}
27+
28+
visitParentheses(ctx) {
29+
return this.visit(ctx.term());
30+
}
31+
32+
visitSubscript(ctx) {
33+
return `(subscript ${ctx.term().map(t => this.visit(t)).join(" ")})`;
34+
}
35+
36+
visitFunction(ctx) {
37+
return `(function ${ctx.term().map(t => this.visit(t)).join(" ")})`;
38+
}
39+
40+
visitUnary(ctx) {
41+
return `(unary ${ctx.getChild(0).getText()} ${this.visit(ctx.term())})`;
42+
}
43+
44+
visitBinary(ctx) {
45+
return `(binary ${ctx.getChild(1).getText()} ${this.visit(ctx.term(0))} ${this.visit(ctx.term(1))})`;
46+
}
47+
}
48+
49+
export function parse(input) {
50+
const chars = new antlr4.InputStream(input);
51+
const lexer = new DsLexer(chars);
52+
const tokens = new antlr4.CommonTokenStream(lexer);
53+
const parser = new DsParser(tokens);
54+
const tree = parser.rule_pool();
55+
const visitor = new Visitor();
56+
return visitor.visit(tree);
57+
}

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)