Initial Commit

This commit is contained in:
2018-10-15 12:47:14 -06:00
commit 0c531ffff9
55 changed files with 7285 additions and 0 deletions
+271
View File
@@ -0,0 +1,271 @@
/* basic application to be extended
*/
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.ArrayList;
public class Basic extends JFrame implements Runnable, KeyListener,
MouseListener,
MouseMotionListener,
WindowListener
{
protected static int FPS = 50; // desired frames per second
private int stepNumber;
// part of the basic framework
private Thread theThread; //to control the animation
private boolean waiting;
protected int pixelWidth, pixelHeight; // dimensions of window in pixels
private int ulcX, ulcY; // location of upper left corner of window on screen
private Color backgroundColor; // background color of entire window
private double mouseX, mouseY; // maintain correct mouse location
private int whichCamera; // maintain which camera's pixel grid region mouse is in
private Graphics dbg;
private Image dbImage = null;
protected ArrayList<Camera> cameras;
public Basic( String title, int ulx, int uly, int pw, int ph )
{
super( title ); // call JFrame
ulcX = ulx; ulcY = uly;
pixelWidth = pw; pixelHeight = ph;
setBounds(ulcX, ulcY, pixelWidth, pixelHeight );
setResizable( false );
addKeyListener(this);
// setFocusable(true);
// requestFocus();
addMouseListener(this);
addMouseMotionListener(this);
addWindowListener(this);
cameras = new ArrayList<Camera>();
stepNumber = 0;
// force mouse to be in center of window at start
mouseX = pixelWidth/2;
mouseY = pixelHeight/2;
}
public void start()
{
setVisible(true);
// physically draw the mouse cursor where we want it
try{
Robot rob = new Robot();
rob.mouseMove( ulcX+pixelWidth/2, ulcY+pixelHeight/2 );
}catch(Exception e){}
if (theThread == null)
theThread = new Thread(this);
theThread.start();
}
public void run()
{
while (true)
{
stepNumber++;
long startTime = System.nanoTime();
render();
paintScreen();
long stopTime = System.nanoTime();
double elapsed = (stopTime-startTime)/1000000.0; // milliseconds
int waitTime = 1000/FPS - (int) Math.round( elapsed );
if( waitTime < 1 )
waitTime = 1;
try {
Thread.sleep(waitTime);
}
catch (InterruptedException ie)
{System.err.println("OOPS");}
}
}
private void render()
{
if( dbImage == null )
{// create the buffer
dbImage = createImage( pixelWidth, pixelHeight );
if( dbImage == null )
{
System.out.println("dbImage is null???");
return;
}
else
{// dbg is created, tell Camera
dbg = dbImage.getGraphics();
Camera.setGraphicsContext( dbg );
}
}
// clear the background of entire window
dbg.setColor( backgroundColor );
dbg.fillRect(0,0,pixelWidth,pixelHeight);
// give app a chance to update its instance variables
// and then draw stuff to dbg
step();
}
private void paintScreen()
{
Graphics gr;
try{
gr = this.getGraphics();
if( gr != null && dbImage != null )
gr.drawImage(dbImage,0,0,null);
Toolkit.getDefaultToolkit().sync(); // maybe not needed?
gr.dispose();
}
catch(Exception e)
{
System.out.println("graphics context error" + e );
System.exit(1);
}
}
// override this method with code to display stuff
// and update app instance variables
public void step()
{
System.out.println("Step number: " + getStepNumber() );
}
public int getStepNumber()
{
return stepNumber;
}
// implement KeyListener:
// ******************************************************************
public void keyPressed(KeyEvent e){}
public void keyReleased(KeyEvent e){}
public void keyTyped(KeyEvent e){}
// implement MouseListener:
// ******************************************************************
public void mouseClicked(MouseEvent e)
{
updateMouse(e);
}
public void mouseEntered(MouseEvent e)
{
updateMouse(e);
}
public void mouseExited(MouseEvent e)
{
updateMouse(e);
}
public void mousePressed(MouseEvent e)
{
updateMouse(e);
}
public void mouseReleased(MouseEvent e)
{
updateMouse(e);
}
// implement MouseMotionListener:
// ******************************************************************
public void mouseDragged(MouseEvent e)
{
updateMouse(e);
}
public void mouseMoved(MouseEvent e)
{
updateMouse(e);
}
private void updateMouse( MouseEvent e )
{
int ix = e.getX(), iy = e.getY();
// determine which camera this mouse event hits
// and compute mouseX, mouseY in that camera's graph paper coords
whichCamera = -1;
Camera ac=null, temp;
for( int k=0; k<cameras.size(); k++ )
{
temp = cameras.get(k);
if( temp.hits(ix,iy) )
{
ac = temp;
whichCamera = k;
}
}
if( whichCamera == -1 )
{
mouseX=0; mouseY=0;
whichCamera = -1;
}
else
{// mouse event happened in an active camera, update coords for that cam
mouseX = ac.invMapX( ix );
mouseY = ac.invMapY( iy );
}
}
// -----------------------------------------------------------------
// These can be called, but don't override
protected double getMouseX()
{
return mouseX;
}
protected double getMouseY()
{
return mouseY;
}
protected int getMouseCamera()
{
return whichCamera;
}
// set background color of entire window
protected void setBackgroundColor( Color color )
{
backgroundColor = color;
}
// implement WindowListener:
// ******************************************************************^M
public void windowActivated(WindowEvent e){}
public void windowClosed(WindowEvent e){}
public void windowClosing(WindowEvent e)
{
System.exit(0);
} // end of windowClosing()
public void windowDeactivated(WindowEvent e){}
public void windowDeiconified(WindowEvent e){}
public void windowIconified(WindowEvent e){}
public void windowOpened(WindowEvent e){}
}
+330
View File
@@ -0,0 +1,330 @@
import java.awt.*;
import java.awt.font.FontRenderContext;
import java.awt.font.GlyphVector;
public class Camera
{
// whenever graphics context is changed by Basic, all
// cameras get shared access to that context
// *******************************************************************
private static Graphics gc; // the graphics context
public static void setGraphicsContext( Graphics g )
{
gc = g;
}
// instance variables
// *******************************************************************
private Color backgroundColor;
private int px, py, pw, ph; // the pixel grid rectangle where draw
private double left, right, bottom, top; // the visible rectangle in the
// virtual graph paper
private Font currentFont; // the current font
private int currentFontHeight; // height of a typical char in current font
// methods for creating and changing camera properties
// *******************************************************************
// construct a camera with both rectangles (pixelgrid and graph paper)
// specified, and background color
// Note: the top coordinate of the visible region is computed so that
// the visible region has the same aspect ratio as the pixel
// grid region (can change if desired by using setRegion)
public Camera( int vx, int vy, int vw, int vh,
double l, double r, double b,
Color bc )
{
px=vx; py=vy; pw=vw; ph=vh;
left=l; right=r; bottom=b; top=bottom + ph*(right-left)/pw;
backgroundColor=bc;
}
// construct a camera with both rectangles specified, and back color
// Note: this constructor lets you select coordinates each way,
// dangerous to draw geometrical entities
public Camera( int vx, int vy, int vw, int vh,
double l, double r, double b, double t,
Color bc )
{
px=vx; py=vy; pw=vw; ph=vh;
left=l; right=r; bottom=b; top=t;
backgroundColor=bc;
}
// set the background color
// (might want to change it after camera is first built)
public void setBackgroundColor( Color color )
{
backgroundColor = color;
}
// move the graph paper viewing rectangle
public void setRegion( double l, double r, double b, double t )
{
left=l; right=r; bottom=b; top=t;
}
// shift the graph paper rectangle by given fractions in x and y
public void shiftRegion( double fx, double fy )
{
double dx = fx*(right-left);
double dy = fy*(top-bottom);
left += dx; right += dx;
bottom += dy; top += dy;
}
// scale the graph paper rectangle by given fractions in x and y,
// keeping the center fixed
public void scaleRegion( double sx, double sy )
{
double cx = (left+right)/2, cy = (bottom+top)/2;
double dx = sx*(right-left);
double dy = sy*(top-bottom);
left = cx - dx/2; right = cx + dx/2;
bottom = cy - dy/2; top = cy + dy/2;
}
public double getRegionLeft()
{
return left;
}
public double getRegionBottom()
{
return bottom;
}
public double getRegionWidth()
{
return right-left;
}
public double getRegionHeight()
{
return top-bottom;
}
// methods for drawing things used by application
// *******************************************************************
// prepare pixel grid for this camera to draw in its region
public void activate()
{
// set up clipping so no drawing can occur outside this camera's
// pixel grid region
gc.setClip(null);
gc.clipRect( px, py, pw, ph );
// clear the background of entire window
gc.setColor( backgroundColor );
gc.fillRect( px, py, pw, ph );
}
// set the drawing color
public void setColor( Color color )
{
gc.setColor( color );
}
// draw a rectangle---just the border---with lower left corner (x,y),
// width w, height h, in graph paper coords
public void drawRect( double x, double y, double w, double h )
{
rect( false, x, y, w, h );
}
// draw a filled rectangle with lower left corner (x,y),
// width w, height h, in graph paper coords
public void fillRect( double x, double y, double w, double h )
{
rect( true, x, y, w, h );
}
public void drawCircle( double x, double y, double r )
{
circle( false, x, y, r );
}
public void fillCircle( double x, double y, double r )
{
circle( true, x, y, r );
}
public void drawTri( double x1, double y1,
double x2, double y2,
double x3, double y3 )
{
tri( false, x1, y1, x2, y2, x3, y3 );
}
public void fillTri( double x1, double y1,
double x2, double y2,
double x3, double y3 )
{
tri( true, x1, y1, x2, y2, x3, y3 );
}
public void drawLine( double x1, double y1,
double x2, double y2 )
{
gc.drawLine( mapX(x1), mapY(y1), mapX(x2), mapY(y2) );
}
public void drawText( String text, double x, double y )
{
gc.drawString( text, mapX(x), mapY(y) );
}
public void setFont( Font f )
{
currentFont = f;
Rectangle r = figureBounds( "e", currentFont );
currentFontHeight = r.height;
gc.setFont( f );
}
// compute the width of the text in the current font
// in the visible region
public double getWidth( String text )
{
FontMetrics fm = gc.getFontMetrics();
double w = invMapX( fm.stringWidth( text ) );
return w;
}
// compute the height of the current font
// in the visible region
public double getHeight()
{
FontMetrics fm = gc.getFontMetrics();
double h = invMapY( fm.getHeight() );
return h;
}
// draw the text centered about (x,y)
// using height of typical char (as in setFont) for vertical centering
public void drawCenteredText( String text, double x, double y )
{
FontMetrics fm = gc.getFontMetrics();
int w = fm.stringWidth( text );
gc.drawString( text, mapX(x)-w/2, mapY(y) + currentFontHeight/2 );
}
// figure bounds of the given string
private Rectangle figureBounds( String s, Font font )
{
Graphics2D g2 = (Graphics2D) gc;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2.setFont( font );
FontRenderContext frc = g2.getFontRenderContext();
GlyphVector gv = g2.getFont().createGlyphVector(frc, s);
return gv.getPixelBounds(null, 0, 0);
}
// draw the text horizontally centered about x,
// with baseline at y
public void drawHorizCenteredText( String text, double x, double y )
{
FontMetrics fm = gc.getFontMetrics();
int w = fm.stringWidth( text );
gc.drawString( text, mapX(x)-w/2, mapY(y) );
}
// draw the text vertically centered about y,
// with left edge at x
public void drawVertCenteredText( String text, double x, double y )
{
gc.drawString( text, mapX(x), mapY(y) + currentFontHeight/2 );
}
// use these carefully!
// -----------------------------------------------------------------
public int mapX( double x )
{
return px + nicefy( ((x-left)/(right-left))*pw );
}
public int mapY( double y )
{
return py + ph - nicefy( ((y-bottom)/(top-bottom))*ph );
}
// does the mouse location in pixel grid (ix,iy) hit this
// camera's pixel grid region
public boolean hits( int ix, int iy )
{
boolean result = px<=ix && ix<=px+pw && py<=iy && iy<=py+ph;
return result;
}
public double invMapX( int ix )
{
return left + (right-left)*(ix-px)/pw;
}
public double invMapY( int iy )
{
return bottom + (top-bottom)*(ph-(iy-py))/ph;
}
// -----------------------------------------------------------------
// methods used internally
private int nicefy( double a )
{
return (int) Math.round(a);
}
// draw or fill a rectangle
private void rect( boolean fill, double x, double y, double w, double h )
{
int x1, x2, y1, y2;
x1 = mapX(x); x2 = mapX(x+w);
y1 = mapY(y); y2 = mapY(y+h);
if( fill )
gc.fillRect( x1, y2, x2-x1, y1-y2 );
else
gc.drawRect( x1, y2, x2-x1, y1-y2 );
}
private void circle( boolean fill, double x, double y, double r )
{
int x1=mapX(x-r), y1=mapY(y+r), x2=mapX(x+r);
if( fill )
gc.fillOval( x1, y1, x2-x1, x2-x1 );
else
gc.drawOval( x1, y1, x2-x1, x2-x1 );
}
private void tri( boolean fill, double x1, double y1,
double x2, double y2,
double x3, double y3 )
{
int[] x = new int[3]; x[0]=mapX(x1); x[1]=mapX(x2); x[2]=mapX(x3);
int[] y = new int[3]; y[0]=mapY(y1); y[1]=mapY(y2); y[2]=mapY(y3);
if( fill )
gc.fillPolygon( x, y, 3 );
else
gc.drawPolygon( x, y, 3 );
}
}
+25
View File
@@ -0,0 +1,25 @@
import java.util.Scanner;
public class Corgi {
public static void main(String[] args) {
System.out.print("Enter name of Corgi program file: ");
Scanner keys = new Scanner( System.in );
String name = keys.nextLine();
Lexer lex = new Lexer( name );
Parser parser = new Parser( lex );
// start with <statements>
Node root = parser.parseProgram();
// display parse tree for debugging/testing:
TreeViewer viewer = new TreeViewer("Parse Tree", 0, 0, 800, 500, root );
// execute the parse tree
// root.execute();
}// main
}
+275
View File
@@ -0,0 +1,275 @@
import java.io.BufferedReader;
import java.io.FileReader;
import java.util.Scanner;
import java.util.Stack;
public class Lexer {
public static String margin = "";
// holds any number of tokens that have been put back
private Stack<Token> stack;
// the source of physical symbols
// (use BufferedReader instead of Scanner because it can
// read a single physical symbol)
private BufferedReader input;
// one lookahead physical symbol
private int lookahead;
// construct a Lexer ready to produce tokens from a file
public Lexer( String fileName ) {
try {
input = new BufferedReader( new FileReader( fileName ) );
}
catch(Exception e) {
error("Problem opening file named [" + fileName + "]" );
}
stack = new Stack<Token>();
lookahead = 0; // indicates no lookahead symbol present
}// constructor
// produce the next token
private Token getNext() {
if( ! stack.empty() ) {
// produce the most recently putback token
Token token = stack.pop();
return token;
}
else {
// produce a token from the input source
int state = 1; // state of FA
String data = ""; // specific info for the token
boolean done = false;
int sym; // holds current symbol
do {
sym = getNextSymbol();
// System.out.println("current symbol: " + sym + " state = " + state );
if ( state == 1 ) {
if ( sym == 9 || sym == 10 || sym == 13 ||
sym == 32 ) {// whitespace
state = 1;
}
else if ( 'a'<=sym && sym<='z' ) {// lowercase
data += (char) sym;
state = 2;
}
else if ( digit( sym ) ) {
data += (char) sym;
state = 3;
}
else if ( sym == '.' ) {
data += (char) sym;
state = 5;
}
else if ( sym == '\"' ) {
state = 6;
}
else if ( sym == '+' || sym == '-' || sym == '*' ||
sym == '/' || sym == '(' || sym == ')' ||
sym == ',' || sym == '='
) {
data += (char) sym;
state = 8;
done = true;
}
else if ( sym == -1 ) {// end of file
state = 9;
done = true;
}
else {
error("Error in lexical analysis phase with symbol "
+ sym + " in state " + state );
}
}
else if ( state == 2 ) {
if ( letter(sym) || digit(sym) ) {
data += (char) sym;
state = 2;
}
else {// done with variable token
putBackSymbol( sym );
done = true;
}
}
else if ( state == 3 ) {
if ( digit(sym) ) {
data += (char) sym;
state = 3;
}
else if ( sym == '.' ) {
data += (char) sym;
state = 4;
}
else {// done with number token
putBackSymbol( sym );
done = true;
}
}
else if ( state == 4 ) {
if ( digit(sym) ) {
data += (char) sym;
state = 4;
}
else {// done with number token
putBackSymbol( sym );
done = true;
}
}
else if ( state == 5 ) {
if ( digit(sym) ) {
data += (char) sym;
state = 4;
}
else {
error("Error in lexical analysis phase with symbol "
+ sym + " in state " + state );
}
}
else if ( state == 6 ) {
if ( (' '<=sym && sym<='~') && sym != '\"' ) {
data += (char) sym;
state = 6;
}
else if ( sym == '\"' ) {
state = 7;
done = true;
}
}
// note: states 7, 8, and 9 are accepting states with
// no arcs out of them, so they are handled
// in the arc going into them
}while( !done );
// generate token depending on stopping state
Token token;
if ( state == 2 ) {
// see if data matches any special words
if ( data.equals("input") ) {
return new Token( "bif0", data );
}
else if ( data.equals("sqrt") || data.equals("cos") ||
data.equals("sin") || data.equals("atan")
) {
return new Token( "bif1", data );
}
else if ( data.equals("pow") ) {
return new Token( "bif2", data );
}
else if ( data.equals("print") ) {
return new Token( "print", "" );
}
else if ( data.equals("newline") ) {
return new Token( "newline", "" );
}
else {// is just a variable
return new Token( "var", data );
}
}
else if ( state == 3 || state == 4 ) {
return new Token( "num", data );
}
else if ( state == 7 ) {
return new Token( "string", data );
}
else if ( state == 8 ) {
return new Token( "single", data );
}
else if ( state == 9 ) {
return new Token( "eof", data );
}
else {// Lexer error
error("somehow Lexer FA halted in bad state " + state );
return null;
}
}// else generate token from input
}// getNext
public Token getNextToken() {
Token token = getNext();
System.out.println(" got token: " + token );
return token;
}
public void putBackToken( Token token )
{
System.out.println( margin + "put back token " + token.toString() );
stack.push( token );
}
// next physical symbol is the lookahead symbol if there is one,
// otherwise is next symbol from file
private int getNextSymbol() {
int result = -1;
if( lookahead == 0 ) {// is no lookahead, use input
try{ result = input.read(); }
catch(Exception e){}
}
else {// use the lookahead and consume it
result = lookahead;
lookahead = 0;
}
return result;
}
private void putBackSymbol( int sym ) {
if( lookahead == 0 ) {// sensible to put one back
lookahead = sym;
}
else {
System.out.println("Oops, already have a lookahead " + lookahead +
" when trying to put back symbol " + sym );
System.exit(1);
}
}// putBackSymbol
private boolean letter( int code ) {
return 'a'<=code && code<='z' ||
'A'<=code && code<='Z';
}
private boolean digit( int code ) {
return '0'<=code && code<='9';
}
private boolean printable( int code ) {
return ' '<=code && code<='~';
}
private static void error( String message ) {
System.out.println( message );
System.exit(1);
}
public static void main(String[] args) {
System.out.print("Enter file name: ");
Scanner keys = new Scanner( System.in );
String name = keys.nextLine();
Lexer lex = new Lexer( name );
Token token;
do{
token = lex.getNext();
System.out.println( token.toString() );
}while( ! token.getKind().equals( "eof" ) );
}
}
+75
View File
@@ -0,0 +1,75 @@
/*
store variable names with stored value
*/
import java.util.ArrayList;
public class MemTable {
private ArrayList<String> names;
private ArrayList<Double> values;
public MemTable() {
names = new ArrayList<String>();
values = new ArrayList<Double>();
}
public String toString() {
String s = "----\n";
for( int k=0; k<names.size(); k++ ) {
s += names.get(k) + " " + values.get(k) + "\n";
}
return s;
}
public int size() {
return names.size();
}
// store value for name, adding name if not already
// there
public void store( String name, double value ) {
int loc = findName( name );
if ( loc < 0 ) {// add new pair
names.add( name );
values.add( value );
}
else {// change value for existing pair
values.set( loc, value );
}
}// store
// retrieve value for given name
public double retrieve( String name ) {
int loc = findName( name );
if ( loc >= 0 ) {// add new pair
return values.get( loc );
}
else {
System.out.println("variable [" + name + "] not found");
System.exit(1);
return 0;
}
}// retrieve
// return index of name in names, or -1 if
// not found
private int findName( String name ) {
// locate name
int loc = -1;
for (int k=0; k<names.size() && loc<0; k++) {
if ( names.get(k).equals(name) ) {
loc = k;
}
}
return loc;
}// findName
}
+223
View File
@@ -0,0 +1,223 @@
/* a Node holds one node of a parse tree
with several pointers to children used
depending on the kind of node
*/
import java.awt.*;
import java.util.Scanner;
public class Node {
public static int count = 0; // maintain unique id for each node
private int id;
private String kind; // non-terminal or terminal category for the node
private String info; // extra information about the node such as
// the actual identifier for an I
// references to children in the parse tree
private Node first, second, third;
// memory table shared by all nodes
private static MemTable table = new MemTable();
private static Scanner keys = new Scanner( System.in );
// construct a common node with no info specified
public Node( String k, Node one, Node two, Node three ) {
kind = k; info = "";
first = one; second = two; third = three;
id = count;
count++;
System.out.println( this );
}
// construct a node with specified info
public Node( String k, String inf, Node one, Node two, Node three ) {
kind = k; info = inf;
first = one; second = two; third = three;
id = count;
count++;
System.out.println( this );
}
// construct a node that is essentially a token
public Node( Token token ) {
kind = token.getKind(); info = token.getDetails();
first = null; second = null; third = null;
id = count;
count++;
System.out.println( this );
}
public String toString() {
return "#" + id + "[" + kind + "," + info + "]<" + nice(first) +
" " + nice(second) + ">";
}
public String nice( Node node ) {
if ( node == null ) {
return "";
}
else {
return "" + node.id;
}
}
// produce array with the non-null children
// in order
private Node[] getChildren() {
int count = 0;
if( first != null ) count++;
if( second != null ) count++;
if( third != null ) count++;
Node[] children = new Node[count];
int k=0;
if( first != null ) { children[k] = first; k++; }
if( second != null ) { children[k] = second; k++; }
if( third != null ) { children[k] = third; k++; }
return children;
}
//******************************************************
// graphical display of this node and its subtree
// in given camera, with specified location (x,y) of this
// node, and specified distances horizontally and vertically
// to children
public void draw( Camera cam, double x, double y, double h, double v ) {
System.out.println("draw node " + id );
// set drawing color
cam.setColor( Color.black );
String text = kind;
if( ! info.equals("") ) text += "(" + info + ")";
cam.drawHorizCenteredText( text, x, y );
// positioning of children depends on how many
// in a nice, uniform manner
Node[] children = getChildren();
int number = children.length;
System.out.println("has " + number + " children");
double top = y - 0.75*v;
if( number == 0 ) {
return;
}
else if( number == 1 ) {
children[0].draw( cam, x, y-v, h/2, v ); cam.drawLine( x, y, x, top );
}
else if( number == 2 ) {
children[0].draw( cam, x-h/2, y-v, h/2, v ); cam.drawLine( x, y, x-h/2, top );
children[1].draw( cam, x+h/2, y-v, h/2, v ); cam.drawLine( x, y, x+h/2, top );
}
else if( number == 3 ) {
children[0].draw( cam, x-h, y-v, h/2, v ); cam.drawLine( x, y, x-h, top );
children[1].draw( cam, x, y-v, h/2, v ); cam.drawLine( x, y, x, top );
children[2].draw( cam, x+h, y-v, h/2, v ); cam.drawLine( x, y, x+h, top );
}
else {
System.out.println("no Node kind has more than 3 children???");
System.exit(1);
}
}// draw
public static void error( String message ) {
System.out.println( message );
System.exit(1);
}
// ask this node to execute itself
// (for nodes that don't return a value)
public void execute() {
if ( kind.equals("stmts") ) {
// insert code here for Exercise 15
}
else if ( kind.equals("prtstr") ) {
System.out.print( info );
}
else if ( kind.equals("prtexp") ) {
// insert code here for Exercise 15
}
else if ( kind.equals("nl") ) {
System.out.print( "\n" );
}
else if ( kind.equals("sto") ) {
// insert code here for Exercise 15
}
else {
error("Unknown kind of node [" + kind + "]");
}
}// execute
// compute and return value produced by this node
public double evaluate() {
if ( kind.equals("num") ) {
return Double.parseDouble( info );
}
else if ( kind.equals("var") ) {
// insert code here for Exercise 15
}
else if ( kind.equals("+") || kind.equals("-") ) {
// insert code here for Exercise 15
}
else if ( kind.equals("*") || kind.equals("/") ) {
// insert code here for Exercise 15
}
else if ( kind.equals("input") ) {
return keys.nextDouble();
}
else if ( kind.equals("sqrt") || kind.equals("cos") ||
kind.equals("sin") || kind.equals("atan")
) {
double value = first.evaluate();
if ( kind.equals("sqrt") )
return Math.sqrt(value);
else if ( kind.equals("cos") )
return Math.cos( Math.toRadians( value ) );
else if ( kind.equals("sin") )
return Math.sin( Math.toRadians( value ) );
else if ( kind.equals("atan") )
return Math.toDegrees( Math.atan( value ) );
else {
error("unknown function name [" + kind + "]");
return 0;
}
}
else if ( kind.equals("pow") ) {
// insert code here for Exercise 15
}
else if ( kind.equals("opp") ) {
// insert code here for Exercise 15
}
else {
error("Unknown node kind [" + kind + "]");
return 0;
}
}// evaluate
}// Node
+202
View File
@@ -0,0 +1,202 @@
/*
This class provides a recursive descent parser
for Corgi (a simple calculator language),
creating a parse tree which can be interpreted
to simulate execution of a Corgi program
*/
public class Parser {
private Lexer lex;
public Parser( Lexer lexer ) {
lex = lexer;
}
public Node parseProgram() {
return parseStatements();
}
private Node parseStatements() {
System.out.println("-----> parsing <statements>:");
Node first = parseStatement();
// look ahead to see if there are more statement's
Token token = lex.getNextToken();
if ( token.isKind("eof") ) {
return new Node( "stmts", first, null, null );
}
else {
lex.putBackToken( token );
Node second = parseStatements();
return new Node( "stmts", first, second, null );
}
}// <statements>
private Node parseStatement() {
System.out.println("-----> parsing <statement>:");
Token token = lex.getNextToken();
// ---------------->>> print <string> or print <expr>
if ( token.isKind("print") ) {
token = lex.getNextToken();
if ( token.isKind("string") ) {// print <string>
return new Node( "prtstr", token.getDetails(),
null, null, null );
}
else {// must be first token in <expr>
// put back the token we looked ahead at
lex.putBackToken( token );
Node first = parseExpr();
return new Node( "prtexp", first, null, null );
}
// ---------------->>> newline
}
else if ( token.isKind("newline") ) {
return new Node( "nl", null, null, null );
}
// --------------->>> <var> = <expr>
else if ( token.isKind("var") ) {
String varName = token.getDetails();
token = lex.getNextToken();
errorCheck( token, "single", "=" );
Node first = parseExpr();
return new Node( "sto", varName, first, null, null );
}
else {
System.out.println("Token " + token +
" can't begin a statement");
System.exit(1);
return null;
}
}// <statement>
private Node parseExpr() {
System.out.println("-----> parsing <expr>");
Node first = parseTerm();
// look ahead to see if there's an addop
Token token = lex.getNextToken();
if ( token.matches("single", "+") ||
token.matches("single", "-")
) {
Node second = parseExpr();
return new Node( token.getDetails(), first, second, null );
}
else {// is just one term
lex.putBackToken( token );
return first;
}
}// <expr>
private Node parseTerm() {
System.out.println("-----> parsing <term>");
Node first = parseFactor();
// look ahead to see if there's a multop
Token token = lex.getNextToken();
if ( token.matches("single", "*") ||
token.matches("single", "/")
) {
Node second = parseTerm();
return new Node( token.getDetails(), first, second, null );
}
else {// is just one factor
lex.putBackToken( token );
return first;
}
}// <term>
private Node parseFactor() {
System.out.println("-----> parsing <factor>");
Token token = lex.getNextToken();
if ( token.isKind("num") ) {
return new Node("num", token.getDetails(), null, null, null );
}
else if ( token.isKind("var") ) {
return new Node("var", token.getDetails(), null, null, null );
}
else if ( token.matches("single","(") ) {
Node first = parseExpr();
token = lex.getNextToken();
errorCheck( token, "single", ")" );
return first;
}
else if ( token.isKind("bif0") ) {
String bifName = token.getDetails();
token = lex.getNextToken();
errorCheck( token, "single", "(" );
token = lex.getNextToken();
errorCheck( token, "single", ")" );
return new Node( bifName, null, null, null );
}
else if ( token.isKind("bif1") ) {
String bifName = token.getDetails();
token = lex.getNextToken();
errorCheck( token, "single", "(" );
Node first = parseExpr();
token = lex.getNextToken();
errorCheck( token, "single", ")" );
return new Node( bifName, first, null, null );
}
else if ( token.isKind("bif2") ) {
String bifName = token.getDetails();
token = lex.getNextToken();
errorCheck( token, "single", "(" );
Node first = parseExpr();
token = lex.getNextToken();
errorCheck( token, "single", "," );
Node second = parseExpr();
token = lex.getNextToken();
errorCheck( token, "single", ")" );
return new Node( bifName, first, second, null );
}
else if ( token.matches("single","-") ) {
Node first = parseFactor();
return new Node("opp", first, null, null );
}
else {
System.out.println("Can't have factor starting with " + token );
System.exit(1);
return null;
}
}// <factor>
// check whether token is correct kind
private void errorCheck( Token token, String kind ) {
if( ! token.isKind( kind ) ) {
System.out.println("Error: expected " + token +
" to be of kind " + kind );
System.exit(1);
}
}
// check whether token is correct kind and details
private void errorCheck( Token token, String kind, String details ) {
if( ! token.isKind( kind ) ||
! token.getDetails().equals( details ) ) {
System.out.println("Error: expected " + token +
" to be kind=" + kind +
" and details=" + details );
System.exit(1);
}
}
}
+20
View File
@@ -0,0 +1,20 @@
main()
def fact( n )
if lt(n 1)
return 1
else
temp = fact( n-1 )
return n * temp
end
end
def main()
"enter n: "
n = input()
print( fact(n) )
end
+23
View File
@@ -0,0 +1,23 @@
main()
def main()
"enter a:"
a = input()
"enter b:"
b = input()
"enter c:"
c = input()
disc = pow(b,2) - 4*a*c
x1 = (-b - sqrt(disc) ) / (2*a)
x2 = (-b + sqrt(disc) ) / (2*a)
"x1: " print(x1) "\n"
"x2: " print(x2 ) "\n"
end
+31
View File
@@ -0,0 +1,31 @@
public class Token
{
private String kind;
private String details;
public Token( String k, String d )
{
kind = k; details = d;
}
public boolean isKind( String s )
{
return kind.equals( s );
}
public String getKind()
{ return kind; }
public String getDetails()
{ return details; }
public boolean matches( String k, String d ) {
return kind.equals(k) && details.equals(d);
}
public String toString()
{
return "[" + kind + "," + details + "]";
}
}
+78
View File
@@ -0,0 +1,78 @@
/* this class allows interactive
viewing of a tree built from
Node instances
*/
import java.awt.*;
import java.awt.event.KeyEvent;
public class TreeViewer extends Basic
{
// instance variables for the application:
// vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
private Node root; // root of tree to be viewed
private String keyInput;
private double horizGap = 2, vertGap = .5;
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
public TreeViewer( String title, int ulx, int uly, int pw, int ph,
Node tree )
{
super(title,ulx,uly,pw,ph);
setBackgroundColor( new Color( 128, 128, 200 ) );
// tree display
cameras.add( new Camera( 25, 45, pw-55, ph-75,
0, 10, 0, 5,
new Color( 200, 200, 200 ) ) );
root = tree;
super.start();
}
public void step()
{
// tree display
Camera cam = cameras.get(0);
cam.activate();
cam.setColor( Color.black );
root.draw( cam, 5.0, 4.0, horizGap, vertGap );
}// step
public void keyTyped( KeyEvent e ) {
char key = e.getKeyChar();
if( key == 'w' ){
horizGap *= 1.2;
}
else if( key == 'n' ){
horizGap /= 1.2;
}
}// keyTyped
public void keyPressed( KeyEvent e ) {
int code = e.getKeyCode();
if( code == KeyEvent.VK_LEFT ){
cameras.get(0).shiftRegion( -0.25, 0 );
}
else if( code == KeyEvent.VK_RIGHT ){
cameras.get(0).shiftRegion( 0.25, 0 );
}
else if( code == KeyEvent.VK_UP ){
cameras.get(0).shiftRegion( 0, 0.25 );
}
else if( code == KeyEvent.VK_DOWN ){
cameras.get(0).shiftRegion( 0, -0.25 );
}
}// keyPressed
}// TreeViewer
+66
View File
@@ -0,0 +1,66 @@
Note: this is the draft grammar, with notes and some thoughts,
for the Project 2 version of Corgi
------------------
<program> -> <funcCall> <funcDefs>
<funcDefs> -> <funcDef> | <funcDef> <funcDefs>
<funcDef> -> def <funcName> ( ) end |
def <funcName> ( <params> ) end |
def <funcName> ( ) <statements> end
def <funcName> ( <params> ) <statements> end
<funcName> -> <var>
<params> -> <var> | <var> <params>
<statements> -> <statement> |
<statement> <statements>
<funcCall> -> <var> ( ) |
<var> ( <args> )
<args> -> <expr> | <expr> <args>
<statement> -> <string> |
<var> = <expr> |
<funcCall> |
if <expr> else end |
if <expr> else <statements> end |
if <expr> <statements> else end |
if <expr> <statements> else <statements> end |
return <expr>
<expr> -> <term> | <term> + <expr> | <term> - <expr>
<term> -> <factor> | <factor> * <term> | <factor> / <term>
<factor> -> <number> | <var> |
( <expr> ) |
- <factor> |
<funcCall>
Notes:
slightly bizarre but cool: in Corgi you can just type a string anywhere
as a statement and it gets sent to the console (still have to use
print( <expr> ) to send a number)
no boolean type---use "non-zero is true, 0 is false"
there's only the if-else---always have to use it
no loop statements---use recursion!
the built-in functions fit the grammar just like user-defined functions---
will execute differently
change the Lexer to remove /* ..... */ type of comments---no tokens
produced
change Lexer to allow \n inside a string---put \\ in the Java string
Need to agree on names for all the many BIF's---see upcoming document
+19
View File
@@ -0,0 +1,19 @@
<program> -> <statements>
<statements> -> <statement> |
<statement> <statements>
<statement> -> print <string> |
print <expr> |
newline |
<var> = <expr>
<expr> -> <term> | <term> <addop> <expr>
<term> -> <factor> | <factor> <multop> <term>
<factor> -> <number> | <var> |
( <expr> ) |
<bif0> () |
<bif1> ( <expr> ) |
<bif2> ( <expr>, <expr> ) |
- <factor>
+87
View File
@@ -0,0 +1,87 @@
// ask this node to execute itself
// (for nodes that don't return a value)
public void execute() {
if ( kind.equals("stmts") ) {
// insert code here for Exercise 15
}
else if ( kind.equals("prtstr") ) {
System.out.print( info );
}
else if ( kind.equals("prtexp") ) {
// insert code here for Exercise 15
}
else if ( kind.equals("nl") ) {
System.out.print( "\n" );
}
else if ( kind.equals("sto") ) {
// insert code here for Exercise 15
}
else {
error("Unknown kind of node [" + kind + "]");
}
}// execute
// compute and return value produced by this node
public double evaluate() {
if ( kind.equals("num") ) {
return Double.parseDouble( info );
}
else if ( kind.equals("var") ) {
// insert code here for Exercise 15
}
else if ( kind.equals("+") || kind.equals("-") ) {
// insert code here for Exercise 15
}
else if ( kind.equals("*") || kind.equals("/") ) {
// insert code here for Exercise 15
}
else if ( kind.equals("input") ) {
return keys.nextDouble();
}
else if ( kind.equals("sqrt") || kind.equals("cos") ||
kind.equals("sin") || kind.equals("atan")
) {
double value = first.evaluate();
if ( kind.equals("sqrt") )
return Math.sqrt(value);
else if ( kind.equals("cos") )
return Math.cos( Math.toRadians( value ) );
else if ( kind.equals("sin") )
return Math.sin( Math.toRadians( value ) );
else if ( kind.equals("atan") )
return Math.toDegrees( Math.atan( value ) );
else {
error("unknown function name [" + kind + "]");
return 0;
}
}
else if ( kind.equals("pow") ) {
// insert code here for Exercise 15
}
else if ( kind.equals("opp") ) {
// insert code here for Exercise 15
}
else {
error("Unknown node kind [" + kind + "]");
return 0;
}
}// evaluate
+16
View File
@@ -0,0 +1,16 @@
print "enter a:"
a = input()
print "enter b:"
b = input()
print "enter c:"
c = input()
disc = pow(b,2) - 4*a*c
x1 = (-b - sqrt(disc) ) / (2*a)
x2 = (-b + sqrt(disc) ) / (2*a)
print "x1: " print x1 newline
print "x2: " print x2 newline
+25
View File
@@ -0,0 +1,25 @@
Announcements
(I'll try to keep this file current with any due dates, corrections to
the course notes, corrections to
Exercises and Projects, and so on)
=======================================
Exercise 2:
The command (occurring two places):
2 1001 1
is misleading, because the "1" is a conceptual error
(in an earlier version of VPL, I though the call had
to speciy how many arguments had been passed, but now
we just say that the command 3's have to immediately
precede the command 2)
but I didn't notice this issue because the loader
sees opcode 2, reads one further argument (1001), and
tosses the rest of the line---it's just as if the "1"
is a comment.
---------------------------------------
Project 1 is due September 10 (target)
BIN
View File
Binary file not shown.
+757
View File
@@ -0,0 +1,757 @@
\input pictex
\input /Users/Shared/TeX/defs
\advance \hoffset 0.25 true in
\def\inclassexercise{\item{$\Rightarrow$\quad\quad} {\bf In-Class Exercise:}\quad}
\def\borderline{\medskip\hrule\bigskip}
\startDoc{CS 3210 Fall 2018}{25}{Implementing a Programming Language}
{\bigboldfont A Brief Look at More Serious Language Implementation}
\bigskip
We have already played some with language design and implementation---you were asked in Project 1
to implement VPL, and I suffered greatly implementing Jive. But, those languages have relatively simple
structure and can be described just
using finite automata. Now we want to learn a little about implementing a language that is described using
a {\it context free grammar}. It turns out that if a language is described using a finite automaton to describe
its meaningful chunks, and a context free grammar of the right form to describe its main structure,
then we can implement the language using {\it recursive descent parsing}.
\bigskip
\Indent{.5}
Not that long ago,
probably every computer science program had a rather nasty required course known as
``the compiler course.'' As this technology became more well-known and accepted, this
course gradually disappeared from the curriculum, but scraps of it remain in this course.
\medskip
We will make our work much easier by mostly
ignoring issues of {\it efficiency}, both in space and time.
For example, a real compiler tries to recover from errors and go on to report other errors, but
we will be happy to detect one error and stop. And, a real compiler tries to generate code that
uses as little memory as is reasonable, and runs as quickly as is reasonable.
We won't be crazy about it in our upcoming work, but we will compromise efficiency whenever it saves us
work.
\medskip
\Outdent
{\bigboldfont Language Specification}
\bigskip
To specify a programming language, we have to specify its {\it grammar}---what sequences of symbols
(or diagrammatic elements, if it's a non-textual language) form a syntactically legal program, and its
{\it semantics}---the meaning of those sequences of symbols.
\medskip
To precisely specify the grammar of our language, we need to do some fairly abstract work (all of which overlaps the
CS 3240 course, but with a more practical focus).
\medskip
We have already seen a little of both finite automata and context free grammars, but the following will be
more detailed and organized.
\medskip
As we do the abstract stuff, we will have in mind two languages. The first will be a
simple calculator language. The second will be the language that you will be asked to
implement in Project 2. Both of these languages will be designed and specified in the
upcoming work. The implementation of the simple calculator language through
a lexical phase and
recursive descent parsing will be worked out fully as an example, leaving you to do
the same things on Project 2.
\border
{\bf Definition of a Language}
\medskip
Given a finite set, which is known as an {\it alphabet} (and can be thought of as some set
of ordinary symbols), we define a {\it string\/}
to be any finite sequence of members of the alphabet, and we define a {\it language\/} to
be any set of strings over the alphabet.
\medskip
\In
For this course, we are interested in situations where a single string is a program in some
programming language, and the language is the set of all syntactically legal programs.
\medskip
\Out
\border
{\bf Finite Automata}
\medskip
We already introduced finite automata, so let's do some examples that will
be used in the simple calculator language.
\border
{\bf Exercise 9}
\medskip
Working in your small group, draw a finite automaton for each of the following languages:
\medskip
\Indent{1}
\item{a.} all strings that start with a lowercase letter, followed by zero or more letters or digits
\medskip
\item{b.} all strings that represent a real number in the way usually
used by humans (no scientific notation allowed), say in a math class.
\border
\Outdent
{\bf The Concept of Lexical Analysis as Just a First Step in Parsing}
\medskip
It turns out that the FA technique is not expressive enough to describe the syntax we want
to have for a typical programming language.
\medskip
\In
Here's a proof of this fact: we clearly want to have, in a typical
imperative language, the ability to write expressions
such as $((((((a))))))$, where the number of extra parentheses is unlimited. Our parser needs
to be able to check whether there are as many left parentheses as right. But, the FA technique
can't say this. Suppose to the contrary that we have an FA that accepts all strings that
have $n$ left parentheses followed by {\tt a} followed by $n$ right parentheses. Imagine that
you are looking at this wonderful diagram. Since it is a {\it finite\/} state automaton, it has a
finite number of states, say $M$. Now, feed this machine a string that has more than $M$
left parentheses, followed by an {\tt a}, followed by the same number of right parentheses.
Since there are only $M$ states, in processing the left parentheses, we will visit some state
twice, and there will be a loop in the machine that processes just one or more left parentheses.
Clearly this loop means that the machine will accept strings that it shouldn't accept.
\medskip
\Out
Since the FA technique can't describe all the syntactic features we want in a programming
language, we will be forced to develop a more powerful approach. But, the FA technique
is still useful, because we will use it for the first phase of parsing, known as {\it lexical analysis}.
This is a very simple idea: we take the stream of physical symbols and use an FA to
process them, producing either an error message or a stream of {\it tokens}. A token is simply
a higher-level symbol that is composed of one or more physical symbols. Then the
remaining parsing takes place on the sequence of tokens. This is done purely as a
matter of convenience and efficiency, because the technique we will develop to do the parsing
is fully capable of doing the tokenizing part as well.
\border
\vfil\eject
{\bigboldfont Formal Grammars and Parsing}
\medskip
We will now learn a technique for specifying the syntax of a language that is more powerful
than the FA approach. One limited version of this approach will let us specify most of the
syntax of a typical programming language.
\bigskip
A {\it formal grammar\/} consists of a set of {\it non-terminal symbols}, a set of {\it terminal symbols},
and a set of {\it production rules}. One non-terminal symbol is designated as the {\it start symbol}.
\medskip
\Indent{1}
As we saw in my specification of Jive, we will often use symbols written between angle brackets,
like {\tt <expr>}, to represent
non-terminal symbols.
Terminal symbols will be tokens produced by the lexical analysis phase.
\medskip
For our early example we will tend to use uppercase letters for non-terminal symbols and
lowercase letters for terminal symbols.
\Outdent
A production rule has one or more symbols (both terminal and non-terminal allowed) known
as the ``left hand side,'' followed
by a right arrow, followed by one or more symbols known as the ``right hand side.''
\medskip
A {\it derivation\/} starts with the start symbol and proceeds by replacing any substring of
the current string that occurs as the left hand side of a rule by the right hand side of that rule,
continuing until a string is reached that has only terminal symbols in it. At this point, that
string of terminal symbols has been proven to be in the language accepted by the grammar.
\medskip
{\bf A Simple Example}
\medskip
Here is a simple grammar, where the non-terminals are $S$, $A$, and $B$, and the
$S$ is the start symbol,
and the terminal symbols are $a$, $b$, $c$, and $d$.
\medskip
$ S \rightarrow AB $
$ A \rightarrow a A b $
$ A \rightarrow c $
$ B \rightarrow d $
$ B \rightarrow d B $
\medskip
Here is a sample derivation of a string from this grammar, where each line
involves one substitution:
\medskip
$S$
$AB$
$ a A b B$
$ a a A b b B$
$ a a c b b B $
$ a a c b b d B $
$ a a c b b d d B $
$ a a c b b d d d $
\medskip
This derivation shows that {\tt aacbbddd} is in the language accepted by this grammar.
\medskip
\doit Determine the language accepted by this grammar. Note that it
has parts that could have been accomplished by the FA technique, and parts that
could not.
\border
{\bf Context Free Grammars}
\medskip
This formal grammar technique
is a very general tool, but we will focus on a special version known as a
{\it context free grammar} where the left hand side of a rule can only be a single non-terminal
symbol.
\medskip
Context free grammars are nice because on each step of a derivation, the only question is,
which non-terminal symbol in the current string should we replace by using a rule where
it occurs as the left hand side.
\medskip
We can now think of what we really mean by parsing. For a context free grammar, the
challenge is to take a given string---an alleged program---and try to find a derivation.
\medskip
Context free grammars are used because they are powerful enough to specify most of
what we want in the syntax of a language, but are still amenable to being parsed {\it efficiently}.
\medskip
It is also important to note that for the languages people tend to use, apparently, the
semantics (meaning) of a program are closely related to the syntactic structure.
\medskip
\Indent{1}
Here is a feature of a typical programming language that isn't captured, typically, by the
context free grammar that specifies the syntax of the language: local variables in Java
have to be defined before they are used. Typically the context free grammar
says that the body of a method consists of a sequence of one or more statements, and
statements are things like {\tt int x;} and {\tt x = 3;}, but the grammar doesn't specify that
one has to occur before the other. Those rules of the language have to be handled in
some other way.
\medskip
\Outdent
For context free grammars, we can improve on the notation of a derivation a lot by
the {\it parse tree\/} concept. Instead of recopying the current string on each step, we
show the replacement of a left hand side non-terminal symbol by writing a child in the
tree for each symbol in the right hand side. Here is a parse tree for the first example
given:
\medskip
$$
\beginpicture
\setcoordinatesystem units <1true pt,1true pt>
\put {S} at 150.0 120.0
\put {A} at 60.0 90.0
\put {B} at 210.0 90.0
\put {a} at 0.0 60.0
\put {A} at 60.0 60.0
\put {b} at 120.0 60.0
\put {d} at 180.0 60.0
\put {B} at 270.0 60.0
\put {a} at 30.0 30.0
\put {A} at 60.0 30.0
\put {b} at 90.0 30.0
\put {d} at 240.0 30.0
\put {B} at 300.0 30.0
\put {c} at 60.0 0.0
\put {d} at 300.0 0.0
% Edge from 1 to 2:
\plot 141.0 117.0 68.0 92.0 /
\put {} at 141.0 117.0
% Edge from 1 to 3:
\plot 158.0 115.0 201.0 94.0 /
\put {} at 158.0 115.0
% Edge from 2 to 4:
\plot 51.0 85.0 8.0 64.0 /
\put {} at 51.0 85.0
% Edge from 2 to 5:
\plot 60.0 81.0 60.0 69.0 /
\put {} at 60.0 81.0
% Edge from 2 to 6:
\plot 68.0 85.0 111.0 64.0 /
\put {} at 68.0 85.0
% Edge from 3 to 7:
\plot 203.0 83.0 186.0 66.0 /
\put {} at 203.0 83.0
% Edge from 3 to 8:
\plot 218.0 85.0 261.0 64.0 /
\put {} at 218.0 85.0
% Edge from 5 to 9:
\plot 53.0 53.0 36.0 36.0 /
\put {} at 53.0 53.0
% Edge from 5 to 10:
\plot 60.0 51.0 60.0 39.0 /
\put {} at 60.0 51.0
% Edge from 5 to 11:
\plot 66.0 53.0 83.0 36.0 /
\put {} at 66.0 53.0
% Edge from 8 to 12:
\plot 263.0 53.0 246.0 36.0 /
\put {} at 263.0 53.0
% Edge from 8 to 13:
\plot 276.0 53.0 293.0 36.0 /
\put {} at 276.0 53.0
% Edge from 10 to 14:
\plot 60.0 21.0 60.0 9.0 /
\put {} at 60.0 21.0
% Edge from 13 to 15:
\plot 300.0 21.0 300.0 9.0 /
\put {} at 300.0 21.0
\endpicture
$$
\border
\vfil\eject
{\bf A Bad Way to Try to Express Expressions}
\medskip
Consider the following grammar, where $E$ is the start symbol, and
$V$ and $N$ are viewed as terminal symbols namely tokens representing
variables and numeric literals, and other symbols that are not uppercase letters
are viewed as tokens.
\medskip
$ E \rightarrow N$
$ E \rightarrow V$
$ E \rightarrow E + E $
$ E \rightarrow E * E $
$ E \rightarrow (E)$
\medskip
This grammar seems reasonable, but it turns out to be a rather poor way to specify
a language consisting of all mathematical expressions using variables, numeric literals,
addition, multiplication, and parentheses. For one thing, the grammar is ambiguous---there
are strings that have significantly different parse trees. For another, the grammar has no
concept of operator precedence.
\medskip
\doit Come up with some expressions and produce parse trees for them.
Verify the complaints just made.
\border
{\bf A Classic Example of a Context Free Grammar}
\medskip
Now consider this grammar for the language of simple expressions,
where $E$ is the start symbol, and
$V$ and $N$ are viewed as terminal symbols, namely tokens representing
variables and numeric literals, and other symbols that are not uppercase letters
are viewed as tokens.
\medskip
$E \rightarrow T$
$E \rightarrow T+E$
$T \rightarrow F$
$ T \rightarrow F * T$
$F \rightarrow V$
$F \rightarrow N$
$F \rightarrow (E)$
\medskip
\doit This grammar captures the syntax of an {\it expression} involving two
binary operators with different precedence. Produce parse trees for some expressions and
note that the grammar is not ambiguous and enforces operator precedence.
\border
{\bf Parse Trees as Code}
\medskip
The previous example suggests a powerful idea: if someone gives you a parse tree for an
expression, and values for all the variables occurring, you can easily compute the value
of the expression---and you can easily write code that interprets the parse tree.
\medskip
Thus, in a very real sense, the tree structure is a better programming language than
the language described by the context free grammar, except for one big catch: it's hard to
read and write parse trees, compared to reading and writing strings.
\border
{\bf Exercise 10}
\medskip
Working in your small group, produce a parse tree for the following expression, using the good
expression grammar.
Then, assuming that $a=12$, $b=7$, and $c=2$, show how the parse tree can be used to
compute the value of the expression---note how the value of each node in the parse tree
is obtained from the values of its children.
\medskip
Use this expression:
$$ 7*a + (c*a*c+4*a)*b $$
\border
{\bf Designing and Specifying the Simple Calculator Language}
\medskip
Now we want to design (and then implement) a language that allows the user to
perform a sequence of computations such as a person could do on a calculator.
But, we want the language to allow use of expressions and assignment statements.
\medskip
\doit As a whole group, invent a name for this language, and write some example programs
so everyone will see the sorts of things we want to allow, and the sorts of things we don't want
to allow.
\border
{\bf Exercise 11}
\medskip
Working in your small group, specify the simple calculator language by determining its
tokens (categories of conceptual symbols, such as probably {\tt <var>} for variable),
drawing an FA for each kind of token, and writing a context free grammar for the
language.
\medskip
Use {\tt <program>} for the start variable, which should produce any possible program in the
language.
\border
\doit Working back together as a whole group, write down the final specification
for the simple calculator language.
\border
{\bf Implementing the Lexical Phase}
\medskip
\doit As a whole group, produce a Java class named {\tt Lexer} that
will take a file containing a program in the simple calculator language as input and produce a sequence of tokens.
In addition to producing this stream of tokens, {\tt Lexer} should have the ability to ``put back'' a token, for convenience
in the recursive descent parsing phase. The point is that we will produce a grammar that will allow us to
look ahead at the next token, thinking it will be part of the entity we are producing, and then realize from that next token
that we are done with the entity we were producing, so it is convenient to put back the look ahead token.
\vfil\eject
%\bye
{\bf Implementing The Simple Calculator Language}
\medskip
\doit
Working as a whole group,
finish the draft design of the simple calculator language,
and write down a context free grammar to specify it.
\medskip
\Indent{1}
As we do this, we want to try to write the rules so that they process symbols on the
left, leaving the recursive parts on the right.
For example, if we want to say ``1 or more {\tt a}'s'' we could either use the
rules
$$ A \rightarrow Aa \; \vert \; a $$
or we could say
$$ A \rightarrow aA \; \vert \; a $$
with the same result from a theoretical perspective.
But, because we want to use the {\it recursive descent parsing\/} technique (there are other
parsing techniques that we will not study that like grammars in different forms),
we will want to use the second approach.
\medskip
\Outdent
\border
\doit Working as a whole group, begin work on a class {\tt Parser} that will take
a {\tt Lexer} as a source of tokens and produce a {\it parse tree\/} that represents a simple calculator
language program in a way that it can be directly executed.
\medskip
\Indent{1}
As a practical matter, to save some time
we will begin with some old code that I produced for a different language and modify it massively
to do the job for our new language.
\medskip
Note that along with the {\tt Lexer} and {\tt Parser} classes, this old code includes {\tt Token} and
{\tt Node} classes that will be used extensively in our work.
\medskip
The classes {\tt Basic}, {\tt Camera}, and {\tt TreeViewer} support visualizing a parse tree for
debugging and testing purposes.
\medskip
\Outdent
As we will see, the recursive descent parsing technique involves writing a method for every non-terminal
symbol in the grammar. Each of these methods will consume a sequence of tokens and produce a
node that is the root of a tree that is the translation of the corresponding chunk of code.
\medskip
Also, these methods will return {\tt null} if they realize that the next few tokens don't fit what they are
expecting to see.
\medskip
We will not take the time to be very careful about detecting and reporting errors in the source code.
We will basically assume that the source code is correct. But, when it makes sense to do so, we will
notice errors and halt the parsing process with some error message to the programmer.
\border
\vfil\eject
{\bf Final (?) Finite Automata for Lexer for Corgi}
\bigskip
\epsfbox{../Secret/Corgi/Figures/corgiFA.1}
\border
\doit Instructor will briefly discuss {\tt Lexer} and {\tt Parser} in preparation for Exercises 12 and 13.
\border
{\bf Exercise 12}
Working in your small group, write the code for state 3, 4, and 5 in the {\tt Lexer.java} file for Corgi.
To help you understand {\tt Lexer} and do this Exercise effectively, a number of trees have been
killed to provide you with a printout of the existing code on the next pages.
\vfil\eject
\count255 1
\numberedListing{../Corgi/Lexer.java}{\tt}
\border
{\bf Exercise 13}
Working in your small group, write the code for {\tt parseFactor} in
the class {\tt Parser}, listed on the next few pages.
\bigskip
Here is the draft context free grammar for Corgi (note some changes from our earlier version):
\medskip
{\baselineskip 0.95 \baselineskip
\listing{../Corgi/corgiCFG.txt}
\border}
\count255 1
\numberedListing{../Corgi/Parser.java}{\tt}
\vfil\eject
\doit Instructor will discuss the minor changes to {\tt Parser} (listed in its entirety below)
and draw a parse tree for
a Corgi program.
\border
{\bf Exercise 14}
Working in your small groups, construct the parse tree for {\tt quadroots} following the final (I hope!)
version of {\tt Parser}.
\border
{\baselineskip 0.75\baselineskip
\count255 1
\font \smalltt cmtt10 scaled 800
\numberedListing{../Corgi/Parser.java}{\smalltt}
\border
}
{\bf Exercise 15}
Below you will find a partial listing of the {\tt Node} class, namely the partially completed
{\tt execute} and {\tt evaluate} methods.
Working in your small groups,
write the missing code.
\medskip
Note that nodes have instance variables {\tt kind}, {\tt info} (both strings), and
{\tt first} and {\tt second} (both nodes).
\medskip
Also, there is a {\tt MemTable} class that has public methods
{\tt void store( String name, double value)}
and
{\tt double retrieve( String name)}
\medskip
If you need further details about any of the classes in the {\tt Corgi} project
(namely {\tt Corgi}, {\tt Token}, {\tt Lexer}, {\tt Parser}, {\tt Node}, and {\tt MemTable},
you should look at them online (assuming someone in your group has a computer in class).
\vfil\eject
\count255 136
\numberedListing{../Corgi/partialNode.java}{\tt}
\vfil\eject
{\bigboldfont Designing Project 2}
\medskip
To keep Project 2 manageable (a first serious submission for Project 2 must be submitted by the time of Test 2---October 29),
I have decided to make this project be to simply (we hope!) add some
features to Corgi as follows.
\medskip
\Indent{1}
First, we want to give the Corgi programmer the ability to define functions, and of course to call them.
\medskip
Second, we want to add branching to Corgi.
\medskip
\Outdent
\doit Working as a whole group, design the finite automata for the Corgi {\tt Lexer}, and the
context free grammar for the Corgi {\tt Parser}.
Discuss the features we are not adding to Corgi, and perhaps decide to add some of them.
As part of this design process, write some sample Corgi programs (these will also provide a
starting point for testing your Project 2 work).
\medskip
\doit Once the syntax of the language is specified, try to specify the {\it semantics\/} of the language,
and think about how execution/evaluation of the parse tree will be done.
\bigskip
{\bf Note:} after we have made decisions about the new and improved Corgi,
henceforth to be known as ``Corgi,'' I will document them.
But, you should be able to start working on Project 2 right away, based on the informal
documentation recorded during this class session.
\border
{\bigboldfont Project 2} [10 points] [first serious submission absolutely due by October 29]
\medskip
Implement the extended Corgi language as specified in class and in upcoming documents.
Be alert for corrections to the Corgi specification that may need to be made as work proceeds.
\medskip
Be sure to test your implementation thoroughly.
\medskip
Email me your group's submission with a single {\tt zip} or {\tt jar} file attached, named either
{\tt corgi.jar} or {\tt corgi.zip}. This single file must contain all the source code files.
Be sure to CC all group members on the email that submits your work.
\medskip
I must be able to extract all the Java source files from your submitted file into a folder, and then simply
type at the command prompt:
\medskip
{\tt javac Corgi.java}
{\tt java Corgi test3}
\medskip
in order to run the Corgi program in the file named {\tt test3}.
\border
\vfil\eject
\bye
{\bf Designing Project 2}
\medskip
\doit Discuss possibilities for Project 2 and decide what it should be.
% Then, we'll apply CYK and/or recursive descent to it
\vfil\eject
{\bigboldfont Course Policy Change}
\medskip
Test 2 is canceled, due to the facts that we haven't covered enough material suitable for fair assessment,
and we have just barely gotten to the main topics of language implementation.
\medskip
The test scheduled for April 13 will cover the material we have been and are still working on, along
with some functional programming topics, about equally weighted. The test at the time of the final exam
will cover Clojure and Prolog topics.
\medskip
Your course grade will be figured with the 68\% for Tests divided either into 3 or 4, with the next test counting
as two tests or one, and taking the maximum of the two calculations.
\border
{\bigboldfont Otter}
\medskip
I had been thinking Project 2 would be to finish implementing Otter, but now I'm thinking Project 2 will be
to implement the ``simple example'' we started on February 28th. We will spend a few more class periods
working through implementation of Otter together (with me, unfortunately, doing most of the work outside of
class).
\border
{\bigboldfont Project 2}
\medskip
Implement the simple calculator language (let's call it ``CalcLang'') designed in class, with that design
documented (including the finite automaton for the lexical part of the language, the context free grammar,
and an informal description of the language semantics) in the folder {\tt Project2} at the course web stie.
\medskip
When you are done, you will have an application consisting of several Java classes. You must submit your
work to me as follows:
\medskip
\In
Make sure that the main class---the one that contains the {\tt main} method at which execution starts---is
named exactly {\tt CalcLang}.
\medskip
Clean up your source files for submission by removing all non-portable {\tt package} statements and
all extraneous output.
\medskip
Put all your source files in a folder, named {\tt Project2}.
Create a {\tt jar} file from the command line by moving into the folder that contains the folder {\tt Project2}
and entering
\smallskip
{\tt jar cvfM proj2.jar Project2}
\medskip
Test your work by making a temporary folder somewhere, copying {\tt proj2.jar} into it, moving into it,
and entering
\smallskip
{\tt jar xf proj2.jar}
\smallskip
This should make a folder {\tt Project2} that contains all your source code. Move into it and compile and
run your application.
\medskip
Email me your submission with {\tt proj2.jar} attached at {\tt shultzj@msudenver.edu}
\bigskip
If you are somehow incapable of doing the previous work, you may as a slightly irritating (to me) alternative
make a {\tt zip} file of the folder containing your source code instead of a {\tt jar} file.
\medskip
\Out
\vfil\eject
\bye
BIN
View File
Binary file not shown.
+1945
View File
File diff suppressed because it is too large Load Diff
+143
View File
@@ -0,0 +1,143 @@
private Node parseStatement() {
System.out.println("-----> parsing <statement>:");
Token token = lex.getNextToken();
// ---------------->>> print <string> or print <expr>
if ( token.isKind("print") ) {
token = lex.getNextToken();
if ( token.isKind("string") ) {// print <string>
return new Node( "prtstr", token.getDetails(),
null, null, null );
}
else {// must be first token in <expr>
// put back the token we looked ahead at
lex.putBackToken( token );
Node first = parseExpr();
return new Node( "prtexp", first, null, null );
}
// ---------------->>> newline
}
else if ( token.isKind("newline") ) {
return new Node( "nl", null, null, null );
}
// --------------->>> <var> = <expr>
else if ( token.isKind("var") ) {
String varName = token.getDetails();
token = lex.getNextToken();
errorCheck( token, "single", "=" );
Node first = parseExpr();
return new Node( "sto", varName, first, null, null );
}
else {
System.out.println("Token " + token +
" can't begin a statement");
System.exit(1);
return null;
}
}// <statement>
private Node parseExpr() {
System.out.println("-----> parsing <expr>");
Node first = parseTerm();
// look ahead to see if there's an addop
Token token = lex.getNextToken();
if ( token.matches("single", "+") ||
token.matches("single", "-")
) {
Node second = parseExpr();
return new Node( token.getDetails(), first, second, null );
}
else {// is just one term
lex.putBackToken( token );
return first;
}
}// <expr>
private Node parseTerm() {
System.out.println("-----> parsing <term>");
Node first = parseFactor();
// look ahead to see if there's a multop
Token token = lex.getNextToken();
if ( token.matches("single", "*") ||
token.matches("single", "/")
) {
Node second = parseTerm();
return new Node( token.getDetails(), first, second, null );
}
else {// is just one factor
lex.putBackToken( token );
return first;
}
}// <term>
private Node parseFactor() {
System.out.println("-----> parsing <factor>");
Token token = lex.getNextToken();
if ( token.isKind("num") ) {
return new Node("num", token.getDetails(), null, null, null );
}
else if ( token.isKind("var") ) {
return new Node("var", token.getDetails(), null, null, null );
}
else if ( token.matches("single","(") ) {
Node first = parseExpr();
token = lex.getNextToken();
errorCheck( token, "single", ")" );
return first;
}
else if ( token.isKind("bif0") ) {
String bifName = token.getDetails();
token = lex.getNextToken();
errorCheck( token, "single", "(" );
token = lex.getNextToken();
errorCheck( token, "single", ")" );
return new Node( bifName, null, null, null );
}
else if ( token.isKind("bif1") ) {
String bifName = token.getDetails();
token = lex.getNextToken();
errorCheck( token, "single", "(" );
Node first = parseExpr();
token = lex.getNextToken();
errorCheck( token, "single", ")" );
return new Node( bifName, first, null, null );
}
else if ( token.isKind("bif2") ) {
String bifName = token.getDetails();
token = lex.getNextToken();
errorCheck( token, "single", "(" );
Node first = parseExpr();
token = lex.getNextToken();
errorCheck( token, "single", "," );
Node second = parseExpr();
token = lex.getNextToken();
errorCheck( token, "single", ")" );
return new Node( bifName, first, second, null );
}
else if ( token.matches("single","-") ) {
Node first = parseFactor();
return new Node("opp", first, null, null );
}
else {
System.out.println("Can't have a factor starting with " + token );
System.exit(1);
return null;
}
}// <factor>
BIN
View File
Binary file not shown.
+262
View File
@@ -0,0 +1,262 @@
\input /Users/Shared/TeX/defs
\input pictex
\input /Users/Shared/TeX/ruled
%\advance \voffset by 1true in
\pageno -1
\parindent 0true in
\datestartup{CS 3210 Fall 2018}{-1} % crucial for all later handouts
\line{\bf CS 3210 Principles of Programming Languages \hfil Fall 2018}
\medskip
\hrule
\bigskip
Instructor: Jerry Shultz
\medskip
\hrule
\medskip
\line{Office: {AES Building, Room 200Z}\hfil Phone: {\bf 303 615 1161}}
\medskip
\line{Email: {\bf shultzj@msudenver.edu}\hfil Website: {\bf rowdysites.msudenver.edu/$\sim$shultzj}}
\medskip
\hrule
\medskip
\input schedule
\medskip
\hrule
\medskip
The times listed as ``Office Hours'' are times that I will be sitting in my office waiting to help you when you call or come by (barring emergencies and
quick trips away and back, and travel time from and to classes).
\medskip
You are
welcome to stop by any time on the chance that I'll be there and will be able to meet with you.
Finally, if those times are not convenient for you, we can arrange a mutually convenient time
to meet.
\bigskip
\vfil\eject
\line{\bf Text:\hfil}
Written materials provided by instructor and online resources
\medskip
\line{\bf Prerequisites\hfil}
CS 2050, CS 2400, CS 3250, and MTH 3170, all with a grade of C or better, or permission of instructor
\medskip
%\line{\bf Official Syllabus\hfil}
%You can find the official syllabus for this course at {\tt https://mcs.msudenver.edu/syllabi}
%\medskip
{\bf Withdrawal dates} for FULL-TERM courses are:
\medskip
\ruledtable
100\% refund: | Sunday, August 26 \nr
50\% refund: | Wednesday, September 5 \nr
Last Day for W: | Wednesday, November 2
\endruledtable
\medskip
{\advance \leftskip .5true in
For all full-term and part-term courses, you can confirm withdrawal dates on your
$\underline{\hbox{Student Detail Schedule}}$
\medskip
}
{\bf Holiday information:}
Labor Day: September 3 (campus closed)
Fall Break: November 19--25 (no classes, campus open except on 11/22 and 11/23)
\medskip
{\bf University Policies}
\medskip
Students are responsible for full knowledge of the provisions and regulations pertaining
to all aspects of their attendance at MSU Denver, and should familiarize themselves with
the following policies:
{\advance \leftskip .5true in
\item{1.} GENERAL UNIVERSITY POLICIES
\item{2.} GRADES AND NOTATIONS including WITHDRAWAL FROM A COURSE,\hfil\break ADMINISTRATIVE
WITHDRAWAL, and INCOMPLETE POLICY
\item{} Students should be aware that any kind of withdrawal can have a negative impact on some
types of financial aid, including scholarships.
\item{3.} ACADEMIC INTEGRITY
\item{4.} POLICY STATEMENTS ON SEXUAL MISCONDUCT
\item{5.} ACCOMMODATIONS TO ASSIST INDIVIDUALS WITH DISABILITIES
\item{6.} CLASS ATTENDANCE
\item{7.} ELECTRONIC COMMUNICATION (STUDENT EMAIL) POLICY
\medskip
}
For a complete description of these policies go to
{\tt msudenver.edu/math/policies}
\border
{\bf Additional Policies for this Course}
\medskip
If you must miss a class session, it is your
responsibility to find out what you missed and make up work if possible.
If you miss a test due to an appropriate cause (illness, unavoidable family or work conflicts,
religious holiday, etc.), you
are responsible for arranging with me a time to take a make-up exam.
\border
\vfil\eject
\font \smallerfont cmr10 scaled 800
\font \smallertt cmtt10 scaled 800
\line{\bf Course Organization and Rules\hfil}
\medskip
In a typical class session I will present some new material---Mini-Lectures---with that material written up
in the
course notes. Then students will work on Exercises giving hands-on work with the new material.
Some Exercises will involve hand-written solutions and should be done, ideally, working in groups of
four or five using a section of whiteboard. Other Exercises will involve writing code on a computer and
should be done, ideally, working in groups of two or three with at least one laptop computer brought in
by a student.
As students work on these Exercises, the instructor and two Learning Assistants will be available to
discuss issues that come up.
\medskip
Note that these Exercises are designed to provide a more effective alternative to listening to lectures all
the time. The Exercises are not graded, but if you do not complete them during class time (especially if
you are not in class) you should complete them outside of class. If you are unable to do the Exercises,
you will probably not do well on the corresponding questions on the Tests.
It is strongly encouraged that you work in groups, because for most people this is helpful, but it is not
required.
\medskip
At times we will discuss Exercises as a whole group after students have had time to work on them separately.
\medskip
I will post all course materials, including the written ``course notes'' corresponding to the
mini-lectures, and any summaries of whole group discussions of Exercises,
at\hfil\break
{\tt rowdysites.msudenver.edu/$\sim$shultzj}
\bigskip
Your ``homework'' for this course will be to go over the new material and corresponding Exercises as needed,
and to complete a number of programming Projects.
\medskip
You are encouraged to discuss the course
material, the Exercises, and even the Projects
with other students, me, the Learning Assistants, or whomever you wish,
but you may not receive any help from anyone on the Tests.
Also, while you are encouraged to discuss the Projects
with others, you may not directly copy the work of
others---any work that you submit should, at a minimum,
be ``written in your own words.''
\medskip
It is okay, even encouraged, to do the Projects as a group effort with at most three people participating fully.
If your work on a Project is part of a group effort, the group must turn in one submission,
with the two or three group members clearly identified. If you do this, be sure that it is an
actual meaningful collaboration, not just giving the work of one person to the others. And,
when one group member emails me the group submission, be sure to ``CC'' the other
one or two group members so they also receive the feedback email from me.
\medskip
Each project will be worth some number of project points, varying somewhat from project to project to
reflect the work involved in each one.
If your project does not fully meet the specifications, you will be given feedback and will have the
opportunity, with no penalty, to fix the problems and resubmit your work.
Only very limited partial credit will be given for work that is not correct and complete, and this will
happen only when you do not resubmit your work, typically at the end of the semester when you simply
run out of time.
\medskip
Each Project will have a due date by which your first serious submission must be made.
When a Project is specified its tentative due date will be given, but sometimes we will adjust that
date to a later date.
You will be allowed to fix/complete work on projects later as long as you make a first
meaningful submission on time.
Projects not submitted by the due date
will not be accepted.
\bigskip
We will have three in-class Tests, each covering roughly the previous five weeks of material.
You will be allowed to use any written materials during the Tests, but you will not be allowed to
use any electronic devices.
\medskip
Here is the schedule for the tests:
\medskip
\ruledtable
Test Number | Date | Class Periods Covered \cr
Test 1 | September 26 | 1--8 \nr
| (class period 11) | \cr
Test 2 | October 29 | 9, 10, 12--17 \nr
| (class period 20) | \cr
Test 3 | December 10 or 12 | 18, 19, 21--27 \nr
| (scheduled final exam time) |
\endruledtable
\bigskip}
Here is how course grades will be figured:
\medskip
{\advance \leftskip 0.5true in
Your {\tt testScore} will be computed by averaging your three test scores. Each test score is computed by dividing the points you got by the
number of points possible (so test ``points'' have different values on each test---they are just a convenient way of doing the partial credit
accounting on each problem).
\medskip
Your {\tt projectScore} will be the number of project points you got divided by the number of
project points possible.
\medskip
Your course score is then computed as
\smallskip
{\tt 0.4 * projectScore + 0.6 * testScore}
\medskip
Your course grade is then computed according to this chart:
\medskip
}
%\TightTables
\def\tablespace{\hskip 0.05true in}
\def\tw{.35true in}
\font \tinytt cmtt10 scaled 500
\ruledtable
\bf Score in: | \rtitem{\tw}{\tinytt [0,60)} | \rtitem{\tw}{\tinytt [60,63)} | \rtitem{\tw}{\tinytt [63,67)} | \rtitem{\tw}{\tinytt [67,70)} | \rtitem{\tw}{\tinytt [70,73)} | \rtitem{\tw}{\tinytt [73,77)} | \rtitem{\tw}{\tinytt [77,80)} | \rtitem{\tw}{\tinytt [80,83)} | \rtitem{\tw}{\tinytt [83,87)} | \rtitem{\tw}{\tinytt [87,90)} | \rtitem{\tw}{\tinytt [90,93)} | \rtitem{\tw}{\tinytt [93,100]} \cr
\bf Grade: | \rtitem{\tw}{F} | \rtitem{\tw}{D-} | \rtitem{\tw}{D} | \rtitem{\tw}{D+} | \rtitem{\tw}{C-} | \rtitem{\tw}{C} | \rtitem{\tw}{C+} | \rtitem{\tw}{B-} | \rtitem{\tw}{B} | \rtitem{\tw}{B+} | \rtitem{\tw}{A-} | \rtitem{\tw}{A}
\endruledtable
\medskip
{\advance \leftskip .5true in
with the additional rule that I will improve your grade by one level (one column farther to the right) if you have good attendance and participation.
\bigskip
}
\vfil\eject
\bye
+89
View File
@@ -0,0 +1,89 @@
% PiCTeX schedule generated by Scheduler.java
% if not already loaded, decomment 2 lines below:
%\input pictex
%\input latexpicobjs
{\font \schedfont cmr10 scaled 750
{\font \boldschedfont cmbx10 scaled 750
\schedfont
$$
\beginpicture
\setcoordinatesystem units <0.75pt, 0.75pt>
\put{{\boldschedfont 9:00}--9:30} <22.5pt, 7.5pt> at 0.0 360.0
\putrectangle corners at 0.0 380.0 and 60.0 360.0
\put{9:30--10:00} <22.5pt, 7.5pt> at 0.0 340.0
\putrectangle corners at 0.0 360.0 and 60.0 340.0
\put{{\boldschedfont 10:00}--10:30} <22.5pt, 7.5pt> at 0.0 320.0
\putrectangle corners at 0.0 340.0 and 60.0 320.0
\put{10:30--11:00} <22.5pt, 7.5pt> at 0.0 300.0
\putrectangle corners at 0.0 320.0 and 60.0 300.0
\put{{\boldschedfont 11:00}--11:30} <22.5pt, 7.5pt> at 0.0 280.0
\putrectangle corners at 0.0 300.0 and 60.0 280.0
\put{11:30--12:00} <22.5pt, 7.5pt> at 0.0 260.0
\putrectangle corners at 0.0 280.0 and 60.0 260.0
\put{{\boldschedfont 12:00}--12:30} <22.5pt, 7.5pt> at 0.0 240.0
\putrectangle corners at 0.0 260.0 and 60.0 240.0
\put{12:30--1:00} <22.5pt, 7.5pt> at 0.0 220.0
\putrectangle corners at 0.0 240.0 and 60.0 220.0
\put{{\boldschedfont 1:00}--1:30} <22.5pt, 7.5pt> at 0.0 200.0
\putrectangle corners at 0.0 220.0 and 60.0 200.0
\put{1:30--2:00} <22.5pt, 7.5pt> at 0.0 180.0
\putrectangle corners at 0.0 200.0 and 60.0 180.0
\put{{\boldschedfont 2:00}--2:30} <22.5pt, 7.5pt> at 0.0 160.0
\putrectangle corners at 0.0 180.0 and 60.0 160.0
\put{2:30--3:00} <22.5pt, 7.5pt> at 0.0 140.0
\putrectangle corners at 0.0 160.0 and 60.0 140.0
\put{{\boldschedfont 3:00}--3:30} <22.5pt, 7.5pt> at 0.0 120.0
\putrectangle corners at 0.0 140.0 and 60.0 120.0
\put{3:30--4:00} <22.5pt, 7.5pt> at 0.0 100.0
\putrectangle corners at 0.0 120.0 and 60.0 100.0
\put{{\boldschedfont 4:00}--4:30} <22.5pt, 7.5pt> at 0.0 80.0
\putrectangle corners at 0.0 100.0 and 60.0 80.0
\put{4:30--5:00} <22.5pt, 7.5pt> at 0.0 60.0
\putrectangle corners at 0.0 80.0 and 60.0 60.0
\put{{\boldschedfont 5:00}--5:30} <22.5pt, 7.5pt> at 0.0 40.0
\putrectangle corners at 0.0 60.0 and 60.0 40.0
\put{5:30--6:00} <22.5pt, 7.5pt> at 0.0 20.0
\putrectangle corners at 0.0 40.0 and 60.0 20.0
\put{{\boldschedfont 6:00}--6:30} <22.5pt, 7.5pt> at 0.0 0.0
\putrectangle corners at 0.0 20.0 and 60.0 0.0
\put{CS 3510} <29.400000000000002pt, 29.400000000000002pt> at 60.8 260.8
\putrectangle corners at 60.8 339.20000000000005 and 139.2 260.8
\put{CS 3510} <29.400000000000002pt, 29.400000000000002pt> at 220.8 260.8
\putrectangle corners at 220.8 339.20000000000005 and 299.20000000000005 260.8
\put{CS 3210} <29.400000000000002pt, 29.400000000000002pt> at 60.8 180.8
\putrectangle corners at 60.8 259.20000000000005 and 139.2 180.8
\put{CS 3210} <29.400000000000002pt, 29.400000000000002pt> at 220.8 180.8
\putrectangle corners at 220.8 259.20000000000005 and 299.20000000000005 180.8
\put{CS 3240} <29.400000000000002pt, 29.400000000000002pt> at 140.8 20.8
\putrectangle corners at 140.8 99.2 and 219.20000000000002 20.8
\put{CS 3240} <29.400000000000002pt, 29.400000000000002pt> at 300.8 20.8
\putrectangle corners at 300.8 99.2 and 379.20000000000005 20.8
\put{Office Hours} <29.400000000000002pt, 14.399999999999999pt> at 60.8 140.8
\putrectangle corners at 60.8 179.20000000000002 and 139.2 140.8
\put{Office Hours} <29.400000000000002pt, 14.399999999999999pt> at 220.8 140.8
\putrectangle corners at 220.8 179.20000000000002 and 299.20000000000005 140.8
\put{Office Hours} <29.400000000000002pt, 14.399999999999999pt> at 140.8 100.8
\putrectangle corners at 140.8 139.2 and 219.20000000000002 100.8
\put{Office Hours} <29.400000000000002pt, 14.399999999999999pt> at 300.8 100.8
\putrectangle corners at 300.8 139.2 and 379.20000000000005 100.8
\put{Office Hours} <29.400000000000002pt, 14.399999999999999pt> at 220.8 100.8
\putrectangle corners at 220.8 139.2 and 299.20000000000005 100.8
\put{CS Meetings} <29.400000000000002pt, 21.9pt> at 380.8 280.8
\putrectangle corners at 380.8 339.2 and 459.20000000000005 280.8
\put{Dept. Meetings} <29.400000000000002pt, 21.9pt> at 380.8 160.8
\putrectangle corners at 380.8 219.20000000000002 and 459.20000000000005 160.8
\put{L.A. Meeting} <29.400000000000002pt, 14.399999999999999pt> at 220.8 60.8
\putrectangle corners at 220.8 99.19999999999999 and 299.20000000000005 60.8
\put{Monday} <30.0pt, 8.25pt> at 60.0 380.0
\putrectangle corners at 60.0 402.0 and 140.0 380.0
\put{Tuesday} <30.0pt, 8.25pt> at 140.0 380.0
\putrectangle corners at 140.0 402.0 and 220.0 380.0
\put{Wednesday} <30.0pt, 8.25pt> at 220.0 380.0
\putrectangle corners at 220.0 402.0 and 300.0 380.0
\put{Thursday} <30.0pt, 8.25pt> at 300.0 380.0
\putrectangle corners at 300.0 402.0 and 380.0 380.0
\put{Friday} <30.0pt, 8.25pt> at 380.0 380.0
\putrectangle corners at 380.0 402.0 and 460.0 380.0
\endpicture
$$
}
+8
View File
@@ -0,0 +1,8 @@
public class IntPair
{
public int first, second;
public IntPair( int a, int b )
{ first = a; second = b; }
}
Executable
+948
View File
@@ -0,0 +1,948 @@
import java.io.File;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Scanner;
public class Jive {
private static Scanner keys = new Scanner( System.in );
private static Scanner input;
private static PrintWriter output;
private static PrintWriter output2;
// "global" info --- applies across entire program
// ------------------------------------------------
// holds the vpl code as it is produced
private static ArrayList<Integer> vpl = new ArrayList<Integer>();
// holds the name and starting index of all functions
private static ArrayList<StringIntPair> funcStart = new ArrayList<StringIntPair>();
// string at given index is name of function called at hole -index
private static ArrayList<String> callHoles = new ArrayList<String>();
// stores for entire program the start label assigned to each
// given function name
private static ArrayList<StringIntPair> callInfo = new ArrayList<StringIntPair>();
// little info for actual globals in VPL:
// ----------------------------------------
// holds all the global variables for entire program
private static ArrayList<String> globsList;
// "local" info --- used separately for each function
// --------------------------------------------------
// holds the local variables and literals temporarily for each function
private static ArrayList<String> locsList = new ArrayList<String>();
// once have a locsList for a function, store it in allLocs for output2
private static ArrayList<String> allLocs = new ArrayList<String>();
// holds the locations of the holes and the corresponding labels in current function
private static ArrayList<StringIntPair> labelHoles = new ArrayList<StringIntPair>();
// holds the label and corresponding index for all labels in current function
private static ArrayList<StringIntPair> labelInfo = new ArrayList<StringIntPair>();
public static void main(String[] args) throws Exception {
if (args.length != 1) {
System.out.println("Usage: java Jive <fileName>");
System.exit(1);
}
String fileName = args[0];
input = new Scanner( new File( fileName ) );
output = new PrintWriter( new File( fileName + ".vpl" ) );
output2 = new PrintWriter( new File( fileName + ".doc" ) );
// scan Jive file one word at a time
// (line breaks mean nothing more than a space)
// start anonymous "main" function
// since human readability is not a big issue, go ahead
// and treat the "main" function like all others, even
// though the label at the top is meaningless, since it
// can't be called
// (all other functions do these things when "Def" is encountered)
vpl.add( 1 );
vpl.add( nextLabel(true) ); // all functions start with a 1 command
// note index where command 4 will be inserted
// (can change if there's a Globs command)
funcStart.add( new StringIntPair( "?", 2 ) );
// note label for start of the function
callInfo.add( new StringIntPair( "?", currentLabel ) );
// make scratch cell (local cell 0) for scratch space for main
locsList.add( "-" );
int scratch = 0;
String rememberWord = "huh?"; // used a little to pass word to next state
callHoles.add("---"); // waste spot 0 so call holes -1, -2, -3, ..
// match nicely to positions in list
int state = 1;
while ( input.hasNext() ) {
String word = input.next();
System.out.println("--------------------->>>" +
"\nIn state " + state + " processing [" + word + "]" );
if ( state == 1 ) {
if ( word.equals("/*") ) {
state = 2;
}
else if ( word.equals("Halt") ) {
vpl.add( 26 );
state = 1;
}
else if ( word.equals("NL") ) {
vpl.add( 29 );
state = 1;
}
else if ( word.equals("Def") ) {// starting a function definition
// stuff to do when see Def, also when see end of input file
finishFunctionDef();
// initialize things for the upcoming function definition
locsList = new ArrayList<String>();
labelHoles = new ArrayList<StringIntPair>();
labelInfo = new ArrayList<StringIntPair>();
// move on to see the function name
state = 3;
}
else if ( isLabel( word ) ) {// process a label
int label = nextLabel(false);
labelInfo.add( new StringIntPair( word, label ) );
vpl.add( 1 );
vpl.add( label );
state = 1;
}
else if ( word.equals("Globs") ) {// global declarations section
// global declarations must be first command in program, if there at all
if ( vpl.size() == 2 ) {// have only put in the command 1 for "main"
// so still at start
vpl.add( 0, 32 );
globsList = new ArrayList<String>();
state = 6;
}
else {
error( "Globals declaration must occur at very beginning of a Jive program");
}
}
else if ( word.equals("Jmp") ) {
vpl.add( 7 );
state = 7;
}
else if ( findBIF2( word ) >= 0 ) {// is built-in function with 2 args
// cheaply get opcode corresponding to word
int op;
if ( word.equals("Get") ) {
op = 24;
}
else {
op = findBIF2(word) + 9;
}
vpl.add( op ); // the binary op
vpl.add( scratch ); // where to put the result
state = 8;
}
else if ( findBIF1( word ) >= 0 ) {// is built-in function with 1 arg
if ( word.equals( "Not" ) )
vpl.add( 20 );
else if ( word.equals( "Opp" ) )
vpl.add( 21 );
else if ( word.equals( "New" ) )
vpl.add( 31 );
else
error("[" + word + "] is not a valid one argument built-in function");
vpl.add( scratch );
state = 11;
}
else if ( word.equals("Keys") ) {// is built-in function with 0 args
vpl.add( 27 );
state = 13;
}
else if ( word.equals("Fet") ) {// have to look for built-in Fet before user-def
state = 16;
}
else if ( isFuncName( word ) ) {
rememberWord = word;
state = 14;
}
else if ( isVar( word ) ) {
// can put in entire part 1 code here
vpl.add( 23 );
vpl.add( scratch );
vpl.add( processVar( word, locsList ) );
state = 15;
}
}// state 1
else if ( state == 2 ) {
if ( word.equals("*/") ) {// reached end of comment
state = 1; // start a new command
}
else {// part of comment
// consume the word and stay in state 2
}
}
else if ( state == 3 ) {
if ( ! isFuncName( word ) ) {
error( "[" + word + "] is not a valid function name");
}
vpl.add( 1 );
vpl.add( nextLabel(true) ); // all functions start with a 1 command
// note index where command 4 will be inserted
funcStart.add( new StringIntPair( word, vpl.size() ) );
// note label for start of the function
callInfo.add( new StringIntPair( word, currentLabel ) );
state = 5;
}
// state 4 lost in change from f ( a b c ) to f a b c .
else if ( state == 5 ) {
if ( word.equals( "." ) ) {
// make scratch cell for this function after params cells
locsList.add( "-" );
scratch = locsList.size()-1;
state = 1; // go on to body of function
}
else if ( isParam( word ) ) {
// note another parameter
locsList.add( word );
// loop back to stay in state 5
}
}
else if ( state == 6 ) {
if ( word.equals( "." ) ) {
// done creating list of globals, generate VPL code for command 32
vpl.add( 1, globsList.size() );
// adjust start index of "main" to be 2 farther
funcStart.get( 0 ).x += 2;
state = 1;
}
else if ( isParam( word ) ) {
// add global
globsList.add( word );
// stay in state 6
}
else {
error("[" + word + "] is not a valid global variable name");
}
}
else if ( state == 7 ) {
if ( isLabel( word ) ) {
// add the hole
vpl.add( -1 );
labelHoles.add( new StringIntPair( word, vpl.size()-1 ) );
state = 1;
}
else {
error( "[" + word + "] is not a valid label");
}
}
else if ( state == 8 ) {
if ( isVar( word ) ) {
vpl.add( processVar( word, locsList ) ); // first arg
state = 9;
}
else {
error( "[" + word + "] is not a valid variable or literal");
}
}
else if ( state == 9 ) {
if ( isVar( word ) ) {
vpl.add( processVar( word, locsList ) ); // second arg
state = 10;
}
else {
error( "[" + word + "] is not a valid variable or literal");
}
}
else if ( state == 10 ) {
if ( word.equals("->") ) {
state = 100;
}
else {
error("a part 1 must be followed by ->");
}
}
else if ( state == 11 ) {
if ( isVar( word ) ) {
vpl.add( processVar( word, locsList ) );
state = 12;
}
else {
error( "[" + word + "] is not a valid variable or literal");
}
}
else if ( state == 12 ) {
if ( word.equals("->") ) {
state = 100;
}
else {
error("a part 1 must be followed by ->");
}
}
else if ( state == 13 ) {
if ( word.equals("->") ) {
vpl.add( scratch );
state = 100;
}
else {
error("a part 1 must be followed by ->");
}
}
else if ( state == 14 ) {
if ( isVar( word ) ) {
vpl.add( 3 );
vpl.add( processVar( word, locsList ) );
// state loops to 14
}
else if ( word.equals("->") ) {
// done with function call, send out the vpl code
vpl.add( 2 );
vpl.add( - nextCallHole() ); // leave a hole
callHoles.add( rememberWord );
// followed by command 6 for when return from doing called function
vpl.add( 6 );
vpl.add( scratch );
state = 100;
}
else {
error("a part 1 must be followed by ->");
}
}
else if ( state == 15 ) {
if ( word.equals("->") ) {
state = 100;
}
else {
error("a part 1 must be followed by ->");
}
}
else if ( state == 16 ) {
if ( isParam( word ) ) {
vpl.add( 34 );
vpl.add( scratch );
vpl.add( processVar( word, globsList ) );
state = 17;
}
else {
error("[" + word + "] is not a valid argument for Fet");
}
}
else if ( state == 17 ) {
if ( word.equals("->") ) {
state = 100;
}
else {
error("a part 1 must be followed by ->");
}
}
// end of part 1 states
// begin part 2 states
else if ( state == 100 ) {// start state for part 2
if ( word.equals(".") ) {
// do nothing with the value in scratch cell from part 1
state = 1;
}
else if ( word.equals("Prt") ) {
// generate code to print the value in the scratch cell
vpl.add( 28 );
vpl.add( scratch );
state = 1;
}
else if ( word.equals("Sym") ) {
// generate code to print the value in the scratch cell
vpl.add( 30 );
vpl.add( scratch );
state = 1;
}
else if ( word.equals("Ret") ) {
// generate code to return the value in scratch cell
vpl.add( 5 );
vpl.add( scratch );
state = 1;
}
else if ( isParam( word ) ) {
vpl.add( 23 );
vpl.add( processVar( word, locsList ) );
vpl.add( scratch );
state = 1;
}
else if ( word.equals("Jmp") ) {
state = 101;
}
else if ( word.equals("Put") ) {
state = 102;
}
else if ( word.equals("Sto") ) {
state = 104;
}
else {// unknown first word in a part 2
error("[" + word + "] is invalid as start of a part 2");
}
}// start state for part 2 (100)
else if ( state == 101 ) {
if ( isLabel( word ) ) {
vpl.add( 8 );
vpl.add( -1 ); // hole for target of jump
labelHoles.add( new StringIntPair( word, vpl.size()-1 ) );
vpl.add( scratch );
state = 1;
}
else {
error("[" + word + "] is not a valid label to use after conditional Jmp");
}
}
else if ( state == 102 ) {// processing first <var> for Put
if ( isVar( word ) ) {// have valid first argument
vpl.add( 25 );
vpl.add( processVar( word, locsList ) );
state = 103;
}
else {
error("[" + word + "] is not a valid first argument for Put");
}
}
else if ( state == 103 ) {// processing second <var> for Put
if ( isVar( word ) ) {// have valid second argument
vpl.add( processVar( word, locsList ) );
vpl.add( scratch );
state = 1;
}
else {
error("[" + word + "] is not a valid first argument for Put");
}
}
else if ( state == 104 ) {
if ( isParam( word ) ) {// valid argument for Sto
// generate VPL code 33 n a
vpl.add( 33 );
vpl.add( processVar( word, globsList ) );
vpl.add( scratch );
state = 1;
}
else {
error("[" + word + "] is not a valid argument for Sto");
}
}
}// loop to scan all words in Jive source file
// finish off last function definition
finishFunctionDef();
System.out.println("vpl before filling call holes:");
for ( int k=0; k<vpl.size(); k++) {
System.out.printf("%4d %6d\n", k, vpl.get(k) );
}
System.out.println();
// display the holes and info:
System.out.println("Call holes:");
for (int k=0; k<callHoles.size(); k++) {
System.out.println( callHoles.get(k) );
}
// scan vpl to line-oriented output file
// and to doc file
// and fill call holes
int funcNumber = 0;
int ip = 0;
while ( ip < vpl.size() ) {
int op = vpl.get( ip );
System.out.println("at ip: " + ip + ", sending op: " + op + " to vpl file");
if ( op==26 || op==29 ) {// operations with 0 arguments
output2.printf("[%5d] ", ip );
out( op + "\n" ); ip++;
}
else if ( op==4 ) {
System.out.println("function number is " + funcNumber);
output2.println("\n------------ " + funcStart.get(funcNumber).s + " -------------");
output2.print( allLocs.get( funcNumber ) ); funcNumber++;
output2.println();
output2.printf("[%5d] ", ip );
out( op + " " ); ip++;
out( vpl.get(ip) + "\n" ); ip++;
}
else if ( op== 2 ) {
// before send to files, replace call hole with actual label
String fName = callHoles.get( - vpl.get( ip+1 ) );
// now search callInfo for the label
int label = -1;
for (int k=0; k<callInfo.size() && label < 0; k++) {
if ( callInfo.get(k).s.equals( fName ) ) {
label = callInfo.get(k).x;
}
}
if ( label == -1 )
error("Could not find function [" + fName + "] in callInfo");
output2.printf("[%5d] ", ip );
out( op + " " ); ip++;
out( label + "\n" ); ip++;
}
else if ( op==1 || op==3 || op==5 || op==6 || op==7 ||
op==27 || op==28 || op==30 || op==32 ) {// ops with 1 arg
output2.printf("[%5d] ", ip );
out( op + " " ); ip++;
out( vpl.get(ip) + "\n" ); ip++;
}
else if ( op==8 || op==20 || op==21 || op==22 || op==23 ||
op==31 || op==33 || op==34 ) {// ops with 2 args
output2.printf("[%5d] ", ip );
out( op + " " ); ip++;
out( vpl.get(ip) + " " ); ip++;
out( vpl.get(ip) + "\n" ); ip++;
}
else if ( (9<=op && op<=19) || op==24 || op==25 ) {
output2.printf("[%5d] ", ip );
out( op + " " ); ip++;
out( vpl.get(ip) + " " ); ip++;
out( vpl.get(ip) + " " ); ip++;
out( vpl.get(ip) + "\n" ); ip++;
}
else {
output2.printf("[%5d] ", ip );
System.out.println( op + " is invalid op code, stop translation");
ip = vpl.size()+1; // just to stop it
//error("[" + op + "] is an invalid operation code");
}
}
output.close();
output2.close();
input.close();
}// main
// return whether w starts with lowercase,
// followed by 0 or more letters or digits
private static boolean isParam( String w ) {
if ( w.length() == 0 ) return false;
if ( ! ( 'a' <= w.charAt(0) && w.charAt(0) <= 'z' ) ) return false;
if ( w.length() ==1 ) return true;
for (int k=1; k<w.length(); k++) {
char x = w.charAt(k);
if ( !letter(x) && !digit(x) ) return false;
}
return true;
}
// return whether w starts with uppercase,
// followed by 0 or more letters or digits
private static boolean isFuncName( String w ) {
if ( w.length() == 0 ) return false;
if ( ! ( 'A' <= w.charAt(0) && w.charAt(0) <= 'Z' ) ) return false;
if ( w.length() == 1 ) return true;
for (int k=1; k<w.length(); k++) {
char x = w.charAt(k);
if ( !letter(x) && !digit(x) ) return false;
}
return true;
}
private static boolean isLabel( String w ) {
if ( ! w.endsWith( ":" ) ) {
return false;
}
else if ( w.length() < 2 || ! lowercase( w.charAt(0) ) ) {
return false;
}
else {
for (int k=1; k<w.length()-1; k++) {
char x = w.charAt(k);
if ( !letter(x) && !digit(x) ) {
return false;
}
}
}
return true;
}
private static boolean lowercase( char x ) {
return 'a'<=x && x<='z';
}
private static boolean uppercase( char x ) {
return 'A'<=x && x<='Z';
}
private static boolean letter( char x ) {
return lowercase(x) || uppercase(x);
}
private static boolean digit( char x ) {
return '0'<=x && x<='9';
}
private static String[] bifs2 = { "Add", "Sub", "Mult", "Quot", "Rem",
"Eq", "NotEq", "Less", "LessEq",
"And", "Or",
"Get" };
private static String[] bifs1 = { "Not", "Opp", "New" };
private static int findBIF2( String word ) {
int loc = -1;
for (int k=0; k<bifs2.length && loc < 0; k++) {
if ( word.equals( bifs2[k] ) ) {
loc = k;
}
}
return loc;
}
private static int findBIF1( String word ) {
int loc = -1;
for (int k=0; k<bifs1.length && loc < 0; k++) {
if ( word.equals( bifs1[k] ) ) {
loc = k;
}
}
return loc;
}
// return whether word is an int literal or
// a parameter
private static boolean isVar( String word ) {
return isParam(word) || isInt(word);
}
// given word which is a variable name or an int
// literal, search for it in list (which will be
// either locsList or globsList) and if found, just
// return its location, otherwise append to end,
// and if is an int literal, add to litsList the 22 command to
// create the literal, and return its location
private static int processVar( String word, ArrayList<String> list ) {
for (int k=0; k<list.size(); k++) {
if ( word.equals( list.get(k) ) ) {
// found word in the list
return k;
}
}
// if still here, word was not found, process it further
if ( isInt(word) ) {// is an int literal, not in list
list.add( word );
return list.size()-1;
}
else {// is a newly discovered variable
list.add( word );
return list.size()-1;
}
}// processVar
private static boolean isInt( String s ) {
boolean result;
try {
int x = Integer.parseInt( s );
result = true;
}
catch( Exception e ) {
result = false;
}
return result;
}
private static void showLocals() {
for (int k=0; k<locsList.size(); k++) {
System.out.printf("%4d %s\n", k, locsList.get(k) );
}
}
// find item in list with string matching w, and return
// its matching integer,
// or report error
private static int findString( String w, ArrayList<StringIntPair> list ) {
for (int k=0; k<list.size(); k++) {
if (list.get(k).s.equals(w) ) {
return list.get(k).x;
}
}
// if still here, didn't find
error("could not find info with string [" + w + "]");
return -1;
}
private static void out( String s ) {
output.print( s );
output2.print( s );
}
private static void error( String message ) {
System.out.println( message );
System.exit(1);
}
public static void main2(String[] args) {
String w = "A37";
System.out.println("func?" + isFuncName( w ) );
System.out.println("var?" + isVar( w ) );
System.out.println("param?" + isParam( w ) );
System.out.println("label?" + isLabel( w ) );
}
// do everything that needs to be done when realize
// we've reached the end of a function definition
private static void finishFunctionDef() {
System.out.println("Start finishFunctionDef:");
System.out.println(" vpl at start: " );
showVPL();
showTables();
// get name of function being finished, just for convenience
String funcName = funcStart.get( funcStart.size()-1).s;
// debug output
System.out.println("Local cells for function just finished, " + funcName + ":" );
showLocals();
// for output2, store locsList for this function
String s = "";
for (int k=0; k<locsList.size(); k++) {
s += k + ": " + locsList.get(k) + "\n";
}
allLocs.add( s );
// insert command 4 with correct count
// first find number of params by searching for scratch cell named "-"
int numParams = -1;
for (int k=0; k<locsList.size() && numParams < 0; k++) {
if ( locsList.get(k).equals("-") ) {
numParams = k;
}
}
if (numParams == -1) {
error("Something wrong in finishFunctionDef, no scratch cell found");
}
// get index in vpl for insertion of command 4
// (just 2 more than where the label for the function starts)
int start = funcStart.get( funcStart.size()-1 ).x;
// insert the command 4
vpl.add( start, 4 );
vpl.add( start+1, locsList.size()-numParams );
// insert the command 22's for each literal in locsList
int count = 2; // have to count the two cells used by command 4
int index = start + 2;
for (int k=0; k<locsList.size(); k++) {
if ( isInt( locsList.get(k) ) ) {// is a literal
vpl.add( index, 22 ); index++;
vpl.add( index, k ); index++;
vpl.add( index, Integer.parseInt( locsList.get(k) ) ); index++;
count += 3; // inserting 3 additional values for each int literal
}
}
//System.out.println("finishFunctionDef, vpl after insertions: " );
//showVPL();
// shift hole locations due to insertions of command 4 and command 22's
for (int k=0; k<labelHoles.size(); k++) {
StringIntPair pair = labelHoles.get(k);
pair.x += count;
}
System.out.println("after shifting locations for insertions, tables are: ");
showTables();
// fill in all label holes
for (int k=0; k<labelHoles.size(); k++) {
StringIntPair pair = labelHoles.get(k);
// find location of this label from info:
int loc = -1;
for (int j=0; j<labelInfo.size() && loc < 0; j++) {
if ( labelInfo.get(j).s.equals( pair.s ) ) {// found it
loc = labelInfo.get(j).x;
}
}
// important error check---Jive program might be missing the label
if ( loc == -1 )
error("couldn't find label [" + pair.s + "]");
System.out.println("filling label hole [" + pair.s + "," + pair.x + "] with " + loc );
vpl.set( pair.x, loc );
}
}// finishFunctionDef
private static void showVPL() {
for (int k=0; k<vpl.size(); k++) {
System.out.println(k + ": " + vpl.get(k) );
}
}
private static void showTables() {
System.out.println("Label holes: ");
for (int k=0; k<labelHoles.size(); k++) {
System.out.println(labelHoles.get(k));
}
System.out.println("Label info: ");
for (int k=0; k<labelInfo.size(); k++) {
System.out.println(labelInfo.get(k));
}
System.out.println("Call holes: ");
for (int k=0; k<callHoles.size(); k++) {
System.out.println(callHoles.get(k));
}
System.out.println("Function starts: ");
for (int k=0; k<funcStart.size(); k++) {
System.out.println(funcStart.get(k));
}
}
// label generating scheme:
// functions are numbered while being scanned
private static int functionNumber = 0;
private static int spread = 1000;
private static int currentLabel = 0;
// generate next label, incrementing by 1
// if not starting a function, otherwise
// starting with multiple of spread
private static int nextLabel( boolean startingFunction ) {
if ( startingFunction ) {
functionNumber++;
currentLabel = spread*functionNumber;
return currentLabel;
}
else {
currentLabel++;
return currentLabel;
}
}
// call hole stuff:
private static int currentCallHole = 0;
private static int nextCallHole() {
currentCallHole++;
return currentCallHole;
}
}// Jive
Executable
+67
View File
@@ -0,0 +1,67 @@
Have begin implementation of Jive, working on state 8.
Through Tuesday, 9/11 made good progress, but still
some problems.
JiveVPL.save can be copied to JiveVPL.class to
allow running my VPL interpreter (version that
takes the memory produced by Jive.java) on
a given VPL file produced by Jive.
As of Sunday, 9/16/2018, at noon, Jive is initially
implemented, testing on a few test cases
(may still have errors, of course, but is useable
for demonstrating the desired translation from
Jive to VPL)
All the tests in the folder Tests seem to be working.
To run my VPL simulator on a VPL program produced by
Jive, you need to compile IntPair.java and
then
copy VPL.save to VPL.class
(I'm hiding my VPL source code so Project 1 isn't ruined).
September 17:
in class we wrote a little Jive program, named "sept17",
that was supposed to ask the user for n and
then store in an array n followed by the first n
Fibonacci numbers (we left off the first 1, which was
fine for our purposes), and then
display that array.
When we translated the Jive program to VPL and then
ran the VPL program, the behavior was weird.
After class I found the following errors in the
Jive program (yay---not in Jive.java, my translator):
first, we forgot to put a Halt command in the
"main" at the end, so after doing whatever work
was in "main", it continued into the next function,
or something. At any rate, it was bad, and was
cured by putting in the Halt command.
second, nothing was displaying. I figured out
after a while that we had forgotten to store
the value n at offset 0 in the array. When I
put in the code:
size -> Put array 0,
the program behaved as desired, except at the end
it crashed. After some work, I realized that I
(with no one else to blame), should have done
n -> Put array 0
With that change, sept17 worked perfectly
(up to n==45---for larger n, integer
overflow produced nonsensical results at the
end the sequence).
The punchline is, we didn't find a problem with
Jive.java!
+20
View File
@@ -0,0 +1,20 @@
/* pair up a string and
an int,
used for holes and info
*/
public class StringIntPair {
public String s;
public int x;
public StringIntPair( String sIn, int xIn ) {
s = sIn;
x = xIn;
}
public String toString() {
return "[" + s + "," + x + "]";
}
}
+31
View File
@@ -0,0 +1,31 @@
/* do some function
definitions and calls
in various orders
*/
Keys -> x
F 2 x -> a
a -> Prt
NL
Halt
Def G a b c .
Mult a b -> x
Mult x c -> x
x -> Ret
Def F a b .
Add a 1 -> c
Sub b 1 -> d
G c d 5 -> r
r -> Ret
+21
View File
@@ -0,0 +1,21 @@
/* main function
for computing
factorial of
input value
*/
Keys -> n
Fact n -> f
f -> Prt NL
Halt
Def Fact n .
Less n 2 -> Jmp small:
Sub n 1 -> temp
Fact temp -> f
Mult n f -> Ret
small:
1 -> Ret
+44
View File
@@ -0,0 +1,44 @@
[ 0] 1 1000
------------ ? -------------
0: -
1: n
2: f
[ 2] 4 3
[ 4] 27 0
[ 6] 23 1 0
[ 9] 3 1
[ 11] 2 2000
[ 13] 6 0
[ 15] 23 2 0
[ 18] 23 0 2
[ 21] 28 0
[ 23] 29
[ 24] 26
[ 25] 1 2000
------------ Fact -------------
0: n
1: -
2: 2
3: 1
4: temp
5: f
[ 27] 4 5
[ 29] 22 2 2
[ 32] 22 3 1
[ 35] 16 1 0 2
[ 39] 8 2001 1
[ 42] 10 1 0 3
[ 46] 23 4 1
[ 49] 3 4
[ 51] 2 2000
[ 53] 6 1
[ 55] 23 5 1
[ 58] 11 1 0 5
[ 62] 5 1
[ 64] 1 2001
[ 66] 23 1 3
[ 69] 5 1
+29
View File
@@ -0,0 +1,29 @@
1 1000
4 3
27 0
23 1 0
3 1
2 2000
6 0
23 2 0
23 0 2
28 0
29
26
1 2000
4 5
22 2 2
22 3 1
16 1 0 2
8 2001 1
10 1 0 3
23 4 1
3 4
2 2000
6 1
23 5 1
11 1 0 5
5 1
1 2001
23 1 3
5 1
+27
View File
@@ -0,0 +1,27 @@
Keys -> x
top:
x -> Prt NL
Eq x 1 -> Jmp exit:
Rem x 2 -> r
Eq r 0 -> Jmp even:
Jmp odd:
even:
Quot x 2 -> x
Jmp top:
odd:
Mult 3 x -> x
Add x 1 -> x
Jmp top:
exit:
Halt
+15
View File
@@ -0,0 +1,15 @@
/* unit tests, sort of,
on global stuff
*/
Globs a b c .
17 -> Sto a
23 -> Sto b
41 -> Sto c
Fet a -> Prt NL
Fet b -> Prt NL
Fet c -> Prt NL
Halt
+51
View File
@@ -0,0 +1,51 @@
GetList -> a
PutList a -> .
Halt
/*--------------------------------------*/
Def GetList .
Keys -> size
Add size 1 -> objSize /* 1 extra cell for size */
New objSize -> list
size -> Put list 0 /* store size at index 0 */
1 -> index
top:
Less size index -> Jmp exit:
Keys -> input
input -> Put list index
Add index 1 -> index
Jmp top:
exit:
list -> Ret
/*--------------------------------------*/
Def PutList list .
0 -> index /* get size of list */
Get list index -> size
1 -> index
top:
Less size index -> Jmp exit:
Get list index -> value
value -> Prt 32 -> Sym
Add index 1 -> index
Jmp top:
exit:
0 -> Ret
+10
View File
@@ -0,0 +1,10 @@
ShowSyms -> .
Halt
Def ShowSyms .
65 -> Sym
33 -> Sym
97 -> Sym
NL
0 -> Ret
+22
View File
@@ -0,0 +1,22 @@
Keys -> row
Keys -> col
PasTri row col -> Prt
Halt
Def PasTri row col .
Eq col 0 -> temp1
Eq row col -> temp2
Or temp1 temp2 -> easy
easy -> Jmp easy:
Sub col 1 -> upLeft
Sub row 1 -> rowAbove
PasTri rowAbove upLeft -> res1
PasTri rowAbove col -> res2
Add res1 res2 -> Ret
easy:
1 -> Ret
+71
View File
@@ -0,0 +1,71 @@
Globs p rowSize .
Main -> .
/* ------------------------------------ */
Def Pastri2 row col .
GetArray2d row col -> temp
NotEq temp 0 -> Jmp easy:
Eq col 0 -> Jmp onEdge:
Eq col row -> Jmp onEdge:
Sub col 1 -> col1
Sub row 1 -> row1
Pastri2 row1 col1 -> temp1
Pastri2 row1 col -> temp2
Add temp1 temp2 -> result
PutArray2d row col result -> .
result -> Ret
onEdge:
PutArray2d row col 1 -> .
1 -> Ret
easy:
temp -> Ret
/* ------------------------------------ */
Def Main .
Keys -> row
Keys -> col
Add row 1 -> rowsize
Add col 1 -> colsize
Mult rowsize colsize -> n
New n -> Sto p
colsize -> Sto rowSize
Pastri2 row col -> Prt NL
Halt
/* ------------------------------------ */
Def GetArray2d r c .
Fet p -> array
Fet rowSize -> cols
Mult r cols -> index
Add c index -> index
Get array index -> result
result -> Ret
/* ------------------------------------ */
Def PutArray2d r c value .
Fet p -> array
Fet rowSize -> cols
Mult r cols -> index
Add c index -> index
value -> Put array index
0 -> Ret
+13
View File
@@ -0,0 +1,13 @@
Keys -> x
Keys -> y
Keys -> z
Add3 x y z -> Prt NL
Halt
Def Add3 a b c .
Add a b -> x
Add x c -> x
x -> Ret
+7
View File
@@ -0,0 +1,7 @@
Globs a b c .
17 -> Sto b
Fet b -> Prt
Halt
Executable
BIN
View File
Binary file not shown.
Executable
+77
View File
@@ -0,0 +1,77 @@
/* ask the user for n,
create in an array the
first n fibonacci numbers
(1,1,2,3,5,8,...)
total them up and display
*/
Keys -> n
Fib n -> array
PutList array -> .
/* forgot this on Sept. 17,
caused weird behavior,
running into the next function?!
*/
Halt
/* given n,
create a heap array with n+1 spaces,
store n in space 0,
compute fib numbers and store them in
spaces 1, 2, ... n
Return starting index of the array
*/
Def Fib n .
Add n 1 -> size
New size -> array
/* forgot this on Sept. 17---
have to store n at
offset 0
*/
n -> Put array 0
0 -> temp1
1 -> temp2
1 -> k
top:
Less n k -> Jmp exit:
Add temp1 temp2 -> temp
temp -> Put array k
temp2 -> temp1
Get array k -> temp2
Add k 1 -> k
Jmp top:
exit:
array -> Ret
/*--------------------------------------*/
Def PutList list .
0 -> index /* get size of list */
Get list index -> size
1 -> index
top:
Less size index -> Jmp exit:
Get list index -> value
value -> Prt 32 -> Sym
Add index 1 -> index
Jmp top:
exit:
0 -> Ret
+101
View File
@@ -0,0 +1,101 @@
[ 0] 1 1000
------------ ? -------------
0: -
1: n
2: array
[ 2] 4 3
[ 4] 27 0
[ 6] 23 1 0
[ 9] 3 1
[ 11] 2 2000
[ 13] 6 0
[ 15] 23 2 0
[ 18] 3 2
[ 20] 2 3000
[ 22] 6 0
[ 24] 26
[ 25] 1 2000
------------ Fib -------------
0: n
1: -
2: 1
3: size
4: array
5: 0
6: temp1
7: temp2
8: k
9: temp
[ 27] 4 9
[ 29] 22 2 1
[ 32] 22 5 0
[ 35] 9 1 0 2
[ 39] 23 3 1
[ 42] 31 1 3
[ 45] 23 4 1
[ 48] 23 1 0
[ 51] 25 4 5 1
[ 55] 23 1 5
[ 58] 23 6 1
[ 61] 23 1 2
[ 64] 23 7 1
[ 67] 23 1 2
[ 70] 23 8 1
[ 73] 1 2001
[ 75] 16 1 0 8
[ 79] 8 2002 1
[ 82] 9 1 6 7
[ 86] 23 9 1
[ 89] 23 1 9
[ 92] 25 4 8 1
[ 96] 23 1 7
[ 99] 23 6 1
[ 102] 24 1 4 8
[ 106] 23 7 1
[ 109] 9 1 8 2
[ 113] 23 8 1
[ 116] 7 2001
[ 118] 1 2002
[ 120] 23 1 4
[ 123] 5 1
[ 125] 1 3000
------------ PutList -------------
0: list
1: -
2: 0
3: index
4: size
5: 1
6: value
7: 32
[ 127] 4 7
[ 129] 22 2 0
[ 132] 22 5 1
[ 135] 22 7 32
[ 138] 23 1 2
[ 141] 23 3 1
[ 144] 24 1 0 3
[ 148] 23 4 1
[ 151] 23 1 5
[ 154] 23 3 1
[ 157] 1 3001
[ 159] 16 1 4 3
[ 163] 8 3002 1
[ 166] 24 1 0 3
[ 170] 23 6 1
[ 173] 23 1 6
[ 176] 28 1
[ 178] 23 1 7
[ 181] 30 1
[ 183] 9 1 3 5
[ 187] 23 3 1
[ 190] 7 3001
[ 192] 1 3002
[ 194] 23 1 2
[ 197] 5 1
+71
View File
@@ -0,0 +1,71 @@
1 1000
4 3
27 0
23 1 0
3 1
2 2000
6 0
23 2 0
3 2
2 3000
6 0
26
1 2000
4 9
22 2 1
22 5 0
9 1 0 2
23 3 1
31 1 3
23 4 1
23 1 0
25 4 5 1
23 1 5
23 6 1
23 1 2
23 7 1
23 1 2
23 8 1
1 2001
16 1 0 8
8 2002 1
9 1 6 7
23 9 1
23 1 9
25 4 8 1
23 1 7
23 6 1
24 1 4 8
23 7 1
9 1 8 2
23 8 1
7 2001
1 2002
23 1 4
5 1
1 3000
4 7
22 2 0
22 5 1
22 7 32
23 1 2
23 3 1
24 1 0 3
23 4 1
23 1 5
23 3 1
1 3001
16 1 4 3
8 3002 1
24 1 0 3
23 6 1
23 1 6
28 1
23 1 7
30 1
9 1 3 5
23 3 1
7 3001
1 3002
23 1 2
5 1
Executable
+1
View File
@@ -0,0 +1 @@
<h1> <i>Folder:</i> Project2</h1>
+8
View File
@@ -0,0 +1,8 @@
public class IntPair
{
public int first, second;
public IntPair( int a, int b )
{ first = a; second = b; }
}
Executable
+309
View File
@@ -0,0 +1,309 @@
import java.io.File;
import java.util.ArrayList;
import java.util.Scanner;
import java.util.StringTokenizer;
public class VPL
{
static String fileName;
static Scanner keys;
static int max;
static int[] mem;
static int ip, bp, sp, rv, hp, numPassed, gp;
static int step;
public static void main(String[] args) throws Exception {
keys = new Scanner( System.in );
if( args.length != 2 ) {
System.out.println("Usage: java VPL <vpl program> <memory size>" );
System.exit(1);
}
fileName = args[0];
max = Integer.parseInt( args[1] );
mem = new int[max];
// load the program into the front part of
// memory
Scanner input = new Scanner( new File( fileName ) );
String line;
StringTokenizer st;
int opcode;
ArrayList<IntPair> labels, holes;
labels = new ArrayList<IntPair>();
holes = new ArrayList<IntPair>();
int label;
// load the code
int k=0;
while ( input.hasNextLine() ) {
line = input.nextLine();
System.out.println("parsing line [" + line + "]");
if( line != null )
{// extract any tokens
st = new StringTokenizer( line );
if( st.countTokens() > 0 )
{// have a token, so must be an instruction (as opposed to empty line)
opcode = Integer.parseInt(st.nextToken());
// load the instruction into memory:
if( opcode == labelCode )
{// note index that comes where label would go
label = Integer.parseInt(st.nextToken());
labels.add( new IntPair( label, k ) );
}
else if( opcode == noopCode ){
}
else
{// opcode actually gets stored
mem[k] = opcode; k++;
if( opcode == callCode || opcode == jumpCode ||
opcode == condJumpCode )
{// note the hole immediately after the opcode to be filled in later
label = Integer.parseInt( st.nextToken() );
mem[k] = label; holes.add( new IntPair( k, label ) );
++k;
}
// load correct number of arguments (following label, if any):
for( int j=0; j<numArgs(opcode); ++j )
{
mem[k] = Integer.parseInt(st.nextToken());
++k;
}
}// not a label
}// have a token, so must be an instruction
}// have a line
}// loop to load code
//System.out.println("after first scan:");
//showMem( 0, k-1 );
// fill in all the holes:
int index;
for( int m=0; m<holes.size(); ++m )
{
label = holes.get(m).second;
index = -1;
for( int n=0; n<labels.size(); ++n )
if( labels.get(n).first == label )
index = labels.get(n).second;
mem[ holes.get(m).first ] = index;
}
System.out.println("after replacing labels:");
showMem( 0, k-1 );
// initialize registers:
bp = k; sp = k+2; ip = 0; rv = -1; hp = max;
numPassed = 0;
int codeEnd = bp-1;
System.out.println("Code is " );
showMem( 0, codeEnd );
gp = codeEnd + 1;
// start execution:
boolean done = false;
int op, a=0, b=0, c=0;
int actualNumArgs;
int step = 0;
int oldIp = 0;
// repeatedly execute a single operation
// *****************************************************************
do {
/* // show details of current step
System.out.println("--------------------------");
System.out.println("Step of execution with IP = " + ip + " opcode: " +
mem[ip] +
" bp = " + bp + " sp = " + sp + " hp = " + hp + " rv = " + rv );
System.out.println(" chunk of code: " + mem[ip] + " " +
mem[ip+1] + " " + mem[ip+2] + " " + mem[ip+3] );
System.out.println("--------------------------");
System.out.println( " memory from " + (codeEnd+1) + " up: " );
showMem( codeEnd+1, sp+3 );
System.out.println("hit <enter> to go on" );
keys.nextLine();
*/
oldIp = ip;
op = mem[ ip ]; ip++;
// extract the args into a, b, c for convenience:
a = -1; b = -2; c = -3;
// numArgs is wrong for these guys, need one more!
if( op == callCode || op == jumpCode ||
op == condJumpCode )
{
actualNumArgs = numArgs( op ) + 1;
}
else
actualNumArgs = numArgs( op );
if( actualNumArgs == 1 )
{ a = mem[ ip ]; ip++; }
else if( actualNumArgs == 2 )
{ a = mem[ ip ]; ip++; b = mem[ ip ]; ip++; }
else if( actualNumArgs == 3 )
{ a = mem[ ip ]; ip++; b = mem[ ip ]; ip++; c = mem[ ip ]; ip++; }
// implement all operations here:
// ********************************************
// put your work right here!
if ( op == oppCode ) {
mem[ bp+2 + a ] = - mem[ bp+2 + b ];
}
else
{
System.out.println("Fatal error: unknown opcode [" + op + "]" );
System.exit(1);
}
step++;
}while( !done );
}// main
// use symbolic names for all opcodes:
// op to produce comment
private static final int noopCode = 0;
// ops involved with registers
private static final int labelCode = 1;
private static final int callCode = 2;
private static final int passCode = 3;
private static final int allocCode = 4;
private static final int returnCode = 5; // return a means "return and put
// copy of value stored in cell a in register rv
private static final int getRetvalCode = 6;//op a means "copy rv into cell a"
private static final int jumpCode = 7;
private static final int condJumpCode = 8;
// arithmetic ops
private static final int addCode = 9;
private static final int subCode = 10;
private static final int multCode = 11;
private static final int divCode = 12;
private static final int remCode = 13;
private static final int equalCode = 14;
private static final int notEqualCode = 15;
private static final int lessCode = 16;
private static final int lessEqualCode = 17;
private static final int andCode = 18;
private static final int orCode = 19;
private static final int notCode = 20;
private static final int oppCode = 21;
// ops involving transfer of data
private static final int litCode = 22; // litCode a b means "cell a gets b"
private static final int copyCode = 23;// copy a b means "cell a gets cell b"
private static final int getCode = 24; // op a b means "cell a gets
// contents of cell whose
// index is stored in b"
private static final int putCode = 25; // op a b means "put contents
// of cell b in cell whose offset is stored in cell a"
// system-level ops:
private static final int haltCode = 26;
private static final int inputCode = 27;
private static final int outputCode = 28;
private static final int newlineCode = 29;
private static final int symbolCode = 30;
private static final int newCode = 31;
// global variable ops:
private static final int allocGlobalCode = 32;
private static final int toGlobalCode = 33;
private static final int fromGlobalCode = 34;
// debug ops:
private static final int debugCode = 35;
// return the number of arguments after the opcode,
// except ops that have a label return number of arguments
// after the label, which always comes immediately after
// the opcode
private static int numArgs( int opcode )
{
// highlight specially behaving operations
if( opcode == labelCode ) return 1; // not used
else if( opcode == jumpCode ) return 0; // jump label
else if( opcode == condJumpCode ) return 1; // condJump label expr
else if( opcode == callCode ) return 0; // call label
// for all other ops, lump by count:
else if( opcode==noopCode ||
opcode==haltCode ||
opcode==newlineCode ||
opcode==debugCode
)
return 0; // op
else if( opcode==passCode || opcode==allocCode ||
opcode==returnCode || opcode==getRetvalCode ||
opcode==inputCode ||
opcode==outputCode || opcode==symbolCode ||
opcode==allocGlobalCode
)
return 1; // op arg1
else if( opcode==notCode || opcode==oppCode ||
opcode==litCode || opcode==copyCode || opcode==newCode ||
opcode==toGlobalCode || opcode==fromGlobalCode
)
return 2; // op arg1 arg2
else if( opcode==addCode || opcode==subCode || opcode==multCode ||
opcode==divCode || opcode==remCode || opcode==equalCode ||
opcode==notEqualCode || opcode==lessCode ||
opcode==lessEqualCode || opcode==andCode ||
opcode==orCode || opcode==getCode || opcode==putCode
)
return 3;
else
{
System.out.println("Fatal error: unknown opcode [" + opcode + "]" );
System.exit(1);
return -1;
}
}// numArgs
private static void showMem( int a, int b )
{
for( int k=a; k<=b; ++k )
{
System.out.println( k + ": " + mem[k] );
}
}// showMem
}// VPL
Executable
+17
View File
@@ -0,0 +1,17 @@
32 1 allocate one global cell named "0"
4 10 make plenty of scratch space in the "main" stack frame
22 0 17 local cell 0 <- constant 17
33 0 0 global cell 0 <- local cell 0
27 1 local cell 1 <- input from keyboard
34 2 0 local cell 2 <- global cell 0
9 3 1 2 local cell 3 <- input + copy of global value
28 3 display the final answer
29 newline
26 halt
Executable
+33
View File
@@ -0,0 +1,33 @@
0 Here's the map between local cells and names:
0 Local cell: Name:
0 0 n (input value)
0 1 2 (literal)
0 2 1 (literal)
0 3 n % 2
4 4 allocate space for 4 local cells
27 0 local cell 0 <- input value (n)
22 1 2 local cell 1 <- literal 2
22 2 1 local cell 2 <- literal 1
13 3 0 1 local cell 3 <- n % 2 (conveniently 0 or 1
8 1001 3 if n%2 is not 0 jump to 1001
0 case that n is even
28 1 display 2 to say that n is even
29
7 1002 hop over code for odd case
1 1001 case that n is odd
28 2 display 1 to say that n is odd
29
1 1002
26
Executable
+28
View File
@@ -0,0 +1,28 @@
0 Local cell: Name:
0 0 n (display 1..n)
0 1 j (index in loop
0 2 1 (literal)
0 3 n < j
4 4 allocate space for 4 local cells
27 0 n = keyboard input
22 1 1 j <- 1
22 2 1
1 1001 top of loop
16 3 0 1 if n < j exit loop
8 1002 3
28 1 println j
29
9 1 1 2 j = j+1
7 1001 go up to top of loop
1 1002 exit loop
26 halt
Executable
+43
View File
@@ -0,0 +1,43 @@
0 Local cell: Name:
0 0 x
0 1 1
0 2 2
0 3 3
0 4 x==1, x % 2
4 5 allocate local cells in main stack frame
22 1 1 set the literals
22 2 2
22 3 3
27 0 x <- input
1 1001 top of loop
14 4 0 1 local cell 4 <- x == 1
8 1002 4 if x==1 exit loop
28 0 println x
29
13 4 0 2 local cell 4 <- x%2, so is 0 if x even, 1 if x odd
8 1003 4 if x is odd jump
0 didn't jump so x is even
12 0 0 2 x <- x / 2
7 1004 skip over x odd code
1 1003 start of x odd case
11 0 0 3 x <- x*3
9 0 0 1 x <- x+1
1 1004
7 1001 jump to top of loop
1 1002 exit loop
26
Executable
+23
View File
@@ -0,0 +1,23 @@
4 3
27 0
3 0
2 1001
6 1
28 1
29
26
1 1001
4 6
22 2 2
22 1 1
16 6 0 2
8 2001 6
10 3 0 1
3 3
2 1001
6 4
11 5 0 4
5 5
1 2001
5 1
Executable
+103
View File
@@ -0,0 +1,103 @@
0 main subprogram
0 cells used:
0
0 0 holds starting index of list
0 1 holds n=# of items in list
4 2
27 1
3 1
2 100000
6 0
28 0
29
3 0
2 200000
29
26
0 list input subprogram
0 cells used
0 0 parameter (n=desired number of items in list)
0 1 literal 1
0 2 n+1
0 3 index (k) in loop
0 4 holds starting point (a) of list
0 5 boolean result of n < k
0 6 input value
1 100000
4 6
22 1 1 create 1
9 2 0 1 cell 2 = n+1
31 4 2 a = new int[n+1]
22 3 0 k=0
25 4 3 0 a[k] = n
22 3 1 k=1
1 102 top of loop
16 5 0 3 cell 5 = n < k
8 101 5 if n < k jump to 101
27 6 cell 6 = input value
25 4 3 6 a[k] = input value
9 3 3 1 k=k+1
7 102 jump to top of loop
1 101 exit point of loop
5 4 return a
0 list display subprogram
0 cells used:
0 0 index of start of object (a)
0 1 literal 1
0 2 number of items in list (n)
0 3 index k
0 4 ascii code for a space (32)
0 5 n < k
0 6 temp
1 200000
4 5
22 1 1
22 4 32
22 3 0 k=0
24 2 0 3 n=a[0]
22 3 1 k=1
1 201 top of loop
16 5 2 3 cell 5 = n < k
8 202 5 if n < k exit loop
24 6 0 3 temp = a[k]
28 6 print temp
30 4 print a space
9 3 3 1 k=k+1
7 201 jump to top of loop
1 202 exit loop
5 0 return (value stored in RV irrelevant)
Executable
+32
View File
@@ -0,0 +1,32 @@
4 3
27 0
27 1
3 0
3 1
2 101
6 2
28 2
29
26
1 101
4 6
22 2 1
22 5 0
14 6 1 5
8 102 6
14 6 1 0
8 102 6
10 3 0 2
10 4 1 2
3 3
3 4
2 101
6 6
3 3
3 1
2 101
6 7
9 6 6 7
5 6
1 102
5 2
+93
View File
@@ -0,0 +1,93 @@
4 5
27 0
28 0
29
22 0 23
22 1 17
22 3 0
22 4 1
9 2 0 1
28 2
29
10 2 0 1
28 2
29
11 2 0 1
28 2
29
12 2 0 1
28 2
29
13 2 0 1
28 2
29
14 2 0 1
28 2
14 2 1 1
28 2
29
15 2 1 1
28 2
15 2 0 1
28 2
29
16 2 1 0
28 2
16 2 0 1
28 2