| @@ -0,0 +1,58 @@ | ||
| package lang.ast; | ||
|
|
||
| import java.util.ArrayList; | ||
| import java.io.ByteArrayOutputStream; | ||
| import java.io.PrintStream; | ||
| import java.lang.reflect.InvocationTargetException; | ||
| import java.util.Set; | ||
| import java.util.TreeSet; | ||
| /** | ||
| * @ast class | ||
| * @declaredat ASTNode:213 | ||
| */ | ||
| public class ASTNodeAnnotation extends java.lang.Object { | ||
|
|
||
| @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.RUNTIME) | ||
| @java.lang.annotation.Target(java.lang.annotation.ElementType.METHOD) | ||
| @java.lang.annotation.Documented | ||
| public @interface Child { | ||
| String name(); | ||
| } | ||
|
|
||
|
|
||
|
|
||
| @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.RUNTIME) | ||
| @java.lang.annotation.Target(java.lang.annotation.ElementType.METHOD) | ||
| @java.lang.annotation.Documented | ||
| public @interface ListChild { | ||
| String name(); | ||
| } | ||
|
|
||
|
|
||
|
|
||
| @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.RUNTIME) | ||
| @java.lang.annotation.Target(java.lang.annotation.ElementType.METHOD) | ||
| @java.lang.annotation.Documented | ||
| public @interface OptChild { | ||
| String name(); | ||
| } | ||
|
|
||
|
|
||
|
|
||
| @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.RUNTIME) | ||
| @java.lang.annotation.Target(java.lang.annotation.ElementType.METHOD) | ||
| @java.lang.annotation.Documented | ||
| public @interface Token { | ||
| String name(); | ||
| } | ||
|
|
||
|
|
||
|
|
||
| @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.RUNTIME) | ||
| @java.lang.annotation.Target(java.lang.annotation.ElementType.METHOD) | ||
| @java.lang.annotation.Documented | ||
| public @interface Attribute { | ||
| } | ||
|
|
||
|
|
||
| } |
| @@ -0,0 +1,146 @@ | ||
| /* This file was generated with JastAdd2 (http://jastadd.org) version 2.1.13 */ | ||
| package lang.ast; | ||
|
|
||
| import java.util.ArrayList; | ||
| import java.io.ByteArrayOutputStream; | ||
| import java.io.PrintStream; | ||
| import java.lang.reflect.InvocationTargetException; | ||
| import java.util.Set; | ||
| import java.util.TreeSet; | ||
| /** | ||
| * @ast node | ||
| * @declaredat /h/dk/r/ada10dlu/edan65/CalcASM/src/jastadd/calc.ast:17 | ||
| * @production Ask : {@link Expr}; | ||
| */ | ||
| public class Ask extends Expr implements Cloneable { | ||
| /** | ||
| * @aspect CodeGen | ||
| * @declaredat /h/dk/r/ada10dlu/edan65/CalcASM/src/jastadd/CodeGen.jrag:155 | ||
| */ | ||
| public void genEval(PrintStream out) { | ||
| out.println(" pushq ask_msg_len"); | ||
| out.println(" pushq $ask_message"); | ||
| out.println(" call print_string"); | ||
| out.println(" addq $16, %rsp"); | ||
| out.println(" call read"); | ||
| } | ||
| /** | ||
| * @aspect PrettyPrint | ||
| * @declaredat /h/dk/r/ada10dlu/edan65/CalcASM/src/jastadd/PrettyPrint.jrag:59 | ||
| */ | ||
| public void prettyPrint(PrintStream out, String ind) { | ||
| out.print("ask user"); | ||
| } | ||
| /** | ||
| * @declaredat ASTNode:1 | ||
| */ | ||
| public Ask() { | ||
| super(); | ||
| } | ||
| /** | ||
| * Initializes the child array to the correct size. | ||
| * Initializes List and Opt nta children. | ||
| * @apilevel internal | ||
| * @ast method | ||
| * @declaredat ASTNode:10 | ||
| */ | ||
| public void init$Children() { | ||
| } | ||
| /** | ||
| * @apilevel low-level | ||
| * @declaredat ASTNode:15 | ||
| */ | ||
| protected int numChildren() { | ||
| return 0; | ||
| } | ||
| /** | ||
| * @apilevel internal | ||
| * @declaredat ASTNode:21 | ||
| */ | ||
| public void flushAttrCache() { | ||
| super.flushAttrCache(); | ||
| } | ||
| /** | ||
| * @apilevel internal | ||
| * @declaredat ASTNode:27 | ||
| */ | ||
| public void flushCollectionCache() { | ||
| super.flushCollectionCache(); | ||
| } | ||
| /** | ||
| * @apilevel internal | ||
| * @declaredat ASTNode:33 | ||
| */ | ||
| public Ask clone() throws CloneNotSupportedException { | ||
| Ask node = (Ask) super.clone(); | ||
| return node; | ||
| } | ||
| /** | ||
| * @apilevel internal | ||
| * @declaredat ASTNode:40 | ||
| */ | ||
| public Ask copy() { | ||
| try { | ||
| Ask node = (Ask) clone(); | ||
| node.parent = null; | ||
| if (children != null) { | ||
| node.children = (ASTNode[]) children.clone(); | ||
| } | ||
| return node; | ||
| } catch (CloneNotSupportedException e) { | ||
| throw new Error("Error: clone not supported for " + getClass().getName()); | ||
| } | ||
| } | ||
| /** | ||
| * Create a deep copy of the AST subtree at this node. | ||
| * The copy is dangling, i.e. has no parent. | ||
| * @return dangling copy of the subtree at this node | ||
| * @apilevel low-level | ||
| * @deprecated Please use treeCopy or treeCopyNoTransform instead | ||
| * @declaredat ASTNode:59 | ||
| */ | ||
| @Deprecated | ||
| public Ask fullCopy() { | ||
| return treeCopyNoTransform(); | ||
| } | ||
| /** | ||
| * Create a deep copy of the AST subtree at this node. | ||
| * The copy is dangling, i.e. has no parent. | ||
| * @return dangling copy of the subtree at this node | ||
| * @apilevel low-level | ||
| * @declaredat ASTNode:69 | ||
| */ | ||
| public Ask treeCopyNoTransform() { | ||
| Ask tree = (Ask) copy(); | ||
| if (children != null) { | ||
| for (int i = 0; i < children.length; ++i) { | ||
| ASTNode child = (ASTNode) children[i]; | ||
| if (child != null) { | ||
| child = child.treeCopyNoTransform(); | ||
| tree.setChild(child, i); | ||
| } | ||
| } | ||
| } | ||
| return tree; | ||
| } | ||
| /** | ||
| * Create a deep copy of the AST subtree at this node. | ||
| * The subtree of this node is traversed to trigger rewrites before copy. | ||
| * The copy is dangling, i.e. has no parent. | ||
| * @return dangling copy of the subtree at this node | ||
| * @apilevel low-level | ||
| * @declaredat ASTNode:89 | ||
| */ | ||
| public Ask treeCopy() { | ||
| doFullTraversal(); | ||
| return treeCopyNoTransform(); | ||
| } | ||
| /** | ||
| * @apilevel internal | ||
| * @declaredat ASTNode:96 | ||
| */ | ||
| protected boolean is$Equal(ASTNode node) { | ||
| return super.is$Equal(node); | ||
| } | ||
| } |
| @@ -0,0 +1,148 @@ | ||
| /* This file was generated with JastAdd2 (http://jastadd.org) version 2.1.13 */ | ||
| package lang.ast; | ||
|
|
||
| import java.util.ArrayList; | ||
| import java.io.ByteArrayOutputStream; | ||
| import java.io.PrintStream; | ||
| import java.lang.reflect.InvocationTargetException; | ||
| import java.util.Set; | ||
| import java.util.TreeSet; | ||
| /** | ||
| * @ast node | ||
| * @declaredat /h/dk/r/ada10dlu/edan65/CalcASM/src/jastadd/calc.ast:4 | ||
| * @production BinExpr : {@link Expr} ::= <span class="component">Left:{@link Expr}</span> <span class="component">Right:{@link Expr}</span>; | ||
| */ | ||
| public abstract class BinExpr extends Expr implements Cloneable { | ||
| /** | ||
| * @declaredat ASTNode:1 | ||
| */ | ||
| public BinExpr() { | ||
| super(); | ||
| } | ||
| /** | ||
| * Initializes the child array to the correct size. | ||
| * Initializes List and Opt nta children. | ||
| * @apilevel internal | ||
| * @ast method | ||
| * @declaredat ASTNode:10 | ||
| */ | ||
| public void init$Children() { | ||
| children = new ASTNode[2]; | ||
| } | ||
| /** | ||
| * @declaredat ASTNode:13 | ||
| */ | ||
| public BinExpr(Expr p0, Expr p1) { | ||
| setChild(p0, 0); | ||
| setChild(p1, 1); | ||
| } | ||
| /** | ||
| * @apilevel low-level | ||
| * @declaredat ASTNode:20 | ||
| */ | ||
| protected int numChildren() { | ||
| return 2; | ||
| } | ||
| /** | ||
| * @apilevel internal | ||
| * @declaredat ASTNode:26 | ||
| */ | ||
| public void flushAttrCache() { | ||
| super.flushAttrCache(); | ||
| } | ||
| /** | ||
| * @apilevel internal | ||
| * @declaredat ASTNode:32 | ||
| */ | ||
| public void flushCollectionCache() { | ||
| super.flushCollectionCache(); | ||
| } | ||
| /** | ||
| * @apilevel internal | ||
| * @declaredat ASTNode:38 | ||
| */ | ||
| public BinExpr clone() throws CloneNotSupportedException { | ||
| BinExpr node = (BinExpr) super.clone(); | ||
| return node; | ||
| } | ||
| /** | ||
| * Create a deep copy of the AST subtree at this node. | ||
| * The copy is dangling, i.e. has no parent. | ||
| * @return dangling copy of the subtree at this node | ||
| * @apilevel low-level | ||
| * @deprecated Please use treeCopy or treeCopyNoTransform instead | ||
| * @declaredat ASTNode:49 | ||
| */ | ||
| @Deprecated | ||
| public abstract BinExpr fullCopy(); | ||
| /** | ||
| * Create a deep copy of the AST subtree at this node. | ||
| * The copy is dangling, i.e. has no parent. | ||
| * @return dangling copy of the subtree at this node | ||
| * @apilevel low-level | ||
| * @declaredat ASTNode:57 | ||
| */ | ||
| public abstract BinExpr treeCopyNoTransform(); | ||
| /** | ||
| * Create a deep copy of the AST subtree at this node. | ||
| * The subtree of this node is traversed to trigger rewrites before copy. | ||
| * The copy is dangling, i.e. has no parent. | ||
| * @return dangling copy of the subtree at this node | ||
| * @apilevel low-level | ||
| * @declaredat ASTNode:65 | ||
| */ | ||
| public abstract BinExpr treeCopy(); | ||
| /** | ||
| * Replaces the Left child. | ||
| * @param node The new node to replace the Left child. | ||
| * @apilevel high-level | ||
| */ | ||
| public void setLeft(Expr node) { | ||
| setChild(node, 0); | ||
| } | ||
| /** | ||
| * Retrieves the Left child. | ||
| * @return The current node used as the Left child. | ||
| * @apilevel high-level | ||
| */ | ||
| @ASTNodeAnnotation.Child(name="Left") | ||
| public Expr getLeft() { | ||
| return (Expr) getChild(0); | ||
| } | ||
| /** | ||
| * Retrieves the Left child. | ||
| * <p><em>This method does not invoke AST transformations.</em></p> | ||
| * @return The current node used as the Left child. | ||
| * @apilevel low-level | ||
| */ | ||
| public Expr getLeftNoTransform() { | ||
| return (Expr) getChildNoTransform(0); | ||
| } | ||
| /** | ||
| * Replaces the Right child. | ||
| * @param node The new node to replace the Right child. | ||
| * @apilevel high-level | ||
| */ | ||
| public void setRight(Expr node) { | ||
| setChild(node, 1); | ||
| } | ||
| /** | ||
| * Retrieves the Right child. | ||
| * @return The current node used as the Right child. | ||
| * @apilevel high-level | ||
| */ | ||
| @ASTNodeAnnotation.Child(name="Right") | ||
| public Expr getRight() { | ||
| return (Expr) getChild(1); | ||
| } | ||
| /** | ||
| * Retrieves the Right child. | ||
| * <p><em>This method does not invoke AST transformations.</em></p> | ||
| * @return The current node used as the Right child. | ||
| * @apilevel low-level | ||
| */ | ||
| public Expr getRightNoTransform() { | ||
| return (Expr) getChildNoTransform(1); | ||
| } | ||
| } |
| @@ -0,0 +1,264 @@ | ||
| /* This file was generated with JastAdd2 (http://jastadd.org) version 2.1.13 */ | ||
| package lang.ast; | ||
|
|
||
| import java.util.ArrayList; | ||
| import java.io.ByteArrayOutputStream; | ||
| import java.io.PrintStream; | ||
| import java.lang.reflect.InvocationTargetException; | ||
| import java.util.Set; | ||
| import java.util.TreeSet; | ||
| /** | ||
| * @ast node | ||
| * @declaredat /h/dk/r/ada10dlu/edan65/CalcASM/src/jastadd/calc.ast:13 | ||
| * @production Binding : {@link ASTNode} ::= <span class="component">{@link IdDecl}</span> <span class="component">{@link Expr}</span>; | ||
| */ | ||
| public class Binding extends ASTNode<ASTNode> implements Cloneable { | ||
| /** | ||
| * @aspect CodeGen | ||
| * @declaredat /h/dk/r/ada10dlu/edan65/CalcASM/src/jastadd/CodeGen.jrag:163 | ||
| */ | ||
| public void genCode(PrintStream out) { | ||
| getExpr().genEval(out); | ||
| out.println(" movq %rax, " + getIdDecl().address()); | ||
| } | ||
| /** | ||
| * @aspect PrettyPrint | ||
| * @declaredat /h/dk/r/ada10dlu/edan65/CalcASM/src/jastadd/PrettyPrint.jrag:53 | ||
| */ | ||
| public void prettyPrint(PrintStream out, String ind) { | ||
| getIdDecl().prettyPrint(out, ind); | ||
| out.append(" = "); | ||
| getExpr().prettyPrint(out, ind+" "); | ||
| } | ||
| /** | ||
| * @declaredat ASTNode:1 | ||
| */ | ||
| public Binding() { | ||
| super(); | ||
| } | ||
| /** | ||
| * Initializes the child array to the correct size. | ||
| * Initializes List and Opt nta children. | ||
| * @apilevel internal | ||
| * @ast method | ||
| * @declaredat ASTNode:10 | ||
| */ | ||
| public void init$Children() { | ||
| children = new ASTNode[2]; | ||
| } | ||
| /** | ||
| * @declaredat ASTNode:13 | ||
| */ | ||
| public Binding(IdDecl p0, Expr p1) { | ||
| setChild(p0, 0); | ||
| setChild(p1, 1); | ||
| } | ||
| /** | ||
| * @apilevel low-level | ||
| * @declaredat ASTNode:20 | ||
| */ | ||
| protected int numChildren() { | ||
| return 2; | ||
| } | ||
| /** | ||
| * @apilevel internal | ||
| * @declaredat ASTNode:26 | ||
| */ | ||
| public void flushAttrCache() { | ||
| super.flushAttrCache(); | ||
| inExprOf_IdDecl_reset(); | ||
| } | ||
| /** | ||
| * @apilevel internal | ||
| * @declaredat ASTNode:33 | ||
| */ | ||
| public void flushCollectionCache() { | ||
| super.flushCollectionCache(); | ||
| } | ||
| /** | ||
| * @apilevel internal | ||
| * @declaredat ASTNode:39 | ||
| */ | ||
| public Binding clone() throws CloneNotSupportedException { | ||
| Binding node = (Binding) super.clone(); | ||
| return node; | ||
| } | ||
| /** | ||
| * @apilevel internal | ||
| * @declaredat ASTNode:46 | ||
| */ | ||
| public Binding copy() { | ||
| try { | ||
| Binding node = (Binding) clone(); | ||
| node.parent = null; | ||
| if (children != null) { | ||
| node.children = (ASTNode[]) children.clone(); | ||
| } | ||
| return node; | ||
| } catch (CloneNotSupportedException e) { | ||
| throw new Error("Error: clone not supported for " + getClass().getName()); | ||
| } | ||
| } | ||
| /** | ||
| * Create a deep copy of the AST subtree at this node. | ||
| * The copy is dangling, i.e. has no parent. | ||
| * @return dangling copy of the subtree at this node | ||
| * @apilevel low-level | ||
| * @deprecated Please use treeCopy or treeCopyNoTransform instead | ||
| * @declaredat ASTNode:65 | ||
| */ | ||
| @Deprecated | ||
| public Binding fullCopy() { | ||
| return treeCopyNoTransform(); | ||
| } | ||
| /** | ||
| * Create a deep copy of the AST subtree at this node. | ||
| * The copy is dangling, i.e. has no parent. | ||
| * @return dangling copy of the subtree at this node | ||
| * @apilevel low-level | ||
| * @declaredat ASTNode:75 | ||
| */ | ||
| public Binding treeCopyNoTransform() { | ||
| Binding tree = (Binding) copy(); | ||
| if (children != null) { | ||
| for (int i = 0; i < children.length; ++i) { | ||
| ASTNode child = (ASTNode) children[i]; | ||
| if (child != null) { | ||
| child = child.treeCopyNoTransform(); | ||
| tree.setChild(child, i); | ||
| } | ||
| } | ||
| } | ||
| return tree; | ||
| } | ||
| /** | ||
| * Create a deep copy of the AST subtree at this node. | ||
| * The subtree of this node is traversed to trigger rewrites before copy. | ||
| * The copy is dangling, i.e. has no parent. | ||
| * @return dangling copy of the subtree at this node | ||
| * @apilevel low-level | ||
| * @declaredat ASTNode:95 | ||
| */ | ||
| public Binding treeCopy() { | ||
| doFullTraversal(); | ||
| return treeCopyNoTransform(); | ||
| } | ||
| /** | ||
| * @apilevel internal | ||
| * @declaredat ASTNode:102 | ||
| */ | ||
| protected boolean is$Equal(ASTNode node) { | ||
| return super.is$Equal(node); | ||
| } | ||
| /** | ||
| * Replaces the IdDecl child. | ||
| * @param node The new node to replace the IdDecl child. | ||
| * @apilevel high-level | ||
| */ | ||
| public void setIdDecl(IdDecl node) { | ||
| setChild(node, 0); | ||
| } | ||
| /** | ||
| * Retrieves the IdDecl child. | ||
| * @return The current node used as the IdDecl child. | ||
| * @apilevel high-level | ||
| */ | ||
| @ASTNodeAnnotation.Child(name="IdDecl") | ||
| public IdDecl getIdDecl() { | ||
| return (IdDecl) getChild(0); | ||
| } | ||
| /** | ||
| * Retrieves the IdDecl child. | ||
| * <p><em>This method does not invoke AST transformations.</em></p> | ||
| * @return The current node used as the IdDecl child. | ||
| * @apilevel low-level | ||
| */ | ||
| public IdDecl getIdDeclNoTransform() { | ||
| return (IdDecl) getChildNoTransform(0); | ||
| } | ||
| /** | ||
| * Replaces the Expr child. | ||
| * @param node The new node to replace the Expr child. | ||
| * @apilevel high-level | ||
| */ | ||
| public void setExpr(Expr node) { | ||
| setChild(node, 1); | ||
| } | ||
| /** | ||
| * Retrieves the Expr child. | ||
| * @return The current node used as the Expr child. | ||
| * @apilevel high-level | ||
| */ | ||
| @ASTNodeAnnotation.Child(name="Expr") | ||
| public Expr getExpr() { | ||
| return (Expr) getChild(1); | ||
| } | ||
| /** | ||
| * Retrieves the Expr child. | ||
| * <p><em>This method does not invoke AST transformations.</em></p> | ||
| * @return The current node used as the Expr child. | ||
| * @apilevel low-level | ||
| */ | ||
| public Expr getExprNoTransform() { | ||
| return (Expr) getChildNoTransform(1); | ||
| } | ||
| /** | ||
| * @attribute inh | ||
| * @aspect CircularDefinitions | ||
| * @declaredat /h/dk/r/ada10dlu/edan65/CalcASM/src/jastadd/NameAnalysis.jrag:34 | ||
| */ | ||
| @ASTNodeAnnotation.Attribute | ||
| public boolean inExprOf(IdDecl decl) { | ||
| Object _parameters = decl; | ||
| if (inExprOf_IdDecl_visited == null) inExprOf_IdDecl_visited = new java.util.HashSet(4); | ||
| if (inExprOf_IdDecl_values == null) inExprOf_IdDecl_values = new java.util.HashMap(4); | ||
| ASTNode$State state = state(); | ||
| if (inExprOf_IdDecl_values.containsKey(_parameters)) { | ||
| return (Boolean) inExprOf_IdDecl_values.get(_parameters); | ||
| } | ||
| if (inExprOf_IdDecl_visited.contains(_parameters)) { | ||
| throw new RuntimeException("Circular definition of attr: inExprOf in class: org.jastadd.ast.AST.InhDecl"); | ||
| } | ||
| inExprOf_IdDecl_visited.add(_parameters); | ||
| boolean intermediate = state.INTERMEDIATE_VALUE; | ||
| state.INTERMEDIATE_VALUE = false; | ||
| boolean inExprOf_IdDecl_value = getParent().Define_inExprOf(this, null, decl); | ||
| if (true) { | ||
| inExprOf_IdDecl_values.put(_parameters, inExprOf_IdDecl_value); | ||
| } else { | ||
| } | ||
| state.INTERMEDIATE_VALUE |= intermediate; | ||
|
|
||
| inExprOf_IdDecl_visited.remove(_parameters); | ||
| return inExprOf_IdDecl_value; | ||
| } | ||
| /** | ||
| * @apilevel internal | ||
| */ | ||
| protected java.util.Set inExprOf_IdDecl_visited; | ||
| /** | ||
| * @apilevel internal | ||
| */ | ||
| protected java.util.Map inExprOf_IdDecl_values; | ||
| /** | ||
| * @apilevel internal | ||
| */ | ||
| private void inExprOf_IdDecl_reset() { | ||
| inExprOf_IdDecl_values = null; | ||
| inExprOf_IdDecl_visited = null; | ||
| } | ||
| /** | ||
| * @declaredat /h/dk/r/ada10dlu/edan65/CalcASM/src/jastadd/NameAnalysis.jrag:34 | ||
| * @apilevel internal | ||
| */ | ||
| public boolean Define_inExprOf(ASTNode caller, ASTNode child, IdDecl decl) { | ||
| if (caller == getExprNoTransform()) { | ||
| // @declaredat /h/dk/r/ada10dlu/edan65/CalcASM/src/jastadd/NameAnalysis.jrag:35 | ||
| return getIdDecl() == decl || inExprOf(decl); | ||
| } | ||
| else { | ||
| return getParent().Define_inExprOf(this, caller, decl); | ||
| } | ||
| } | ||
| } |
| @@ -0,0 +1,210 @@ | ||
| /* This file was generated with JastAdd2 (http://jastadd.org) version 2.1.13 */ | ||
| package lang.ast; | ||
|
|
||
| import java.util.ArrayList; | ||
| import java.io.ByteArrayOutputStream; | ||
| import java.io.PrintStream; | ||
| import java.lang.reflect.InvocationTargetException; | ||
| import java.util.Set; | ||
| import java.util.TreeSet; | ||
| /** | ||
| * @ast node | ||
| * @declaredat /h/dk/r/ada10dlu/edan65/CalcASM/src/jastadd/calc.ast:6 | ||
| * @production Div : {@link BinExpr}; | ||
| */ | ||
| public class Div extends BinExpr implements Cloneable { | ||
| /** | ||
| * @aspect CodeGen | ||
| * @declaredat /h/dk/r/ada10dlu/edan65/CalcASM/src/jastadd/CodeGen.jrag:137 | ||
| */ | ||
| public void genEval(PrintStream out) { | ||
| getLeft().genEval(out); | ||
| out.println(" pushq %rax"); | ||
| getRight().genEval(out); | ||
| out.println(" movq %rax, %rbx"); | ||
| out.println(" popq %rax"); | ||
| out.println(" movq $0, %rdx");// NB: clear RDX to prepare division RDX:RAX / RBX | ||
| out.println(" idivq %rbx"); | ||
| } | ||
| /** | ||
| * @aspect PrettyPrint | ||
| * @declaredat /h/dk/r/ada10dlu/edan65/CalcASM/src/jastadd/PrettyPrint.jrag:21 | ||
| */ | ||
| public void prettyPrint(PrintStream out, String ind) { | ||
| getLeft().prettyPrint(out, ind); | ||
| out.print(" / "); | ||
| getRight().prettyPrint(out, ind); | ||
| } | ||
| /** | ||
| * @declaredat ASTNode:1 | ||
| */ | ||
| public Div() { | ||
| super(); | ||
| } | ||
| /** | ||
| * Initializes the child array to the correct size. | ||
| * Initializes List and Opt nta children. | ||
| * @apilevel internal | ||
| * @ast method | ||
| * @declaredat ASTNode:10 | ||
| */ | ||
| public void init$Children() { | ||
| children = new ASTNode[2]; | ||
| } | ||
| /** | ||
| * @declaredat ASTNode:13 | ||
| */ | ||
| public Div(Expr p0, Expr p1) { | ||
| setChild(p0, 0); | ||
| setChild(p1, 1); | ||
| } | ||
| /** | ||
| * @apilevel low-level | ||
| * @declaredat ASTNode:20 | ||
| */ | ||
| protected int numChildren() { | ||
| return 2; | ||
| } | ||
| /** | ||
| * @apilevel internal | ||
| * @declaredat ASTNode:26 | ||
| */ | ||
| public void flushAttrCache() { | ||
| super.flushAttrCache(); | ||
| } | ||
| /** | ||
| * @apilevel internal | ||
| * @declaredat ASTNode:32 | ||
| */ | ||
| public void flushCollectionCache() { | ||
| super.flushCollectionCache(); | ||
| } | ||
| /** | ||
| * @apilevel internal | ||
| * @declaredat ASTNode:38 | ||
| */ | ||
| public Div clone() throws CloneNotSupportedException { | ||
| Div node = (Div) super.clone(); | ||
| return node; | ||
| } | ||
| /** | ||
| * @apilevel internal | ||
| * @declaredat ASTNode:45 | ||
| */ | ||
| public Div copy() { | ||
| try { | ||
| Div node = (Div) clone(); | ||
| node.parent = null; | ||
| if (children != null) { | ||
| node.children = (ASTNode[]) children.clone(); | ||
| } | ||
| return node; | ||
| } catch (CloneNotSupportedException e) { | ||
| throw new Error("Error: clone not supported for " + getClass().getName()); | ||
| } | ||
| } | ||
| /** | ||
| * Create a deep copy of the AST subtree at this node. | ||
| * The copy is dangling, i.e. has no parent. | ||
| * @return dangling copy of the subtree at this node | ||
| * @apilevel low-level | ||
| * @deprecated Please use treeCopy or treeCopyNoTransform instead | ||
| * @declaredat ASTNode:64 | ||
| */ | ||
| @Deprecated | ||
| public Div fullCopy() { | ||
| return treeCopyNoTransform(); | ||
| } | ||
| /** | ||
| * Create a deep copy of the AST subtree at this node. | ||
| * The copy is dangling, i.e. has no parent. | ||
| * @return dangling copy of the subtree at this node | ||
| * @apilevel low-level | ||
| * @declaredat ASTNode:74 | ||
| */ | ||
| public Div treeCopyNoTransform() { | ||
| Div tree = (Div) copy(); | ||
| if (children != null) { | ||
| for (int i = 0; i < children.length; ++i) { | ||
| ASTNode child = (ASTNode) children[i]; | ||
| if (child != null) { | ||
| child = child.treeCopyNoTransform(); | ||
| tree.setChild(child, i); | ||
| } | ||
| } | ||
| } | ||
| return tree; | ||
| } | ||
| /** | ||
| * Create a deep copy of the AST subtree at this node. | ||
| * The subtree of this node is traversed to trigger rewrites before copy. | ||
| * The copy is dangling, i.e. has no parent. | ||
| * @return dangling copy of the subtree at this node | ||
| * @apilevel low-level | ||
| * @declaredat ASTNode:94 | ||
| */ | ||
| public Div treeCopy() { | ||
| doFullTraversal(); | ||
| return treeCopyNoTransform(); | ||
| } | ||
| /** | ||
| * @apilevel internal | ||
| * @declaredat ASTNode:101 | ||
| */ | ||
| protected boolean is$Equal(ASTNode node) { | ||
| return super.is$Equal(node); | ||
| } | ||
| /** | ||
| * Replaces the Left child. | ||
| * @param node The new node to replace the Left child. | ||
| * @apilevel high-level | ||
| */ | ||
| public void setLeft(Expr node) { | ||
| setChild(node, 0); | ||
| } | ||
| /** | ||
| * Retrieves the Left child. | ||
| * @return The current node used as the Left child. | ||
| * @apilevel high-level | ||
| */ | ||
| @ASTNodeAnnotation.Child(name="Left") | ||
| public Expr getLeft() { | ||
| return (Expr) getChild(0); | ||
| } | ||
| /** | ||
| * Retrieves the Left child. | ||
| * <p><em>This method does not invoke AST transformations.</em></p> | ||
| * @return The current node used as the Left child. | ||
| * @apilevel low-level | ||
| */ | ||
| public Expr getLeftNoTransform() { | ||
| return (Expr) getChildNoTransform(0); | ||
| } | ||
| /** | ||
| * Replaces the Right child. | ||
| * @param node The new node to replace the Right child. | ||
| * @apilevel high-level | ||
| */ | ||
| public void setRight(Expr node) { | ||
| setChild(node, 1); | ||
| } | ||
| /** | ||
| * Retrieves the Right child. | ||
| * @return The current node used as the Right child. | ||
| * @apilevel high-level | ||
| */ | ||
| @ASTNodeAnnotation.Child(name="Right") | ||
| public Expr getRight() { | ||
| return (Expr) getChild(1); | ||
| } | ||
| /** | ||
| * Retrieves the Right child. | ||
| * <p><em>This method does not invoke AST transformations.</em></p> | ||
| * @return The current node used as the Right child. | ||
| * @apilevel low-level | ||
| */ | ||
| public Expr getRightNoTransform() { | ||
| return (Expr) getChildNoTransform(1); | ||
| } | ||
| } |
| @@ -0,0 +1,41 @@ | ||
| package lang.ast; | ||
|
|
||
| import java.util.ArrayList; | ||
| import java.io.ByteArrayOutputStream; | ||
| import java.io.PrintStream; | ||
| import java.lang.reflect.InvocationTargetException; | ||
| import java.util.Set; | ||
| import java.util.TreeSet; | ||
| /** | ||
| * @ast class | ||
| * @aspect Errors | ||
| * @declaredat /h/dk/r/ada10dlu/edan65/CalcASM/src/jastadd/Errors.jrag:5 | ||
| */ | ||
| public class ErrorMessage extends java.lang.Object implements Comparable<ErrorMessage> { | ||
|
|
||
| protected final String message; | ||
|
|
||
|
|
||
| protected final int lineNumber; | ||
|
|
||
|
|
||
| public ErrorMessage(String message, int lineNumber) { | ||
| this.message = message; | ||
| this.lineNumber = lineNumber; | ||
| } | ||
|
|
||
|
|
||
| public int compareTo(ErrorMessage other) { | ||
| if (lineNumber == other.lineNumber) { | ||
| return message.compareTo(other.message); | ||
| } | ||
| return Integer.compare(lineNumber, other.lineNumber); | ||
| } | ||
|
|
||
|
|
||
| public String toString() { | ||
| return "Error at line " + lineNumber + ": " + message; | ||
| } | ||
|
|
||
|
|
||
| } |
| @@ -0,0 +1,97 @@ | ||
| /* This file was generated with JastAdd2 (http://jastadd.org) version 2.1.13 */ | ||
| package lang.ast; | ||
|
|
||
| import java.util.ArrayList; | ||
| import java.io.ByteArrayOutputStream; | ||
| import java.io.PrintStream; | ||
| import java.lang.reflect.InvocationTargetException; | ||
| import java.util.Set; | ||
| import java.util.TreeSet; | ||
| /** | ||
| * @ast node | ||
| * @declaredat /h/dk/r/ada10dlu/edan65/CalcASM/src/jastadd/calc.ast:3 | ||
| * @production Expr : {@link ASTNode}; | ||
| */ | ||
| public abstract class Expr extends ASTNode<ASTNode> implements Cloneable { | ||
| /** | ||
| * Generate code to evaluate the expression and | ||
| * store the result in RAX. | ||
| * | ||
| * This must be implemented for every subclass of Expr! | ||
| * @aspect CodeGen | ||
| * @declaredat /h/dk/r/ada10dlu/edan65/CalcASM/src/jastadd/CodeGen.jrag:118 | ||
| */ | ||
| abstract public void genEval(PrintStream out); | ||
| /** | ||
| * @declaredat ASTNode:1 | ||
| */ | ||
| public Expr() { | ||
| super(); | ||
| } | ||
| /** | ||
| * Initializes the child array to the correct size. | ||
| * Initializes List and Opt nta children. | ||
| * @apilevel internal | ||
| * @ast method | ||
| * @declaredat ASTNode:10 | ||
| */ | ||
| public void init$Children() { | ||
| } | ||
| /** | ||
| * @apilevel low-level | ||
| * @declaredat ASTNode:15 | ||
| */ | ||
| protected int numChildren() { | ||
| return 0; | ||
| } | ||
| /** | ||
| * @apilevel internal | ||
| * @declaredat ASTNode:21 | ||
| */ | ||
| public void flushAttrCache() { | ||
| super.flushAttrCache(); | ||
| } | ||
| /** | ||
| * @apilevel internal | ||
| * @declaredat ASTNode:27 | ||
| */ | ||
| public void flushCollectionCache() { | ||
| super.flushCollectionCache(); | ||
| } | ||
| /** | ||
| * @apilevel internal | ||
| * @declaredat ASTNode:33 | ||
| */ | ||
| public Expr clone() throws CloneNotSupportedException { | ||
| Expr node = (Expr) super.clone(); | ||
| return node; | ||
| } | ||
| /** | ||
| * Create a deep copy of the AST subtree at this node. | ||
| * The copy is dangling, i.e. has no parent. | ||
| * @return dangling copy of the subtree at this node | ||
| * @apilevel low-level | ||
| * @deprecated Please use treeCopy or treeCopyNoTransform instead | ||
| * @declaredat ASTNode:44 | ||
| */ | ||
| @Deprecated | ||
| public abstract Expr fullCopy(); | ||
| /** | ||
| * Create a deep copy of the AST subtree at this node. | ||
| * The copy is dangling, i.e. has no parent. | ||
| * @return dangling copy of the subtree at this node | ||
| * @apilevel low-level | ||
| * @declaredat ASTNode:52 | ||
| */ | ||
| public abstract Expr treeCopyNoTransform(); | ||
| /** | ||
| * Create a deep copy of the AST subtree at this node. | ||
| * The subtree of this node is traversed to trigger rewrites before copy. | ||
| * The copy is dangling, i.e. has no parent. | ||
| * @return dangling copy of the subtree at this node | ||
| * @apilevel low-level | ||
| * @declaredat ASTNode:60 | ||
| */ | ||
| public abstract Expr treeCopy(); | ||
| } |
| @@ -0,0 +1,151 @@ | ||
| package lang.ast; | ||
|
|
||
| import beaver.*; | ||
| import java.util.ArrayList; | ||
|
|
||
| /** | ||
| * This class is a LALR parser generated by | ||
| * <a href="http://beaver.sourceforge.net">Beaver</a> v0.9.6.1 | ||
| * from the grammar specification "parser.beaver". | ||
| */ | ||
| public class LangParser extends Parser { | ||
| static public class Terminals { | ||
| static public final short EOF = 0; | ||
| static public final short ID = 1; | ||
| static public final short LET = 2; | ||
| static public final short ASK = 3; | ||
| static public final short NUMERAL = 4; | ||
| static public final short MUL = 5; | ||
| static public final short DIV = 6; | ||
| static public final short ASSIGN = 7; | ||
| static public final short IN = 8; | ||
| static public final short END = 9; | ||
| static public final short USER = 10; | ||
|
|
||
| static public final String[] NAMES = { | ||
| "EOF", | ||
| "ID", | ||
| "LET", | ||
| "ASK", | ||
| "NUMERAL", | ||
| "MUL", | ||
| "DIV", | ||
| "ASSIGN", | ||
| "IN", | ||
| "END", | ||
| "USER" | ||
| }; | ||
| } | ||
|
|
||
| static final ParsingTables PARSING_TABLES = new ParsingTables( | ||
| "U9o5aKjFma0KXKyjAFHbeV8eB5omS67KnEZ261Si#5$#OmKK1H#7CvEXDarDR$BrdlkOtDi" + | ||
| "P00kSeOrZdA238qmmHC2NKYugwJ5QXKuArKSNf#WrUH8ZvF0HMp808GQQPw8SAPUA8#b4tQ" + | ||
| "azbsbsELUl$vIdF$2rOvE7zlRi$eQkDklOUIRo4AWAJ9zXxLpSYPc9gyZcubvSY5jnwV8FT" + | ||
| "VskTYrknADuEkH9lhjwM7VErEMkvEdwqlzcLEQrA$4KplZ3B#wuvISAuxVOSCLNVl2NRpQt" + | ||
| "5cPwgXVnz3Nubb2wJAHRZ7NFcNGctrDF8jqNveK6UxNlIZG="); | ||
|
|
||
| static public class SyntaxError extends RuntimeException { public SyntaxError(String msg) {super(msg);}} | ||
| // Disable syntax error recovery | ||
| protected void recoverFromError(Symbol token, TokenStream in) { | ||
| throw new SyntaxError("Cannot recover from the syntax error"); | ||
| } | ||
|
|
||
| private final Action[] actions; | ||
|
|
||
| public LangParser() { | ||
| super(PARSING_TABLES); | ||
| actions = new Action[] { | ||
| new Action() { // [0] program = exp.a | ||
| public Symbol reduce(Symbol[] _symbols, int offset) { | ||
| final Symbol _symbol_a = _symbols[offset + 1]; | ||
| final Expr a = (Expr) _symbol_a.value; | ||
| return new Program(a); | ||
| } | ||
| }, | ||
| Action.RETURN, // [1] exp = factor | ||
| new Action() { // [2] exp = exp.a MUL factor.b | ||
| public Symbol reduce(Symbol[] _symbols, int offset) { | ||
| final Symbol _symbol_a = _symbols[offset + 1]; | ||
| final Expr a = (Expr) _symbol_a.value; | ||
| final Symbol _symbol_b = _symbols[offset + 3]; | ||
| final Expr b = (Expr) _symbol_b.value; | ||
| return new Mul(a, b); | ||
| } | ||
| }, | ||
| new Action() { // [3] exp = exp.a DIV factor.b | ||
| public Symbol reduce(Symbol[] _symbols, int offset) { | ||
| final Symbol _symbol_a = _symbols[offset + 1]; | ||
| final Expr a = (Expr) _symbol_a.value; | ||
| final Symbol _symbol_b = _symbols[offset + 3]; | ||
| final Expr b = (Expr) _symbol_b.value; | ||
| return new Div(a, b); | ||
| } | ||
| }, | ||
| Action.RETURN, // [4] factor = let | ||
| Action.RETURN, // [5] factor = ask | ||
| Action.RETURN, // [6] factor = numeral | ||
| Action.RETURN, // [7] factor = id_use | ||
| new Action() { // [8] let = LET binding_list.a IN exp.b END | ||
| public Symbol reduce(Symbol[] _symbols, int offset) { | ||
| final Symbol _symbol_a = _symbols[offset + 2]; | ||
| final List a = (List) _symbol_a.value; | ||
| final Symbol _symbol_b = _symbols[offset + 4]; | ||
| final Expr b = (Expr) _symbol_b.value; | ||
| return new Let(a, b); | ||
| } | ||
| }, | ||
| new Action() { // [9] ask = ASK USER | ||
| public Symbol reduce(Symbol[] _symbols, int offset) { | ||
| return new Ask(); | ||
| } | ||
| }, | ||
| new Action() { // [10] binding_list = binding.a | ||
| public Symbol reduce(Symbol[] _symbols, int offset) { | ||
| final Symbol _symbol_a = _symbols[offset + 1]; | ||
| final Binding a = (Binding) _symbol_a.value; | ||
| return new List().add(a); | ||
| } | ||
| }, | ||
| new Action() { // [11] binding_list = binding_list.a binding.b | ||
| public Symbol reduce(Symbol[] _symbols, int offset) { | ||
| final Symbol _symbol_a = _symbols[offset + 1]; | ||
| final List a = (List) _symbol_a.value; | ||
| final Symbol _symbol_b = _symbols[offset + 2]; | ||
| final Binding b = (Binding) _symbol_b.value; | ||
| return a.add(b); | ||
| } | ||
| }, | ||
| new Action() { // [12] binding = id_decl.a ASSIGN exp.b | ||
| public Symbol reduce(Symbol[] _symbols, int offset) { | ||
| final Symbol _symbol_a = _symbols[offset + 1]; | ||
| final IdDecl a = (IdDecl) _symbol_a.value; | ||
| final Symbol _symbol_b = _symbols[offset + 3]; | ||
| final Expr b = (Expr) _symbol_b.value; | ||
| return new Binding(a, b); | ||
| } | ||
| }, | ||
| new Action() { // [13] numeral = NUMERAL.num | ||
| public Symbol reduce(Symbol[] _symbols, int offset) { | ||
| final Symbol num = _symbols[offset + 1]; | ||
| return new Numeral(num); | ||
| } | ||
| }, | ||
| new Action() { // [14] id_decl = ID.id | ||
| public Symbol reduce(Symbol[] _symbols, int offset) { | ||
| final Symbol id = _symbols[offset + 1]; | ||
| return new IdDecl(id); | ||
| } | ||
| }, | ||
| new Action() { // [15] id_use = ID.id | ||
| public Symbol reduce(Symbol[] _symbols, int offset) { | ||
| final Symbol id = _symbols[offset + 1]; | ||
| return new IdUse(id); | ||
| } | ||
| } | ||
| }; | ||
| } | ||
|
|
||
| protected Symbol invokeReduceAction(int rule_num, int offset) { | ||
| return actions[rule_num].reduce(_symbols, offset); | ||
| } | ||
| } |
| @@ -0,0 +1,191 @@ | ||
| /* This file was generated with JastAdd2 (http://jastadd.org) version 2.1.13 */ | ||
| package lang.ast; | ||
|
|
||
| import java.util.ArrayList; | ||
| import java.io.ByteArrayOutputStream; | ||
| import java.io.PrintStream; | ||
| import java.lang.reflect.InvocationTargetException; | ||
| import java.util.Set; | ||
| import java.util.TreeSet; | ||
| /** | ||
| * @ast node | ||
| * @production List : {@link ASTNode}; | ||
| */ | ||
| public class List<T extends ASTNode> extends ASTNode<T> implements Cloneable { | ||
| /** | ||
| * @declaredat ASTNode:1 | ||
| */ | ||
| public List() { | ||
| super(); | ||
| } | ||
| /** | ||
| * Initializes the child array to the correct size. | ||
| * Initializes List and Opt nta children. | ||
| * @apilevel internal | ||
| * @ast method | ||
| * @declaredat ASTNode:10 | ||
| */ | ||
| public void init$Children() { | ||
| } | ||
| /** | ||
| * @declaredat ASTNode:12 | ||
| */ | ||
| public List(T... initialChildren) { | ||
| children = new ASTNode[initialChildren.length]; | ||
| for (int i = 0; i < children.length; ++i) { | ||
| addChild(initialChildren[i]); | ||
| } | ||
| } | ||
| /** | ||
| * @declaredat ASTNode:19 | ||
| */ | ||
| private boolean list$touched = true; | ||
| /** | ||
| * @declaredat ASTNode:21 | ||
| */ | ||
| public List<T> add(T node) { | ||
| addChild(node); | ||
| return this; | ||
| } | ||
| /** | ||
| * @declaredat ASTNode:26 | ||
| */ | ||
| public List<T> addAll(java.util.Collection<? extends T> c) { | ||
| for (T node : c) { | ||
| addChild(node); | ||
| } | ||
| return this; | ||
| } | ||
| /** | ||
| * @declaredat ASTNode:33 | ||
| */ | ||
| public void insertChild(ASTNode node, int i) { | ||
|
|
||
| list$touched = true; | ||
|
|
||
| super.insertChild(node, i); | ||
| } | ||
| /** | ||
| * @declaredat ASTNode:40 | ||
| */ | ||
| public void addChild(T node) { | ||
|
|
||
| list$touched = true; | ||
|
|
||
| super.addChild(node); | ||
| } | ||
| /** | ||
| * @apilevel low-level | ||
| * @declaredat ASTNode:50 | ||
| */ | ||
| public void removeChild(int i) { | ||
|
|
||
| list$touched = true; | ||
|
|
||
| super.removeChild(i); | ||
| } | ||
| /** | ||
| * @declaredat ASTNode:57 | ||
| */ | ||
| public int getNumChild() { | ||
|
|
||
| if (list$touched) { | ||
| for (int i = 0; i < getNumChildNoTransform(); i++) { | ||
| getChild(i); | ||
| } | ||
| list$touched = false; | ||
| } | ||
|
|
||
| return getNumChildNoTransform(); | ||
| } | ||
| /** | ||
| * @apilevel internal | ||
| * @declaredat ASTNode:71 | ||
| */ | ||
| public void flushAttrCache() { | ||
| super.flushAttrCache(); | ||
| } | ||
| /** | ||
| * @apilevel internal | ||
| * @declaredat ASTNode:77 | ||
| */ | ||
| public void flushCollectionCache() { | ||
| super.flushCollectionCache(); | ||
| } | ||
| /** | ||
| * @apilevel internal | ||
| * @declaredat ASTNode:83 | ||
| */ | ||
| public List<T> clone() throws CloneNotSupportedException { | ||
| List node = (List) super.clone(); | ||
| return node; | ||
| } | ||
| /** | ||
| * @apilevel internal | ||
| * @declaredat ASTNode:90 | ||
| */ | ||
| public List<T> copy() { | ||
| try { | ||
| List node = (List) clone(); | ||
| node.parent = null; | ||
| if (children != null) { | ||
| node.children = (ASTNode[]) children.clone(); | ||
| } | ||
| return node; | ||
| } catch (CloneNotSupportedException e) { | ||
| throw new Error("Error: clone not supported for " + getClass().getName()); | ||
| } | ||
| } | ||
| /** | ||
| * Create a deep copy of the AST subtree at this node. | ||
| * The copy is dangling, i.e. has no parent. | ||
| * @return dangling copy of the subtree at this node | ||
| * @apilevel low-level | ||
| * @deprecated Please use treeCopy or treeCopyNoTransform instead | ||
| * @declaredat ASTNode:109 | ||
| */ | ||
| @Deprecated | ||
| public List<T> fullCopy() { | ||
| return treeCopyNoTransform(); | ||
| } | ||
| /** | ||
| * Create a deep copy of the AST subtree at this node. | ||
| * The copy is dangling, i.e. has no parent. | ||
| * @return dangling copy of the subtree at this node | ||
| * @apilevel low-level | ||
| * @declaredat ASTNode:119 | ||
| */ | ||
| public List<T> treeCopyNoTransform() { | ||
| List tree = (List) copy(); | ||
| if (children != null) { | ||
| for (int i = 0; i < children.length; ++i) { | ||
| ASTNode child = (ASTNode) children[i]; | ||
| if (child != null) { | ||
| child = child.treeCopyNoTransform(); | ||
| tree.setChild(child, i); | ||
| } | ||
| } | ||
| } | ||
| return tree; | ||
| } | ||
| /** | ||
| * Create a deep copy of the AST subtree at this node. | ||
| * The subtree of this node is traversed to trigger rewrites before copy. | ||
| * The copy is dangling, i.e. has no parent. | ||
| * @return dangling copy of the subtree at this node | ||
| * @apilevel low-level | ||
| * @declaredat ASTNode:139 | ||
| */ | ||
| public List<T> treeCopy() { | ||
| doFullTraversal(); | ||
| return treeCopyNoTransform(); | ||
| } | ||
| /** | ||
| * @apilevel internal | ||
| * @declaredat ASTNode:146 | ||
| */ | ||
| protected boolean is$Equal(ASTNode node) { | ||
| return super.is$Equal(node); | ||
| } | ||
| } |
| @@ -0,0 +1,209 @@ | ||
| /* This file was generated with JastAdd2 (http://jastadd.org) version 2.1.13 */ | ||
| package lang.ast; | ||
|
|
||
| import java.util.ArrayList; | ||
| import java.io.ByteArrayOutputStream; | ||
| import java.io.PrintStream; | ||
| import java.lang.reflect.InvocationTargetException; | ||
| import java.util.Set; | ||
| import java.util.TreeSet; | ||
| /** | ||
| * @ast node | ||
| * @declaredat /h/dk/r/ada10dlu/edan65/CalcASM/src/jastadd/calc.ast:5 | ||
| * @production Mul : {@link BinExpr}; | ||
| */ | ||
| public class Mul extends BinExpr implements Cloneable { | ||
| /** | ||
| * @aspect CodeGen | ||
| * @declaredat /h/dk/r/ada10dlu/edan65/CalcASM/src/jastadd/CodeGen.jrag:128 | ||
| */ | ||
| public void genEval(PrintStream out) { | ||
| getLeft().genEval(out); | ||
| out.println(" pushq %rax"); | ||
| getRight().genEval(out); | ||
| out.println(" movq %rax, %rbx"); | ||
| out.println(" popq %rax"); | ||
| out.println(" imulq %rbx, %rax"); | ||
| } | ||
| /** | ||
| * @aspect PrettyPrint | ||
| * @declaredat /h/dk/r/ada10dlu/edan65/CalcASM/src/jastadd/PrettyPrint.jrag:15 | ||
| */ | ||
| public void prettyPrint(PrintStream out, String ind) { | ||
| getLeft().prettyPrint(out, ind); | ||
| out.print(" * "); | ||
| getRight().prettyPrint(out, ind); | ||
| } | ||
| /** | ||
| * @declaredat ASTNode:1 | ||
| */ | ||
| public Mul() { | ||
| super(); | ||
| } | ||
| /** | ||
| * Initializes the child array to the correct size. | ||
| * Initializes List and Opt nta children. | ||
| * @apilevel internal | ||
| * @ast method | ||
| * @declaredat ASTNode:10 | ||
| */ | ||
| public void init$Children() { | ||
| children = new ASTNode[2]; | ||
| } | ||
| /** | ||
| * @declaredat ASTNode:13 | ||
| */ | ||
| public Mul(Expr p0, Expr p1) { | ||
| setChild(p0, 0); | ||
| setChild(p1, 1); | ||
| } | ||
| /** | ||
| * @apilevel low-level | ||
| * @declaredat ASTNode:20 | ||
| */ | ||
| protected int numChildren() { | ||
| return 2; | ||
| } | ||
| /** | ||
| * @apilevel internal | ||
| * @declaredat ASTNode:26 | ||
| */ | ||
| public void flushAttrCache() { | ||
| super.flushAttrCache(); | ||
| } | ||
| /** | ||
| * @apilevel internal | ||
| * @declaredat ASTNode:32 | ||
| */ | ||
| public void flushCollectionCache() { | ||
| super.flushCollectionCache(); | ||
| } | ||
| /** | ||
| * @apilevel internal | ||
| * @declaredat ASTNode:38 | ||
| */ | ||
| public Mul clone() throws CloneNotSupportedException { | ||
| Mul node = (Mul) super.clone(); | ||
| return node; | ||
| } | ||
| /** | ||
| * @apilevel internal | ||
| * @declaredat ASTNode:45 | ||
| */ | ||
| public Mul copy() { | ||
| try { | ||
| Mul node = (Mul) clone(); | ||
| node.parent = null; | ||
| if (children != null) { | ||
| node.children = (ASTNode[]) children.clone(); | ||
| } | ||
| return node; | ||
| } catch (CloneNotSupportedException e) { | ||
| throw new Error("Error: clone not supported for " + getClass().getName()); | ||
| } | ||
| } | ||
| /** | ||
| * Create a deep copy of the AST subtree at this node. | ||
| * The copy is dangling, i.e. has no parent. | ||
| * @return dangling copy of the subtree at this node | ||
| * @apilevel low-level | ||
| * @deprecated Please use treeCopy or treeCopyNoTransform instead | ||
| * @declaredat ASTNode:64 | ||
| */ | ||
| @Deprecated | ||
| public Mul fullCopy() { | ||
| return treeCopyNoTransform(); | ||
| } | ||
| /** | ||
| * Create a deep copy of the AST subtree at this node. | ||
| * The copy is dangling, i.e. has no parent. | ||
| * @return dangling copy of the subtree at this node | ||
| * @apilevel low-level | ||
| * @declaredat ASTNode:74 | ||
| */ | ||
| public Mul treeCopyNoTransform() { | ||
| Mul tree = (Mul) copy(); | ||
| if (children != null) { | ||
| for (int i = 0; i < children.length; ++i) { | ||
| ASTNode child = (ASTNode) children[i]; | ||
| if (child != null) { | ||
| child = child.treeCopyNoTransform(); | ||
| tree.setChild(child, i); | ||
| } | ||
| } | ||
| } | ||
| return tree; | ||
| } | ||
| /** | ||
| * Create a deep copy of the AST subtree at this node. | ||
| * The subtree of this node is traversed to trigger rewrites before copy. | ||
| * The copy is dangling, i.e. has no parent. | ||
| * @return dangling copy of the subtree at this node | ||
| * @apilevel low-level | ||
| * @declaredat ASTNode:94 | ||
| */ | ||
| public Mul treeCopy() { | ||
| doFullTraversal(); | ||
| return treeCopyNoTransform(); | ||
| } | ||
| /** | ||
| * @apilevel internal | ||
| * @declaredat ASTNode:101 | ||
| */ | ||
| protected boolean is$Equal(ASTNode node) { | ||
| return super.is$Equal(node); | ||
| } | ||
| /** | ||
| * Replaces the Left child. | ||
| * @param node The new node to replace the Left child. | ||
| * @apilevel high-level | ||
| */ | ||
| public void setLeft(Expr node) { | ||
| setChild(node, 0); | ||
| } | ||
| /** | ||
| * Retrieves the Left child. | ||
| * @return The current node used as the Left child. | ||
| * @apilevel high-level | ||
| */ | ||
| @ASTNodeAnnotation.Child(name="Left") | ||
| public Expr getLeft() { | ||
| return (Expr) getChild(0); | ||
| } | ||
| /** | ||
| * Retrieves the Left child. | ||
| * <p><em>This method does not invoke AST transformations.</em></p> | ||
| * @return The current node used as the Left child. | ||
| * @apilevel low-level | ||
| */ | ||
| public Expr getLeftNoTransform() { | ||
| return (Expr) getChildNoTransform(0); | ||
| } | ||
| /** | ||
| * Replaces the Right child. | ||
| * @param node The new node to replace the Right child. | ||
| * @apilevel high-level | ||
| */ | ||
| public void setRight(Expr node) { | ||
| setChild(node, 1); | ||
| } | ||
| /** | ||
| * Retrieves the Right child. | ||
| * @return The current node used as the Right child. | ||
| * @apilevel high-level | ||
| */ | ||
| @ASTNodeAnnotation.Child(name="Right") | ||
| public Expr getRight() { | ||
| return (Expr) getChild(1); | ||
| } | ||
| /** | ||
| * Retrieves the Right child. | ||
| * <p><em>This method does not invoke AST transformations.</em></p> | ||
| * @return The current node used as the Right child. | ||
| * @apilevel low-level | ||
| */ | ||
| public Expr getRightNoTransform() { | ||
| return (Expr) getChildNoTransform(1); | ||
| } | ||
| } |
| @@ -0,0 +1,193 @@ | ||
| /* This file was generated with JastAdd2 (http://jastadd.org) version 2.1.13 */ | ||
| package lang.ast; | ||
|
|
||
| import java.util.ArrayList; | ||
| import java.io.ByteArrayOutputStream; | ||
| import java.io.PrintStream; | ||
| import java.lang.reflect.InvocationTargetException; | ||
| import java.util.Set; | ||
| import java.util.TreeSet; | ||
| /** | ||
| * @ast node | ||
| * @declaredat /h/dk/r/ada10dlu/edan65/CalcASM/src/jastadd/calc.ast:8 | ||
| * @production Numeral : {@link Expr} ::= <span class="component"><NUMERAL:String></span>; | ||
| */ | ||
| public class Numeral extends Expr implements Cloneable { | ||
| /** | ||
| * @aspect CodeGen | ||
| * @declaredat /h/dk/r/ada10dlu/edan65/CalcASM/src/jastadd/CodeGen.jrag:120 | ||
| */ | ||
| public void genEval(PrintStream out) { | ||
| out.println(" movq $" + getNUMERAL() + ", %rax"); | ||
| } | ||
| /** | ||
| * @aspect PrettyPrint | ||
| * @declaredat /h/dk/r/ada10dlu/edan65/CalcASM/src/jastadd/PrettyPrint.jrag:27 | ||
| */ | ||
| public void prettyPrint(PrintStream out, String ind) { | ||
| out.print(getNUMERAL()); | ||
| } | ||
| /** | ||
| * @declaredat ASTNode:1 | ||
| */ | ||
| public Numeral() { | ||
| super(); | ||
| } | ||
| /** | ||
| * Initializes the child array to the correct size. | ||
| * Initializes List and Opt nta children. | ||
| * @apilevel internal | ||
| * @ast method | ||
| * @declaredat ASTNode:10 | ||
| */ | ||
| public void init$Children() { | ||
| } | ||
| /** | ||
| * @declaredat ASTNode:12 | ||
| */ | ||
| public Numeral(String p0) { | ||
| setNUMERAL(p0); | ||
| } | ||
| /** | ||
| * @declaredat ASTNode:15 | ||
| */ | ||
| public Numeral(beaver.Symbol p0) { | ||
| setNUMERAL(p0); | ||
| } | ||
| /** | ||
| * @apilevel low-level | ||
| * @declaredat ASTNode:21 | ||
| */ | ||
| protected int numChildren() { | ||
| return 0; | ||
| } | ||
| /** | ||
| * @apilevel internal | ||
| * @declaredat ASTNode:27 | ||
| */ | ||
| public void flushAttrCache() { | ||
| super.flushAttrCache(); | ||
| } | ||
| /** | ||
| * @apilevel internal | ||
| * @declaredat ASTNode:33 | ||
| */ | ||
| public void flushCollectionCache() { | ||
| super.flushCollectionCache(); | ||
| } | ||
| /** | ||
| * @apilevel internal | ||
| * @declaredat ASTNode:39 | ||
| */ | ||
| public Numeral clone() throws CloneNotSupportedException { | ||
| Numeral node = (Numeral) super.clone(); | ||
| return node; | ||
| } | ||
| /** | ||
| * @apilevel internal | ||
| * @declaredat ASTNode:46 | ||
| */ | ||
| public Numeral copy() { | ||
| try { | ||
| Numeral node = (Numeral) clone(); | ||
| node.parent = null; | ||
| if (children != null) { | ||
| node.children = (ASTNode[]) children.clone(); | ||
| } | ||
| return node; | ||
| } catch (CloneNotSupportedException e) { | ||
| throw new Error("Error: clone not supported for " + getClass().getName()); | ||
| } | ||
| } | ||
| /** | ||
| * Create a deep copy of the AST subtree at this node. | ||
| * The copy is dangling, i.e. has no parent. | ||
| * @return dangling copy of the subtree at this node | ||
| * @apilevel low-level | ||
| * @deprecated Please use treeCopy or treeCopyNoTransform instead | ||
| * @declaredat ASTNode:65 | ||
| */ | ||
| @Deprecated | ||
| public Numeral fullCopy() { | ||
| return treeCopyNoTransform(); | ||
| } | ||
| /** | ||
| * Create a deep copy of the AST subtree at this node. | ||
| * The copy is dangling, i.e. has no parent. | ||
| * @return dangling copy of the subtree at this node | ||
| * @apilevel low-level | ||
| * @declaredat ASTNode:75 | ||
| */ | ||
| public Numeral treeCopyNoTransform() { | ||
| Numeral tree = (Numeral) copy(); | ||
| if (children != null) { | ||
| for (int i = 0; i < children.length; ++i) { | ||
| ASTNode child = (ASTNode) children[i]; | ||
| if (child != null) { | ||
| child = child.treeCopyNoTransform(); | ||
| tree.setChild(child, i); | ||
| } | ||
| } | ||
| } | ||
| return tree; | ||
| } | ||
| /** | ||
| * Create a deep copy of the AST subtree at this node. | ||
| * The subtree of this node is traversed to trigger rewrites before copy. | ||
| * The copy is dangling, i.e. has no parent. | ||
| * @return dangling copy of the subtree at this node | ||
| * @apilevel low-level | ||
| * @declaredat ASTNode:95 | ||
| */ | ||
| public Numeral treeCopy() { | ||
| doFullTraversal(); | ||
| return treeCopyNoTransform(); | ||
| } | ||
| /** | ||
| * @apilevel internal | ||
| * @declaredat ASTNode:102 | ||
| */ | ||
| protected boolean is$Equal(ASTNode node) { | ||
| return super.is$Equal(node) && (tokenString_NUMERAL == ((Numeral)node).tokenString_NUMERAL); | ||
| } | ||
| /** | ||
| * Replaces the lexeme NUMERAL. | ||
| * @param value The new value for the lexeme NUMERAL. | ||
| * @apilevel high-level | ||
| */ | ||
| public void setNUMERAL(String value) { | ||
| tokenString_NUMERAL = value; | ||
| } | ||
| /** | ||
| * @apilevel internal | ||
| */ | ||
| protected String tokenString_NUMERAL; | ||
| /** | ||
| */ | ||
| public int NUMERALstart; | ||
| /** | ||
| */ | ||
| public int NUMERALend; | ||
| /** | ||
| * JastAdd-internal setter for lexeme NUMERAL using the Beaver parser. | ||
| * @param symbol Symbol containing the new value for the lexeme NUMERAL | ||
| * @apilevel internal | ||
| */ | ||
| public void setNUMERAL(beaver.Symbol symbol) { | ||
| if (symbol.value != null && !(symbol.value instanceof String)) | ||
| throw new UnsupportedOperationException("setNUMERAL is only valid for String lexemes"); | ||
| tokenString_NUMERAL = (String)symbol.value; | ||
| NUMERALstart = symbol.getStart(); | ||
| NUMERALend = symbol.getEnd(); | ||
| } | ||
| /** | ||
| * Retrieves the value for the lexeme NUMERAL. | ||
| * @return The value for the lexeme NUMERAL. | ||
| * @apilevel high-level | ||
| */ | ||
| @ASTNodeAnnotation.Token(name="NUMERAL") | ||
| public String getNUMERAL() { | ||
| return tokenString_NUMERAL != null ? tokenString_NUMERAL : ""; | ||
| } | ||
| } |
| @@ -0,0 +1,126 @@ | ||
| /* This file was generated with JastAdd2 (http://jastadd.org) version 2.1.13 */ | ||
| package lang.ast; | ||
|
|
||
| import java.util.ArrayList; | ||
| import java.io.ByteArrayOutputStream; | ||
| import java.io.PrintStream; | ||
| import java.lang.reflect.InvocationTargetException; | ||
| import java.util.Set; | ||
| import java.util.TreeSet; | ||
| /** | ||
| * @ast node | ||
| * @production Opt : {@link ASTNode}; | ||
| */ | ||
| public class Opt<T extends ASTNode> extends ASTNode<T> implements Cloneable { | ||
| /** | ||
| * @declaredat ASTNode:1 | ||
| */ | ||
| public Opt() { | ||
| super(); | ||
| } | ||
| /** | ||
| * Initializes the child array to the correct size. | ||
| * Initializes List and Opt nta children. | ||
| * @apilevel internal | ||
| * @ast method | ||
| * @declaredat ASTNode:10 | ||
| */ | ||
| public void init$Children() { | ||
| } | ||
| /** | ||
| * @declaredat ASTNode:12 | ||
| */ | ||
| public Opt(T opt) { | ||
| setChild(opt, 0); | ||
| } | ||
| /** | ||
| * @apilevel internal | ||
| * @declaredat ASTNode:18 | ||
| */ | ||
| public void flushAttrCache() { | ||
| super.flushAttrCache(); | ||
| } | ||
| /** | ||
| * @apilevel internal | ||
| * @declaredat ASTNode:24 | ||
| */ | ||
| public void flushCollectionCache() { | ||
| super.flushCollectionCache(); | ||
| } | ||
| /** | ||
| * @apilevel internal | ||
| * @declaredat ASTNode:30 | ||
| */ | ||
| public Opt<T> clone() throws CloneNotSupportedException { | ||
| Opt node = (Opt) super.clone(); | ||
| return node; | ||
| } | ||
| /** | ||
| * @apilevel internal | ||
| * @declaredat ASTNode:37 | ||
| */ | ||
| public Opt<T> copy() { | ||
| try { | ||
| Opt node = (Opt) clone(); | ||
| node.parent = null; | ||
| if (children != null) { | ||
| node.children = (ASTNode[]) children.clone(); | ||
| } | ||
| return node; | ||
| } catch (CloneNotSupportedException e) { | ||
| throw new Error("Error: clone not supported for " + getClass().getName()); | ||
| } | ||
| } | ||
| /** | ||
| * Create a deep copy of the AST subtree at this node. | ||
| * The copy is dangling, i.e. has no parent. | ||
| * @return dangling copy of the subtree at this node | ||
| * @apilevel low-level | ||
| * @deprecated Please use treeCopy or treeCopyNoTransform instead | ||
| * @declaredat ASTNode:56 | ||
| */ | ||
| @Deprecated | ||
| public Opt<T> fullCopy() { | ||
| return treeCopyNoTransform(); | ||
| } | ||
| /** | ||
| * Create a deep copy of the AST subtree at this node. | ||
| * The copy is dangling, i.e. has no parent. | ||
| * @return dangling copy of the subtree at this node | ||
| * @apilevel low-level | ||
| * @declaredat ASTNode:66 | ||
| */ | ||
| public Opt<T> treeCopyNoTransform() { | ||
| Opt tree = (Opt) copy(); | ||
| if (children != null) { | ||
| for (int i = 0; i < children.length; ++i) { | ||
| ASTNode child = (ASTNode) children[i]; | ||
| if (child != null) { | ||
| child = child.treeCopyNoTransform(); | ||
| tree.setChild(child, i); | ||
| } | ||
| } | ||
| } | ||
| return tree; | ||
| } | ||
| /** | ||
| * Create a deep copy of the AST subtree at this node. | ||
| * The subtree of this node is traversed to trigger rewrites before copy. | ||
| * The copy is dangling, i.e. has no parent. | ||
| * @return dangling copy of the subtree at this node | ||
| * @apilevel low-level | ||
| * @declaredat ASTNode:86 | ||
| */ | ||
| public Opt<T> treeCopy() { | ||
| doFullTraversal(); | ||
| return treeCopyNoTransform(); | ||
| } | ||
| /** | ||
| * @apilevel internal | ||
| * @declaredat ASTNode:93 | ||
| */ | ||
| protected boolean is$Equal(ASTNode node) { | ||
| return super.is$Equal(node); | ||
| } | ||
| } |
| @@ -0,0 +1,211 @@ | ||
| /* This file was generated with JastAdd2 (http://jastadd.org) version 2.1.13 */ | ||
| package lang.ast; | ||
|
|
||
| import java.util.ArrayList; | ||
| import java.io.ByteArrayOutputStream; | ||
| import java.io.PrintStream; | ||
| import java.lang.reflect.InvocationTargetException; | ||
| import java.util.Set; | ||
| import java.util.TreeSet; | ||
| /** | ||
| * @ast node | ||
| * @declaredat /h/dk/r/ada10dlu/edan65/CalcASM/src/jastadd/calc.ast:15 | ||
| * @production UnknownDecl : {@link IdDecl}; | ||
| */ | ||
| public class UnknownDecl extends IdDecl implements Cloneable { | ||
| /** | ||
| * @declaredat ASTNode:1 | ||
| */ | ||
| public UnknownDecl() { | ||
| super(); | ||
| } | ||
| /** | ||
| * Initializes the child array to the correct size. | ||
| * Initializes List and Opt nta children. | ||
| * @apilevel internal | ||
| * @ast method | ||
| * @declaredat ASTNode:10 | ||
| */ | ||
| public void init$Children() { | ||
| } | ||
| /** | ||
| * @declaredat ASTNode:12 | ||
| */ | ||
| public UnknownDecl(String p0) { | ||
| setID(p0); | ||
| } | ||
| /** | ||
| * @declaredat ASTNode:15 | ||
| */ | ||
| public UnknownDecl(beaver.Symbol p0) { | ||
| setID(p0); | ||
| } | ||
| /** | ||
| * @apilevel low-level | ||
| * @declaredat ASTNode:21 | ||
| */ | ||
| protected int numChildren() { | ||
| return 0; | ||
| } | ||
| /** | ||
| * @apilevel internal | ||
| * @declaredat ASTNode:27 | ||
| */ | ||
| public void flushAttrCache() { | ||
| super.flushAttrCache(); | ||
| isUnknown_reset(); | ||
| } | ||
| /** | ||
| * @apilevel internal | ||
| * @declaredat ASTNode:34 | ||
| */ | ||
| public void flushCollectionCache() { | ||
| super.flushCollectionCache(); | ||
| } | ||
| /** | ||
| * @apilevel internal | ||
| * @declaredat ASTNode:40 | ||
| */ | ||
| public UnknownDecl clone() throws CloneNotSupportedException { | ||
| UnknownDecl node = (UnknownDecl) super.clone(); | ||
| return node; | ||
| } | ||
| /** | ||
| * @apilevel internal | ||
| * @declaredat ASTNode:47 | ||
| */ | ||
| public UnknownDecl copy() { | ||
| try { | ||
| UnknownDecl node = (UnknownDecl) clone(); | ||
| node.parent = null; | ||
| if (children != null) { | ||
| node.children = (ASTNode[]) children.clone(); | ||
| } | ||
| return node; | ||
| } catch (CloneNotSupportedException e) { | ||
| throw new Error("Error: clone not supported for " + getClass().getName()); | ||
| } | ||
| } | ||
| /** | ||
| * Create a deep copy of the AST subtree at this node. | ||
| * The copy is dangling, i.e. has no parent. | ||
| * @return dangling copy of the subtree at this node | ||
| * @apilevel low-level | ||
| * @deprecated Please use treeCopy or treeCopyNoTransform instead | ||
| * @declaredat ASTNode:66 | ||
| */ | ||
| @Deprecated | ||
| public UnknownDecl fullCopy() { | ||
| return treeCopyNoTransform(); | ||
| } | ||
| /** | ||
| * Create a deep copy of the AST subtree at this node. | ||
| * The copy is dangling, i.e. has no parent. | ||
| * @return dangling copy of the subtree at this node | ||
| * @apilevel low-level | ||
| * @declaredat ASTNode:76 | ||
| */ | ||
| public UnknownDecl treeCopyNoTransform() { | ||
| UnknownDecl tree = (UnknownDecl) copy(); | ||
| if (children != null) { | ||
| for (int i = 0; i < children.length; ++i) { | ||
| ASTNode child = (ASTNode) children[i]; | ||
| if (child != null) { | ||
| child = child.treeCopyNoTransform(); | ||
| tree.setChild(child, i); | ||
| } | ||
| } | ||
| } | ||
| return tree; | ||
| } | ||
| /** | ||
| * Create a deep copy of the AST subtree at this node. | ||
| * The subtree of this node is traversed to trigger rewrites before copy. | ||
| * The copy is dangling, i.e. has no parent. | ||
| * @return dangling copy of the subtree at this node | ||
| * @apilevel low-level | ||
| * @declaredat ASTNode:96 | ||
| */ | ||
| public UnknownDecl treeCopy() { | ||
| doFullTraversal(); | ||
| return treeCopyNoTransform(); | ||
| } | ||
| /** | ||
| * @apilevel internal | ||
| * @declaredat ASTNode:103 | ||
| */ | ||
| protected boolean is$Equal(ASTNode node) { | ||
| return super.is$Equal(node) && (tokenString_ID == ((UnknownDecl)node).tokenString_ID); | ||
| } | ||
| /** | ||
| * Replaces the lexeme ID. | ||
| * @param value The new value for the lexeme ID. | ||
| * @apilevel high-level | ||
| */ | ||
| public void setID(String value) { | ||
| tokenString_ID = value; | ||
| } | ||
| /** | ||
| * JastAdd-internal setter for lexeme ID using the Beaver parser. | ||
| * @param symbol Symbol containing the new value for the lexeme ID | ||
| * @apilevel internal | ||
| */ | ||
| public void setID(beaver.Symbol symbol) { | ||
| if (symbol.value != null && !(symbol.value instanceof String)) | ||
| throw new UnsupportedOperationException("setID is only valid for String lexemes"); | ||
| tokenString_ID = (String)symbol.value; | ||
| IDstart = symbol.getStart(); | ||
| IDend = symbol.getEnd(); | ||
| } | ||
| /** | ||
| * Retrieves the value for the lexeme ID. | ||
| * @return The value for the lexeme ID. | ||
| * @apilevel high-level | ||
| */ | ||
| @ASTNodeAnnotation.Token(name="ID") | ||
| public String getID() { | ||
| return tokenString_ID != null ? tokenString_ID : ""; | ||
| } | ||
| /** | ||
| * @apilevel internal | ||
| */ | ||
| protected boolean isUnknown_visited = false; | ||
| /** | ||
| * @apilevel internal | ||
| */ | ||
| protected boolean isUnknown_computed = false; | ||
| /** | ||
| * @apilevel internal | ||
| */ | ||
| protected boolean isUnknown_value; | ||
| /** | ||
| * @apilevel internal | ||
| */ | ||
| private void isUnknown_reset() { | ||
| isUnknown_computed = false; | ||
| isUnknown_visited = false; | ||
| } | ||
| @ASTNodeAnnotation.Attribute | ||
| public boolean isUnknown() { | ||
| ASTNode$State state = state(); | ||
| if (isUnknown_computed) { | ||
| return isUnknown_value; | ||
| } | ||
| if (isUnknown_visited) { | ||
| throw new RuntimeException("Circular definition of attr: isUnknown in class: org.jastadd.ast.AST.SynDecl"); | ||
| } | ||
| isUnknown_visited = true; | ||
| boolean intermediate = state.INTERMEDIATE_VALUE; | ||
| state.INTERMEDIATE_VALUE = false; | ||
| isUnknown_value = true; | ||
| if (true) { | ||
| isUnknown_computed = true; | ||
| } else { | ||
| } | ||
| state.INTERMEDIATE_VALUE |= intermediate; | ||
|
|
||
| isUnknown_visited = false; | ||
| return isUnknown_value; | ||
| } | ||
| } |
| @@ -0,0 +1,190 @@ | ||
| /** | ||
| * @author jesper.oqvist@cs.lth.se | ||
| */ | ||
| aspect CodeGen { | ||
|
|
||
| public void Program.genCode(PrintStream out) { | ||
| out.println(".global _start"); | ||
| out.println(".data"); | ||
| out.println("ask_message: .ascii \"Please enter a number: \""); | ||
| out.println("ask_msg_len: .quad 23"); | ||
| out.println("buf: .skip 1024"); | ||
| out.println(); | ||
| out.println(".text"); | ||
| out.println("_start:"); | ||
|
|
||
| // allocate space for local variables (bindings): | ||
| out.println(" pushq %rbp"); | ||
| out.println(" movq %rsp, %rbp"); | ||
| out.println(" subq $" + (getExpr().numLocals()*8) + ", %rsp"); | ||
|
|
||
| getExpr().genEval(out);// stores result in RAX | ||
|
|
||
|
|
||
| // print result: | ||
| out.println(" pushq %rax"); | ||
| out.println(" call print"); | ||
| out.println(" addq $8, %rsp"); | ||
|
|
||
| // de-allocate local variables: | ||
| out.println(" movq %rbp, %rsp"); | ||
| out.println(" popq %rbp"); | ||
|
|
||
| // call sys_exit: | ||
| out.println(" movq $0, %rdi"); | ||
| out.println(" movq $60, %rax"); | ||
| out.println(" syscall"); // done! | ||
|
|
||
| // helper functions | ||
| out.println("# Procedure to read number from stdin"); | ||
| out.println("# C signature: long int read(void)"); | ||
| out.println("read:"); | ||
| out.println(" pushq %rbp"); | ||
| out.println(" movq %rsp, %rbp"); | ||
| out.println(" movq $0, %rdi"); | ||
| out.println(" movq $buf, %rsi"); | ||
| out.println(" movq $1024, %rdx"); | ||
| out.println(" movq $0, %rax"); | ||
| out.println(" syscall # %rax = sys_read(0, buf, 1024)"); | ||
| out.println(" ### convert string to integer:"); | ||
| out.println(" ### %rax contains nchar"); | ||
| out.println(" ### %rsi contains ptr"); | ||
| out.println(" movq $0, %rdx # sum = 0"); | ||
| out.println("atoi_loop:"); | ||
| out.println(" cmpq $0, %rax # while (nchar > 0)"); | ||
| out.println(" jle atoi_done # leave loop if nchar <= 0"); | ||
| out.println(" movzbq (%rsi), %rbx # move byte, and sign extend to qword"); | ||
| out.println(" cmpq $0x30, %rbx # test if < '0'"); | ||
| out.println(" jl atoi_done # character is not numeric"); | ||
| out.println(" cmpq $0x39, %rbx # test if > '9'"); | ||
| out.println(" jg atoi_done # character is not numeric"); | ||
| out.println(" imulq $10, %rdx # multiply sum by 10"); | ||
| out.println(" subq $0x30, %rbx # value of character"); | ||
| out.println(" addq %rbx, %rdx # add to sum"); | ||
| out.println(" incq %rsi # step to next char"); | ||
| out.println(" decq %rax # nchar--"); | ||
| out.println(" jmp atoi_loop # loop back"); | ||
| out.println("atoi_done:"); | ||
| out.println(" movq %rdx, %rax # return value in RAX"); | ||
| out.println(" popq %rbp"); | ||
| out.println(" ret"); | ||
| out.println(); | ||
| out.println("# Procedure to print number to stdout"); | ||
| out.println("# C signature: void print(long int)"); | ||
| out.println("print:"); | ||
| out.println(" pushq %rbp"); | ||
| out.println(" movq %rsp, %rbp"); | ||
| out.println(" ### convert integer to string"); | ||
| out.println(" movq 16(%rbp), %rax # parameter"); | ||
| out.println(" movq $(buf+1023), %rsi # write ptr (start from end of buf)"); | ||
| out.println(" movb $0x0a, (%rsi) # insert newline"); | ||
| out.println(" movq $1, %rcx # string length"); | ||
| out.println("itoa_loop: # do.. while (at least one iteration)"); | ||
| out.println(" movq $10, %rbx"); | ||
| out.println(" movq $0, %rdx"); | ||
| out.println(" idivq %rbx # divide rdx:rax by 10"); | ||
| out.println(" addb $0x30, %dl # remainder + '0'"); | ||
| out.println(" decq %rsi # move string pointer"); | ||
| out.println(" movb %dl, (%rsi)"); | ||
| out.println(" incq %rcx # increment string length"); | ||
| out.println(" cmpq $0, %rax"); | ||
| out.println(" jg itoa_loop # produce more digits"); | ||
| out.println("itoa_done:"); | ||
| out.println(" movq $1, %rdi"); | ||
| out.println(" movq %rcx, %rdx"); | ||
| out.println(" movq $1, %rax"); | ||
| out.println(" syscall"); | ||
| out.println(" popq %rbp"); | ||
| out.println(" ret"); | ||
| out.println(); | ||
| out.println("print_string:"); | ||
| out.println(" pushq %rbp"); | ||
| out.println(" movq %rsp, %rbp"); | ||
| out.println(" movq $1, %rdi"); | ||
| out.println(" movq 16(%rbp), %rsi"); | ||
| out.println(" movq 24(%rbp), %rdx"); | ||
| out.println(" movq $1, %rax"); | ||
| out.println(" syscall"); | ||
| out.println(" popq %rbp"); | ||
| out.println(" ret"); | ||
| } | ||
|
|
||
| /** | ||
| * Generate code to evaluate the expression and | ||
| * store the result in RAX. | ||
| * | ||
| * This must be implemented for every subclass of Expr! | ||
| */ | ||
| abstract public void Expr.genEval(PrintStream out); | ||
|
|
||
| public void Numeral.genEval(PrintStream out) { | ||
| out.println(" movq $" + getNUMERAL() + ", %rax"); | ||
| } | ||
|
|
||
| public void IdUse.genEval(PrintStream out) { | ||
| out.println(" movq " + decl().address() + ", %rax"); | ||
| } | ||
|
|
||
| public void Mul.genEval(PrintStream out) { | ||
| getLeft().genEval(out); | ||
| out.println(" pushq %rax"); | ||
| getRight().genEval(out); | ||
| out.println(" movq %rax, %rbx"); | ||
| out.println(" popq %rax"); | ||
| out.println(" imulq %rbx, %rax"); | ||
| } | ||
|
|
||
| public void Div.genEval(PrintStream out) { | ||
| getLeft().genEval(out); | ||
| out.println(" pushq %rax"); | ||
| getRight().genEval(out); | ||
| out.println(" movq %rax, %rbx"); | ||
| out.println(" popq %rax"); | ||
| out.println(" movq $0, %rdx");// NB: clear RDX to prepare division RDX:RAX / RBX | ||
| out.println(" idivq %rbx"); | ||
| } | ||
|
|
||
| public void Let.genEval(PrintStream out) { | ||
| // evaluate bindings: | ||
| for (int i = 0; i < getNumBinding(); ++i) { | ||
| getBinding(i).genCode(out); | ||
| } | ||
| getExpr().genEval(out); | ||
| } | ||
|
|
||
| public void Ask.genEval(PrintStream out) { | ||
| out.println(" pushq ask_msg_len"); | ||
| out.println(" pushq $ask_message"); | ||
| out.println(" call print_string"); | ||
| out.println(" addq $16, %rsp"); | ||
| out.println(" call read"); | ||
| } | ||
|
|
||
| public void Binding.genCode(PrintStream out) { | ||
| getExpr().genEval(out); | ||
| out.println(" movq %rax, " + getIdDecl().address()); | ||
| } | ||
|
|
||
| /** | ||
| * Address of local variable variable in the current stack frame. | ||
| */ | ||
| syn String IdDecl.address() = "-"+(localIndex()*8)+"(%rbp)"; | ||
|
|
||
| /** | ||
| * Local variable counting. | ||
| */ | ||
| syn int ASTNode.numLocals() = lastNode().localIndex() - localIndex(); | ||
|
|
||
| /** | ||
| * Local variable numbering. | ||
| */ | ||
| syn int ASTNode.localIndex() = prevNode().localIndex(); | ||
| eq Program.localIndex() = 0; | ||
| eq IdDecl.localIndex() = prevNode().localIndex() + 1; | ||
|
|
||
| inh ASTNode ASTNode.prevNode(); | ||
| eq ASTNode.getChild(int i).prevNode() = prevNode(i); | ||
| syn ASTNode ASTNode.lastNode() = prevNode(getNumChild()); | ||
| syn ASTNode ASTNode.prevNode(int i) = i>0 ? getChild(i-1).lastNode() : this; | ||
|
|
||
| } |
| @@ -0,0 +1,50 @@ | ||
| import java.util.ArrayList; | ||
| import java.io.ByteArrayOutputStream; | ||
| import java.io.PrintStream; | ||
| import java.lang.reflect.InvocationTargetException; | ||
|
|
||
| // Don't import java.lang.reflect.Method because it may conflict with student code. | ||
|
|
||
| aspect DumpTree { | ||
| private String ASTNode.DUMP_TREE_INDENT = " "; | ||
|
|
||
| public String ASTNode.dumpTree() { | ||
| ByteArrayOutputStream bytes = new ByteArrayOutputStream(); | ||
| dumpTree(new PrintStream(bytes)); | ||
| return bytes.toString(); | ||
| } | ||
|
|
||
| public void ASTNode.dumpTree(PrintStream out) { | ||
| dumpTree(out, ""); | ||
| out.flush(); | ||
| } | ||
|
|
||
| public void ASTNode.dumpTree(PrintStream out, String indent) { | ||
| out.print(indent + getClass().getSimpleName()); | ||
| out.println(getTokens()); | ||
| String childIndent = indent + DUMP_TREE_INDENT; | ||
| for (ASTNode child : this) { | ||
| if (child == null) { | ||
| out.println(childIndent + "null"); | ||
| } else { | ||
| child.dumpTree(out, childIndent); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| public String ASTNode.getTokens() { | ||
| StringBuilder sb = new StringBuilder(); | ||
| java.lang.reflect.Method[] methods = getClass().getMethods(); | ||
| for (java.lang.reflect.Method method : getClass().getMethods()) { | ||
| ASTNodeAnnotation.Token token = method.getAnnotation(ASTNodeAnnotation.Token.class); | ||
| if (token != null) { | ||
| try { | ||
| sb.append(" " + token.name() + "=\"" + method.invoke(this) + "\""); | ||
| } catch (IllegalAccessException e) { | ||
| } catch (InvocationTargetException e) { | ||
| } | ||
| } | ||
| } | ||
| return sb.toString(); | ||
| } | ||
| } |
| @@ -0,0 +1,45 @@ | ||
| import java.util.Set; | ||
| import java.util.TreeSet; | ||
|
|
||
| aspect Errors { | ||
| public class ErrorMessage implements Comparable<ErrorMessage> { | ||
| protected final String message; | ||
| protected final int lineNumber; | ||
| public ErrorMessage(String message, int lineNumber) { | ||
| this.message = message; | ||
| this.lineNumber = lineNumber; | ||
| } | ||
| public int compareTo(ErrorMessage other) { | ||
| if (lineNumber == other.lineNumber) { | ||
| return message.compareTo(other.message); | ||
| } | ||
| return Integer.compare(lineNumber, other.lineNumber); | ||
| } | ||
| public String toString() { | ||
| return "Error at line " + lineNumber + ": " + message; | ||
| } | ||
| } | ||
| protected ErrorMessage ASTNode.error(String message) { | ||
| return new ErrorMessage(message, getLine(getStart())); | ||
| } | ||
|
|
||
| coll Set<ErrorMessage> Program.errors() [new TreeSet<ErrorMessage>()] with add; | ||
|
|
||
| inh Program ASTNode.program(); | ||
| eq Program.getChild().program() = this; | ||
| } | ||
|
|
||
|
|
||
| aspect ErrorContributions { | ||
| IdUse contributes error("symbol '" + getID() + "' is not declared") | ||
| when decl().isUnknown() | ||
| to Program.errors() for program(); | ||
|
|
||
| IdDecl contributes error("symbol '" + getID() + "' is already declared!") | ||
| when isMultiplyDeclared() | ||
| to Program.errors() for program(); | ||
|
|
||
| IdUse contributes error("the definition of symbol '" + getID() + "' is circular") | ||
| when isCircular() | ||
| to Program.errors() for program(); | ||
| } |
| @@ -0,0 +1,38 @@ | ||
| aspect NameAnalysis { | ||
| syn IdDecl IdUse.decl() = lookup(getID()); | ||
| inh IdDecl IdUse.lookup(String name); | ||
|
|
||
| eq Let.getExpr().lookup(String name) { | ||
| IdDecl decl = localLookup(name, getNumBinding()-1); | ||
| return !decl.isUnknown() ? decl : lookup(name); | ||
| } | ||
| eq Program.getChild().lookup(String name) = unknownDecl(); | ||
| inh IdDecl Let.lookup(String name); | ||
|
|
||
| syn IdDecl Let.localLookup(String name, int until) { | ||
| for (int i = 0; i <= until; i++) { | ||
| if (getBinding(i).getIdDecl().getID().equals(name)) { | ||
| return getBinding(i).getIdDecl(); | ||
| } | ||
| } | ||
| return unknownDecl(); | ||
| } | ||
|
|
||
| eq Let.getBinding(int index).lookup(String name) { | ||
| IdDecl decl = localLookup(name, index); | ||
| return !decl.isUnknown() ? decl : lookup(name); | ||
| } | ||
|
|
||
| inh IdDecl IdDecl.lookup(String name); | ||
| syn boolean IdDecl.isMultiplyDeclared() = lookup(getID()) != this; | ||
| } | ||
|
|
||
| aspect CircularDefinitions { | ||
| /* Identify circular definitions in let expressions */ | ||
| syn boolean IdUse.isCircular() = inExprOf(decl()); | ||
| inh boolean IdUse.inExprOf(IdDecl decl); | ||
| inh boolean Binding.inExprOf(IdDecl decl); | ||
| eq Binding.getExpr().inExprOf(IdDecl decl) | ||
| = getIdDecl() == decl || inExprOf(decl); | ||
| eq Program.getChild().inExprOf(IdDecl decl) = false; | ||
| } |
| @@ -0,0 +1,62 @@ | ||
| import java.io.PrintStream; | ||
|
|
||
| aspect PrettyPrint { | ||
| public void ASTNode.prettyPrint(PrintStream out) { | ||
| prettyPrint(out, ""); | ||
| out.println(); | ||
| } | ||
|
|
||
| public void ASTNode.prettyPrint(PrintStream out, String ind) { | ||
| for (int i = 0; i < getNumChild(); ++i) { | ||
| getChild(i).prettyPrint(out, ind); | ||
| } | ||
| } | ||
|
|
||
| public void Mul.prettyPrint(PrintStream out, String ind) { | ||
| getLeft().prettyPrint(out, ind); | ||
| out.print(" * "); | ||
| getRight().prettyPrint(out, ind); | ||
| } | ||
|
|
||
| public void Div.prettyPrint(PrintStream out, String ind) { | ||
| getLeft().prettyPrint(out, ind); | ||
| out.print(" / "); | ||
| getRight().prettyPrint(out, ind); | ||
| } | ||
|
|
||
| public void Numeral.prettyPrint(PrintStream out, String ind) { | ||
| out.print(getNUMERAL()); | ||
| } | ||
|
|
||
| public void IdUse.prettyPrint(PrintStream out, String ind) { | ||
| out.print(getID()); | ||
| } | ||
|
|
||
| public void IdDecl.prettyPrint(PrintStream out, String ind) { | ||
| out.print(getID()); | ||
| } | ||
|
|
||
| public void Let.prettyPrint(PrintStream out, String ind) { | ||
| out.println("let"); | ||
| for (int i = 0; i < getNumBinding(); ++i) { | ||
| out.print(ind+" "); | ||
| getBinding(i).prettyPrint(out, ind+" "); | ||
| out.println(); | ||
| } | ||
| out.println(ind + "in"); | ||
| out.print(ind+" "); | ||
| getExpr().prettyPrint(out, ind+" "); | ||
| out.println(); | ||
| out.print(ind + "end"); | ||
| } | ||
|
|
||
| public void Binding.prettyPrint(PrintStream out, String ind) { | ||
| getIdDecl().prettyPrint(out, ind); | ||
| out.append(" = "); | ||
| getExpr().prettyPrint(out, ind+" "); | ||
| } | ||
|
|
||
| public void Ask.prettyPrint(PrintStream out, String ind) { | ||
| out.print("ask user"); | ||
| } | ||
| } |
| @@ -0,0 +1,9 @@ | ||
| aspect UnknownDecl { | ||
| syn nta UnknownDecl Program.unknownDecl() = new UnknownDecl("<unknown>"); | ||
|
|
||
| inh UnknownDecl ASTNode.unknownDecl(); | ||
| eq Program.getChild().unknownDecl() = unknownDecl(); | ||
|
|
||
| syn boolean IdDecl.isUnknown() = false; | ||
| eq UnknownDecl.isUnknown() = true; | ||
| } |
| @@ -0,0 +1,18 @@ | ||
| Program ::= Expr; | ||
|
|
||
| abstract Expr; | ||
| abstract BinExpr : Expr ::= Left:Expr Right:Expr; | ||
| Mul : BinExpr; | ||
| Div : BinExpr; | ||
|
|
||
| Numeral : Expr ::= <NUMERAL>; | ||
| IdUse : Expr ::= <ID>; | ||
|
|
||
| Let : Expr ::= Binding* Expr; | ||
|
|
||
| Binding ::= IdDecl Expr; | ||
| IdDecl ::= <ID>; | ||
| UnknownDecl : IdDecl; | ||
|
|
||
| Ask : Expr; | ||
|
|
| @@ -0,0 +1,60 @@ | ||
| package lang; | ||
|
|
||
| import java.io.FileReader; | ||
| import java.io.IOException; | ||
| import java.io.FileNotFoundException; | ||
|
|
||
| import beaver.Parser.Exception; | ||
|
|
||
| import lang.ast.Program; | ||
| import lang.ast.LangParser; | ||
| import lang.ast.LangScanner; | ||
| import lang.ast.ErrorMessage; | ||
|
|
||
| /** | ||
| * Computes the maximum statement nesting depth for a Calc program. | ||
| */ | ||
| public class Compiler { | ||
| /** | ||
| * Entry point | ||
| * @param args | ||
| */ | ||
| public static void main(String[] args) { | ||
| try { | ||
| if (args.length != 1) { | ||
| System.err.println( | ||
| "You must specify a source file on the command line!"); | ||
| printUsage(); | ||
| System.exit(1); | ||
| return; | ||
| } | ||
|
|
||
| String filename = args[0]; | ||
| LangScanner scanner = new LangScanner(new FileReader(filename)); | ||
| LangParser parser = new LangParser(); | ||
| Program program = (Program) parser.parse(scanner); | ||
| if (!program.errors().isEmpty()) { | ||
| System.err.println(); | ||
| System.err.println("Errors: "); | ||
| for (ErrorMessage e: program.errors()) { | ||
| System.err.println("- " + e); | ||
| } | ||
| } else { | ||
| program.genCode(System.out); | ||
| } | ||
| } catch (FileNotFoundException e) { | ||
| System.out.println("File not found!"); | ||
| System.exit(1); | ||
| } catch (IOException e) { | ||
| e.printStackTrace(System.err); | ||
| } catch (Exception e) { | ||
| e.printStackTrace(); | ||
| } | ||
| } | ||
|
|
||
| private static void printUsage() { | ||
| System.err.println("Usage: Compiler FILE"); | ||
| System.err.println(" where FILE is the file to be compiled"); | ||
| } | ||
| } | ||
|
|
| @@ -0,0 +1,68 @@ | ||
| package tests; | ||
|
|
||
| import java.io.File; | ||
| import java.util.Collection; | ||
| import java.util.LinkedList; | ||
|
|
||
| /** | ||
| * A parameterized test suite. Adds helper methods for | ||
| * parameterized testing. | ||
| */ | ||
| abstract public class AbstractParameterizedTest extends AbstractTestSuite { | ||
|
|
||
| /** | ||
| * File extension for test input files. EDIT ME | ||
| */ | ||
| protected static final String IN_EXTENSION = ".calc"; | ||
| /** | ||
| * Test output is written to a file with this extension | ||
| */ | ||
| private static final String OUT_EXTENSION = ".out"; | ||
| /** | ||
| * File extension for expected test output | ||
| */ | ||
| private static final String EXPECTED_EXTENSION = ".expected"; | ||
|
|
||
| protected final File inFile; | ||
| protected final File outFile; | ||
| protected final File expectedFile; | ||
|
|
||
| /** | ||
| * @param testDirectory | ||
| * @param testFile | ||
| */ | ||
| public AbstractParameterizedTest(String testDirectory, String testFile) { | ||
| super(testDirectory); | ||
| inFile = getTestFile(testFile); | ||
| outFile = getFileReplaceExtension(testFile, OUT_EXTENSION); | ||
| expectedFile = getFileReplaceExtension(testFile, EXPECTED_EXTENSION); | ||
| } | ||
|
|
||
| protected File getTestFile(String filename) { | ||
| return new File(testDirectory, filename); | ||
| } | ||
|
|
||
| protected File getFileReplaceExtension(File file, String extension) { | ||
| return getFileReplaceExtension(file.getName(), extension); | ||
| } | ||
|
|
||
| protected File getFileReplaceExtension(String filename, String extension) { | ||
| String simpleName = filename.substring(0, filename.lastIndexOf('.')); | ||
| return getTestFile(simpleName+extension); | ||
| } | ||
|
|
||
| @SuppressWarnings("javadoc") | ||
| public static Iterable<Object[]> getTestParameters(String testDirectory) { | ||
| Collection<Object[]> tests = new LinkedList<Object[]>(); | ||
| File testDir = new File(testDirectory); | ||
| if (!testDir.isDirectory()) { | ||
| throw new Error("Could not find '" + testDirectory + "' directory!"); | ||
| } | ||
| for (File f: testDir.listFiles()) { | ||
| if (f.getName().endsWith(IN_EXTENSION)) { | ||
| tests.add(new Object[] {f.getName()}); | ||
| } | ||
| } | ||
| return tests; | ||
| } | ||
| } |
| @@ -0,0 +1,121 @@ | ||
| package tests; | ||
|
|
||
| import static org.junit.Assert.fail; | ||
| import static org.junit.Assert.assertEquals; | ||
|
|
||
| import java.io.ByteArrayOutputStream; | ||
| import java.io.File; | ||
| import java.io.FileNotFoundException; | ||
| import java.io.FileReader; | ||
| import java.io.IOException; | ||
| import java.io.PrintStream; | ||
| import java.nio.file.Files; | ||
| import java.util.Scanner; | ||
|
|
||
| import lang.ast.LangParser; | ||
| import lang.ast.LangScanner; | ||
|
|
||
| /** | ||
| * Utility methods for running tests | ||
| */ | ||
| abstract class AbstractTestSuite { | ||
| private static String SYS_LINE_SEP = System.getProperty("line.separator"); | ||
|
|
||
| /** | ||
| * Directory where test files for this test suite live. | ||
| */ | ||
| protected final File testDirectory; | ||
|
|
||
| public AbstractTestSuite(String testDirectory) { | ||
| this.testDirectory = new File(testDirectory); | ||
| } | ||
|
|
||
| protected void testValidSyntax(String filename) { | ||
| try { | ||
| parse(new File(testDirectory, filename)); | ||
| } catch (Exception e) { | ||
| fail("Unexpected error while parsing '" + filename + "': " | ||
| + e.getMessage()); | ||
| } | ||
| } | ||
|
|
||
| protected void testSyntaxError(String filename) { | ||
| try { | ||
| // Beaver reports syntax error on the standard error. | ||
| // We want to discard these messages since we expect syntax error. | ||
| System.setErr(new PrintStream(new ByteArrayOutputStream())); | ||
|
|
||
| parse(new File(testDirectory, filename)); | ||
|
|
||
| fail("syntax is valid, expected syntax error"); | ||
| } catch (beaver.Parser.Exception | lang.ast.LangParser.SyntaxError e) { | ||
| // ok (syntax error)! | ||
| } catch (Exception e) { | ||
| fail("IO error while trying to parse '" + filename + "': " | ||
| + e.getMessage()); | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * Parses the given file | ||
| * @param file | ||
| * @return parser result, if everything went OK | ||
| * @throws IOException | ||
| * @throws Exception | ||
| */ | ||
| protected static Object parse(File file) throws IOException, Exception { | ||
| LangScanner scanner = new LangScanner(new FileReader(file)); | ||
| LangParser parser = new LangParser(); | ||
| return parser.parse(scanner); | ||
| } | ||
|
|
||
| /** | ||
| * Check that the string matches the contents of the given file. | ||
| * Also writes the actual output to file. | ||
| * @param actual actual output | ||
| * @param out file where output should be written | ||
| * @param expected file containing expected output | ||
| */ | ||
| protected static void compareOutput(String actual, File out, File expected) { | ||
| try { | ||
| Files.write(out.toPath(), actual.getBytes()); | ||
| assertEquals("Output differs", | ||
| readFileToString(expected), | ||
| normalizeText(actual)); | ||
| } catch (IOException e) { | ||
| fail("IOException occurred while comparing output: " + e.getMessage()); | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * Reads an entire file to a string object. | ||
| * <p>If the file does not exist an empty string is returned. | ||
| * <p>The system dependent line separator char sequence is replaced by | ||
| * the newline character. | ||
| * | ||
| * @param file | ||
| * @return normalized text from file | ||
| * @throws FileNotFoundException | ||
| */ | ||
| private static String readFileToString(File file) throws FileNotFoundException { | ||
| if (!file.isFile()) { | ||
| return ""; | ||
| } | ||
|
|
||
| Scanner scanner = new Scanner(file); | ||
| scanner.useDelimiter("\\Z"); | ||
| String text = normalizeText(scanner.hasNext() ? scanner.next() : ""); | ||
| scanner.close(); | ||
| return text; | ||
| } | ||
|
|
||
| /** | ||
| * Trim whitespace and normalize newline characters to be only \n | ||
| * @param text | ||
| * @return normalized text | ||
| */ | ||
| private static String normalizeText(String text) { | ||
| return text.replace(SYS_LINE_SEP, "\n").trim(); | ||
| } | ||
|
|
||
| } |
| @@ -0,0 +1,119 @@ | ||
| package tests; | ||
|
|
||
| import static org.junit.Assert.*; | ||
|
|
||
| import java.io.BufferedReader; | ||
| import java.io.File; | ||
| import java.io.FileOutputStream; | ||
| import java.io.IOException; | ||
| import java.io.InputStream; | ||
| import java.io.InputStreamReader; | ||
| import java.io.PrintStream; | ||
| import java.util.ArrayList; | ||
| import java.util.Arrays; | ||
| import java.util.List; | ||
|
|
||
| import org.junit.Test; | ||
| import org.junit.runner.RunWith; | ||
| import org.junit.runners.Parameterized; | ||
| import org.junit.runners.Parameterized.Parameters; | ||
|
|
||
| import lang.ast.Program; | ||
|
|
||
| /** | ||
| * Tests code generation | ||
| * | ||
| * @Author Niklas Fors | ||
| */ | ||
| @RunWith(Parameterized.class) | ||
| public class TestCodeGeneration extends AbstractParameterizedTest { | ||
| /** | ||
| * Directory where test files live | ||
| */ | ||
| private static final String TEST_DIR = "testfiles/asm"; | ||
|
|
||
| /** | ||
| * Construct a new code generation test | ||
| * @param filename filename of test input file | ||
| */ | ||
| public TestCodeGeneration(String filename) { | ||
| super(TEST_DIR, filename); | ||
| } | ||
|
|
||
| /** | ||
| * Run the code generation test | ||
| */ | ||
| @Test | ||
| public void runTest() throws IOException, Exception { | ||
| Program program = (Program) parse(inFile); | ||
|
|
||
| assertEquals("[]", program.errors().toString()); | ||
|
|
||
| // Generate Assembly file | ||
| File assemblyFile = getFileReplaceExtension(inFile, ".s"); | ||
| PrintStream out = new PrintStream(new FileOutputStream(assemblyFile)); | ||
| program.genCode(out); | ||
| out.close(); | ||
|
|
||
| // Generate object file | ||
| File objectFile = getFileReplaceExtension(inFile, ".o"); | ||
| ArrayList<String> cmdAs = new ArrayList<String>(); | ||
| cmdAs.add("as"); | ||
| cmdAs.add("--gstabs"); | ||
| cmdAs.add(assemblyFile.getAbsolutePath()); | ||
| cmdAs.add("-o"); | ||
| cmdAs.add(objectFile.getAbsolutePath()); | ||
| execute(cmdAs); | ||
|
|
||
| // Link object file and generate executable file | ||
| File execFile = getFileReplaceExtension(inFile, ".elf"); | ||
| ArrayList<String> cmdLd = new ArrayList<String>(); | ||
| cmdLd.add("ld"); | ||
| cmdLd.add(objectFile.getAbsolutePath()); | ||
| cmdLd.add("-o"); | ||
| cmdLd.add(execFile.getAbsolutePath()); | ||
| execute(cmdLd); | ||
|
|
||
| // Run the executable file | ||
| String output = execute(Arrays.asList(execFile.getAbsolutePath())); | ||
| compareOutput(output, outFile, expectedFile); | ||
| } | ||
|
|
||
| private String execute(List<String> cmd) throws IOException, InterruptedException { | ||
| ProcessBuilder pb = new ProcessBuilder(cmd); | ||
| Process process = pb.start(); | ||
| process.getOutputStream().close(); | ||
| process.waitFor(); | ||
|
|
||
| String standardError = inputStreamToString(process.getErrorStream()); | ||
| assertEquals( | ||
| "Standard error was not empty when running command '" + cmd.get(0) + "'", | ||
| "", standardError); | ||
| assertEquals( | ||
| "Exit code was not zero (error occured) when running command '" + cmd.get(0) + "'", | ||
| 0, process.exitValue()); | ||
|
|
||
| return inputStreamToString(process.getInputStream()); | ||
| } | ||
|
|
||
| private String inputStreamToString(InputStream is) { | ||
| StringBuilder sb = new StringBuilder(); | ||
| try { | ||
| BufferedReader br = new BufferedReader(new InputStreamReader(is)); | ||
| String line; | ||
| while ((line = br.readLine()) != null) { | ||
| sb.append(line).append("\n"); | ||
| } | ||
| } catch (IOException e) { | ||
| e.printStackTrace(); | ||
| System.exit(1); | ||
| } | ||
| return sb.toString(); | ||
| } | ||
|
|
||
| @SuppressWarnings("javadoc") | ||
| @Parameters(name = "{0}") | ||
| public static Iterable<Object[]> getTests() { | ||
| return getTestParameters(TEST_DIR); | ||
| } | ||
| } |
| @@ -0,0 +1,59 @@ | ||
| %class "LangParser"; | ||
| %package "lang.ast"; | ||
|
|
||
| %embed {: | ||
| static public class SyntaxError extends RuntimeException { public SyntaxError(String msg) {super(msg);}} | ||
| // Disable syntax error recovery | ||
| protected void recoverFromError(Symbol token, TokenStream in) { | ||
| throw new SyntaxError("Cannot recover from the syntax error"); | ||
| } | ||
| :}; | ||
|
|
||
| %terminals LET, IN, END, ASSIGN, MUL, DIV, ID, NUMERAL; | ||
|
|
||
| // new terminals for Calc 2.0 | ||
| %terminals ASK, USER; | ||
|
|
||
| %typeof program = "Program"; | ||
| %typeof exp = "Expr"; | ||
| %typeof factor = "Expr"; | ||
| %typeof let = "Let"; | ||
| %typeof ask = "Ask"; | ||
| %typeof numeral = "Numeral"; | ||
| %typeof id_decl = "IdDecl"; | ||
| %typeof id_use = "IdUse"; | ||
| %typeof binding = "Binding"; | ||
| %typeof binding_list = "List"; | ||
|
|
||
| %goal program; | ||
|
|
||
| program = exp.a {: return new Program(a); :} ; | ||
|
|
||
| exp = | ||
| factor | ||
| | exp.a MUL factor.b {: return new Mul(a, b); :} | ||
| | exp.a DIV factor.b {: return new Div(a, b); :} | ||
| ; | ||
|
|
||
| factor = | ||
| let | ||
| | ask | ||
| | numeral | ||
| | id_use | ||
| ; | ||
|
|
||
| let = LET binding_list.a IN exp.b END {: return new Let(a, b); :} ; | ||
|
|
||
| ask = ASK USER {: return new Ask(); :} ; | ||
|
|
||
| binding_list = | ||
| binding.a {: return new List().add(a); :} | ||
| | binding_list.a binding.b {: return a.add(b); :} | ||
| ; | ||
|
|
||
| binding = id_decl.a ASSIGN exp.b {: return new Binding(a, b); :} ; | ||
|
|
||
| numeral = NUMERAL.num {: return new Numeral(num); :} ; | ||
|
|
||
| id_decl = ID.id {: return new IdDecl(id); :} ; | ||
| id_use = ID.id {: return new IdUse(id); :} ; |
| @@ -0,0 +1,53 @@ | ||
| package lang.ast; // The generated scanner will belong to the package lang.ast | ||
|
|
||
| import lang.ast.LangParser.Terminals; // The terminals are implicitly defined in the parser | ||
| import lang.ast.LangParser.SyntaxError; | ||
|
|
||
| %% | ||
|
|
||
| // define the signature for the generated scanner | ||
| %public | ||
| %final | ||
| %class LangScanner | ||
| %extends beaver.Scanner | ||
|
|
||
| // the interface between the scanner and the parser is the nextToken() method | ||
| %type beaver.Symbol | ||
| %function nextToken | ||
|
|
||
| // store line and column information in the tokens | ||
| %line | ||
| %column | ||
|
|
||
| // this code will be inlined in the body of the generated scanner class | ||
| %{ | ||
| private beaver.Symbol sym(short id) { | ||
| return new beaver.Symbol(id, yyline + 1, yycolumn + 1, yylength(), yytext()); | ||
| } | ||
| %} | ||
|
|
||
| // macros | ||
| WhiteSpace = [ ] | \t | \f | \n | \r | ||
| ID = [a-zA-Z]+ | ||
| Numeral = [0-9]+ | ||
|
|
||
| %% | ||
|
|
||
| // discard whitespace information | ||
| {WhiteSpace} { } | ||
|
|
||
| // token definitions | ||
| "let" { return sym(Terminals.LET); } | ||
| "in" { return sym(Terminals.IN); } | ||
| "end" { return sym(Terminals.END); } | ||
| "ask" { return sym(Terminals.ASK); } | ||
| "user" { return sym(Terminals.USER); } | ||
| "=" { return sym(Terminals.ASSIGN); } | ||
| "*" { return sym(Terminals.MUL); } | ||
| "/" { return sym(Terminals.DIV); } | ||
| {ID} { return sym(Terminals.ID); } | ||
| {Numeral} { return sym(Terminals.NUMERAL); } | ||
| <<EOF>> { return sym(Terminals.EOF); } | ||
|
|
||
| /* error fallback */ | ||
| [^] { throw new SyntaxError("Illegal character <"+yytext()+">"); } |
| @@ -0,0 +1,6 @@ | ||
| let | ||
| a = 4 | ||
| b = 2 | ||
| in | ||
| a / b | ||
| end |
| @@ -0,0 +1 @@ | ||
| 2 |
| @@ -0,0 +1 @@ | ||
| 765/49 |
| @@ -0,0 +1 @@ | ||
| 15 |
| @@ -0,0 +1 @@ | ||
| 49/764 |
| @@ -0,0 +1 @@ | ||
| 0 |
| @@ -0,0 +1,6 @@ | ||
| let | ||
| a = 3 | ||
| b = 4 | ||
| in | ||
| a * b | ||
| end |
| @@ -0,0 +1 @@ | ||
| 12 |