Commit 9ab7f56f authored by Anya Helene Bagge's avatar Anya Helene Bagge 🦆
Browse files

various changes

parent b90da5cf
......@@ -2,10 +2,11 @@ grammar Expr;
ID : [a-z]+ ; // match lower-case identifiers
NUM : [0-9]+ ; // match integers
WS : [ \t\r\n]+ -> skip ; // skip spaces, tabs, newlines
WS : [ \t\r\n]+ -> skip ; // LAYOUT: skip spaces, tabs, newlines
program : expr; // a program is just an expression
expr : idExpr | numExpr | plusExpr; // an expression is a number, identifier or addition
idExpr : ID; // an identifier
numExpr : NUM; // a number
plusExpr : '+' expr expr; // addition of two expressions
expr : ID # idExpr // an identifier
| NUM # numExpr // a number
| expr '*' expr # multExpr
| expr '+' expr # plusExpr
;
// Define a grammar called Hello
grammar Hello;
ID : [a-z]+ ; // match lower-case identifiers
hello : 'hello' ID '!'; // match keyword hello followed by an identifier
ID : [a-z][a-z0-9]* ; // match lower-case identifiers
WS : [ \t\r\n]+ -> skip ; // skip spaces, tabs, newlines
//symbol_name : sym1 sym2 sym3
//sym1 : 'var' ID '=' Expr;
\ No newline at end of file
package inf225.examples;
public class DrawTree {
}
package inf225.examples;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Deque;
import java.util.Iterator;
import java.util.LinkedList;
import org.antlr.v4.runtime.CharStreams;
import org.antlr.v4.runtime.CommonTokenStream;
import org.antlr.v4.runtime.IntStream;
import org.antlr.v4.runtime.ParserRuleContext;
import org.antlr.v4.runtime.RuleContext;
import org.antlr.v4.runtime.Token;
import org.antlr.v4.runtime.TokenStream;
import org.antlr.v4.runtime.misc.Interval;
import org.antlr.v4.runtime.tree.ErrorNode;
import org.antlr.v4.runtime.tree.ParseTree;
import org.antlr.v4.runtime.tree.ParseTreeVisitor;
import org.antlr.v4.runtime.tree.ParseTreeWalker;
import org.antlr.v4.runtime.tree.RuleNode;
import org.antlr.v4.runtime.tree.TerminalNode;
import org.apache.commons.text.StringEscapeUtils;
import inf225.grammars.ExprBaseListener;
import inf225.grammars.ExprLexer;
import inf225.grammars.ExprListener;
import inf225.grammars.ExprParser;
import inf225.grammars.ExprParser.ExprContext;
import inf225.grammars.ExprParser.IdExprContext;
import inf225.grammars.ExprParser.NumExprContext;
import inf225.grammars.ExprParser.PlusExprContext;
import inf225.grammars.ExprParser.MultExprContext;
import inf225.grammars.ExprParser.ProgramContext;
import inf225.grammars.ExprVisitor;
/**
* Simple expression language
*/
public class ExprExample {
public static void main(String[] args) {
public static void main(String[] args) throws URISyntaxException {
URI uri = new URI(null, null, "foo/bar", null);
int x = 2, y = x * 2;
// our input
String input = "+ 1 + 2 3";
String input = "2** 2 + 3 * 4 + 4 * 7*2";
// a lexer that splits the input string into tokens
ExprLexer lexer = new ExprLexer(CharStreams.fromString(input));
ExprLexer lexer = new ExprLexer(CharStreams.fromString(input,uri.getPath()));
// a stream of tokens to feed to the parser
CommonTokenStream tokens = new CommonTokenStream(lexer);
// the parser that recovers the tree structure from the token stream
ExprParser parser = new ExprParser(tokens);
// the parse tree of the non-terminal we're interested in
ProgramContext tree = parser.program();
HelloExample.dumpParseTree(tree, parser);
ParseTreeWalker walker = new ParseTreeWalker();
System.out.println(tree.accept(new ExprVisitor<Integer>() {
@Override
public Integer visit(ParseTree tree) {
// TODO Auto-generated method stub
return 0;
}
@Override
public Integer visitChildren(RuleNode node) {
// TODO Auto-generated method stub
return 0;
}
@Override
public Integer visitTerminal(TerminalNode node) {
// TODO Auto-generated method stub
return 0;
}
@Override
public Integer visitErrorNode(ErrorNode node) {
System.out.println("error: " + node);
// TODO Auto-generated method stub
return 0;
}
@Override
public Integer visitProgram(ProgramContext ctx) {
return ctx.expr().accept(this);
}
@Override
public Integer visitMultExpr(MultExprContext ctx) {
System.out.println("multexpr:" + ctx.getText());
System.out.println("plusexpr: " + ctx.getText());
int val = 1;
for (ExprContext child : ctx.expr()) {
// val *= child.accept(this);
}
return val;
}
@Override
public Integer visitNumExpr(NumExprContext ctx) {
System.out.println("numexpr:" + ctx.getText());
return Integer.parseInt(ctx.getText());
}
@Override
public Integer visitPlusExpr(PlusExprContext ctx) {
System.out.println("plusexpr: " + ctx.getText());
int val = 0;
for (ExprContext child : ctx.expr()) {
// val += child.accept(this);
}
return val;
}
// grammar-specific walk: evaluate the expression using a stack
walker.walk(new ExprBaseListener() {
Deque<Integer> stack = new LinkedList<>();
@Override
public Integer visitIdExpr(IdExprContext ctx) {
// TODO Auto-generated method stub
return 0;
}
}));
int maxDepth = tree.accept(new ParseTreeVisitor<Integer>() {
public Integer visitChildren(RuleNode node) {
int depth = 0;
for (int i = 0; i < node.getChildCount(); i++) {
depth = Math.max(depth, node.getChild(i).accept(this));
}
node.getRuleContext().setAltNumber(depth);
return depth + 1;
}
@Override
public Integer visit(ParseTree tree) {
return 1;
}
@Override
public Integer visitTerminal(TerminalNode node) {
return 1;
}
/**
* We found a number: push it onto the stack
*/
@Override
public void enterNumExpr(NumExprContext ctx) {
int num = Integer.parseInt(ctx.getText());
stack.push(num);
System.out.printf("%s%d%n", " ".repeat(ctx.depth()), num);
public Integer visitErrorNode(ErrorNode node) {
return 1;
}
});
String sourceName = tokens.getSourceName() == TokenStream.UNKNOWN_SOURCE_NAME ? "" : URLEncoder.encode(tokens.getSourceName(),StandardCharsets.UTF_8);
System.out.println(tree.accept(new ParseTreeVisitor<String>() {
String indent = "";
private String makeSourceRef(ParseTree tree) {
Interval interval = tree.getSourceInterval();
int tokStart = interval.a, tokEnd = interval.b;
if (tokStart <= tokEnd) {
int charStart = tokens.get(tokStart).getStartIndex();
int charEnd = tokens.get(tokEnd).getStopIndex();
String range = "";
if(charStart > charEnd)
return "";
else if (charStart == charEnd)
range += charStart;
else if (charStart < charEnd)
range += charStart + "-" + charEnd;
return String.format("href=\"%s\"", uri.resolve("#"+range).toString());
}
return "";
}
/**
* We found an identifer: not sure what to do with that
*/
@Override
public void enterIdExpr(IdExprContext ctx) {
System.out.println("TODO: ID=" + ctx.getText());
public String visit(ParseTree tree) {
System.out.println("visit: " + tree);
return null;
}
@Override
public String visitChildren(RuleNode node) {
// TODO Auto-generated method stub
RuleContext ctx = node.getRuleContext();
String localIndent = " ".repeat(ctx.depth());
indent = localIndent;
String body = "";
for (int i = 0; i < node.getChildCount(); i++) {
body += String.format("%s", node.getChild(i).accept(this));
}
String rule = ctx.getClass().getSimpleName().replaceFirst("Context$", ""); // ExprParser.ruleNames[ctx.getRuleIndex()];
return String.format(
"%s<node %s symbol=\"%s\" style=\"background-color:hsl(%d,70%%,90%%,50%%)\">\n%s%s</node>\n", //
localIndent, //
makeSourceRef(node), //
rule, //
ctx.getAltNumber() * 360 / maxDepth, body, localIndent);
}
/**
* We're finished with a plus expression; pop two values, add them and push the result
*/
@Override
public void exitPlusExpr(PlusExprContext ctx) {
int a = stack.pop();
int b = stack.pop();
System.out.printf("%s%d = %d + %d%n", " ".repeat(ctx.depth()), a + b, a, b);
stack.push(a + b);
public String visitTerminal(TerminalNode node) {
String symbolName = ExprLexer.VOCABULARY.getDisplayName(node.getSymbol().getType());
String text = node.getText();
return String.format(
"%s <leaf %s symbol=\"%s\" style=\"background-color:hsl(0,70%%,90%%,50%%)\">%s</leaf>\n", //
indent, //
makeSourceRef(node), //
StringEscapeUtils.escapeHtml4(symbolName+"\"'"), StringEscapeUtils.escapeHtml4(text));
}
/**
* End of the program; pop the result and print it
*/
@Override
public void exitProgram(ProgramContext ctx) {
System.out.println("Result: " + stack.pop());
public String visitErrorNode(ErrorNode node) {
String symbolName = ExprLexer.VOCABULARY.getDisplayName(node.getSymbol().getType());
System.out.println("error: " + node.getSymbol());
return String.format(
"%s <error symbol=\"%s\" style=\"background-color:hsl(0,100%%,60%%,50%%)\">%s</error>\n",
indent, StringEscapeUtils.escapeHtml4(symbolName),
StringEscapeUtils.escapeHtml4(node.getText()));
}
}, tree);
}));
// HelloExample.dumpParseTree(tree, parser);
//
// ParseTreeWalker walker = new ParseTreeWalker();
//
// // grammar-specific walk: evaluate the expression using a stack
// walker.walk(new ExprBaseListener() {
// Deque<Integer> stack = new LinkedList<>();
// Deque<TreeNode> stack2 = new LinkedList<>();
//
// /**
// * We found a number: push it onto the stack
// */
// @Override
// public void enterNumExpr(NumExprContext ctx) {
// int num = Integer.parseInt(ctx.getText());
// stack.push(num);
// Token token = ctx.NUM().getSymbol();
// String pos = String.format("%s:%d-%d", //
// token.getTokenSource().getSourceName(), //
// token.getStartIndex(), token.getStopIndex());
// stack2.push(new TreeNode(ctx.getText(), pos));
// System.out.printf("%s%d%n", " ".repeat(ctx.depth()), num);
//
// }
//
// /**
// * We found an identifer: not sure what to do with that
// */
// @Override
// public void enterIdExpr(IdExprContext ctx) {
// Token token = ctx.ID().getSymbol();
// String pos = String.format("%s:%d-%d", //
// token.getTokenSource().getSourceName(), //
// token.getStartIndex(), token.getStopIndex());
// stack2.push(new TreeNode(ctx.getText(), pos));
// System.out.println("TODO: ID=" + ctx.getText());
// }
//
//
// /**
// * We're finished with a plus expression; pop two values, add them and push the result
// */
// @Override
// public void exitPlusExpr(PlusExprContext ctx) {
// int a = stack.pop();
// int b = stack.pop();
// System.out.printf("%s%d = %d + %d%n", " ".repeat(ctx.depth()), a + b, a, b);
// stack.push(a + b);
// String pos = String.format("%s:%d-%d", //
// ctx.getStart().getTokenSource().getSourceName(), //
// ctx.getStart().getStartIndex(), ctx.getStop().getStopIndex());
// TreeNode e2 = stack2.pop();
// TreeNode e1 = stack2.pop();
// stack2.push(new TreeNode("+", pos, e1, e2));
// }
// @Override
// public void exitMultExpr(MultExprContext ctx) {
// int a = stack.pop();
// int b = stack.pop();
// System.out.printf("%s%d = %d * %d%n", " ".repeat(ctx.depth()), a * b, a, b);
// stack.push(a * b);
// String pos = String.format("%s:%d-%d", //
// ctx.getStart().getTokenSource().getSourceName(), //
// ctx.getStart().getStartIndex(), ctx.getStop().getStopIndex());
// TreeNode e2 = stack2.pop();
// TreeNode e1 = stack2.pop();
// stack2.push(new TreeNode("*", pos, e1, e2));
// }
//
// /**
// * End of the program; pop the result and print it
// */
// @Override
// public void exitProgram(ProgramContext ctx) {
// System.out.println("Result: " + stack.pop());
// TreeNode tree = stack2.pop();
// double scale = 50;
// tree.layout(0, 0.5);
// System.out.println("<style>\n" +
// "text {\n" +
// "text-anchor:middle;dominant-baseline:middle;fill:black;\n" +
// "}\n" +
// "circle, line { fill:none; stroke:black; stroke-width:1; }\n" +
// "</style>");
// System.out.printf("<svg width=\"500\" height=\"500\" viewbox=\"%.2f %.2f %.2f %.2f\">%n%s</svg>", //
// -tree.width * scale, 0.0, 2*tree.width* scale, 2*tree.width* scale, tree.toSVG(scale));
// }
// }, tree);
// }
//
// public void test() {
// for(String s : Arrays.asList("s")) {
// System.out.println(s);
// }
// // →
// for(Iterator<String> iterator = Arrays.asList("s").iterator();
// iterator.hasNext(); ) {
// String s = iterator.next();
//
// System.out.println(s);
// }
//
// }
}
}
......@@ -36,6 +36,8 @@ public class HelloExample {
for (Token t : tokens.getTokens())
System.out.printf("%-10s #%d, offset=%2d–%2d, line=%d, column=%2d, source=%s%n", t.getText(), t.getTokenIndex(),
t.getStartIndex(), t.getStopIndex(), t.getLine(), t.getCharPositionInLine(), t.getTokenSource().getSourceName());
// System.exit(0);
// the parser that recovers the tree structure from the token stream
HelloParser parser = new HelloParser(tokens);
// the parse tree of the non-terminal we're interested in
......@@ -111,7 +113,7 @@ public class HelloExample {
@Override
public void visitErrorNode(ErrorNode node) {
System.out.println(" ".repeat(nest + 1) + node);
System.out.println(" ".repeat(nest + 1) + "ERROR:" + node);
}
@Override
......
package inf225.examples;
import org.antlr.v4.runtime.ParserRuleContext;
/*
* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
* Use of this file is governed by the BSD 3-clause license that
* can be found in the LICENSE.txt file in the project root.
*/
import org.antlr.v4.runtime.atn.ATN;
/** A handy class for use with
*
* options {contextSuperClass=org.antlr.v4.runtime.RuleContextWithAltNum;}
*
* that provides a backing field / impl for the outer alternative number
* matched for an internal parse tree node.
*
* I'm only putting into Java runtime as I'm certain I'm the only one that
* will really every use this.
*/
public class RuleContextWithAltNum extends ParserRuleContext {
public int altNum;
public RuleContextWithAltNum() { altNum = ATN.INVALID_ALT_NUMBER; }
public RuleContextWithAltNum(ParserRuleContext parent, int invokingStateNumber) {
super(parent, invokingStateNumber);
}
@Override public int getAltNumber() { return altNum; }
@Override public void setAltNumber(int altNum) { this.altNum = altNum; }
@Override public void copyFrom(ParserRuleContext ctx) {super.copyFrom(ctx); this.altNum = ctx.getAltNumber();}
}
package inf225.examples;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class TreeNode {
String label;
String loc;
String id;
double xPos, yPos;
double width;
List<TreeNode> children = new ArrayList<>();
public TreeNode(String label, String loc, TreeNode...nodes) {
this.label = label;
this.loc = loc;
this.children.addAll(Arrays.asList(nodes));
for(TreeNode child : children) {
width += child.width;
}
width = Math.max(width, 1);
}
public void layout(double x, double y) {
xPos = x;
yPos = y;
if(children.size() == 1) {
children.get(0).layout(x, y+1);
} else if(children.size() > 1) {
double off = -width / 2.0;
double step = width / (children.size()-1.0);
for(TreeNode child : children) {
child.layout(off, 1);
off += step;
}
}
}
public String toSVG(double scale) {
return toSVG(scale, 1, "t");
}
public String toSVG(double scale, int depth, String id) {
double r = .25;
String indent = " ".repeat(depth);
String s = String.format("%s<g id=\"%s\" aria-labelledby=\"%s-text\" transform=\"translate(%.2f,%.2f)\">\n", indent, id, id, xPos*scale/2, yPos*scale);
if(loc != null)
s+=String.format(" %s<title>%s</title>\n", indent,loc.replace("&", "&amp;").replace("<", "&lt;").replace(">", "&gt;"));
// s += String.format("<!-- TreeNode(\"%s\",…,x=%.2f,y=%.2f,w=%.2f) -->\n",
// label, xPos,yPos, width);
s += String.format(" %s<circle r=\"%.2f\" />%n", indent, r*scale);
s += String.format(" %s<text id=\"%s-text\">%s</text>%n", indent, label, id);
// s += String.format(" %s<circle cx=\"%.2f\" cy=\"%.2f\" r=\"%.2f\" />%n",
// indent, 0*xPos*scale/2, 0*yPos*scale, r*scale);
// s += String.format(" %s<text x=\"%.2f\" y=\"%.2f\">%s</text>%n", //
// indent, 0*xPos*scale/2, 0*yPos*scale, label);
int i = 1;
for(TreeNode child : children) {
s += child.toSVG(scale, depth+1, String.format("%s.%d", id, i++));
s += String.format(" %s<line x1=\"%.1f\" y1=\"%.1f\" x2=\"%.1f\" y2=\"%.1f\" />%n", //
indent, 0*xPos*scale/2, (0*yPos+r)*scale, //
child.xPos*scale/2, (child.yPos-r)*scale);
}
s += indent + "</g>\n";
return s;
}
}
\ No newline at end of file
node, leaf, error {
align-items:center;
text-align:center;
vertical-align:top;
display:inline-block;
margin-bottom: 2px;
padding:2px;
border-width: 1px;
border-style:solid;
border-color: #8888;
}
error {
color:#f00;
border-color:#f00;
background-color: #ccc;
}
node > node {
margin-top: -3px;
}
node:after {
content: attr(symbol);
display:block;
font-size:7px;
color:#000d
}
leaf:before, error:before {
content: attr(symbol);
display:block;
font-size:7px;
color:#000c
}
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment