Skip to content

Commit 7a318ac

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

File tree

3 files changed

+160
-0
lines changed

3 files changed

+160
-0
lines changed

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: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
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+
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+
}
54+
55+
// 示例
56+
console.log(
57+
parse(`
58+
(1 + 2) * a -> - 3
59+
f(x)
60+
f(x) == 'x
61+
`)
62+
);
63+

g4/main.py

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

0 commit comments

Comments
 (0)