Large diffs are not rendered by default.

@@ -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();
}

Large diffs are not rendered by default.

Large diffs are not rendered by default.

@@ -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);
}
}

Large diffs are not rendered by default.

Large diffs are not rendered by default.

@@ -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">&lt;NUMERAL:String&gt;</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);
}
}

Large diffs are not rendered by default.

@@ -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