first commit

This commit is contained in:
Jeena Paradies 2011-04-19 11:37:05 +02:00
commit 063194f8be
349 changed files with 36508 additions and 0 deletions

View file

@ -0,0 +1,52 @@
This contains three examples of using the assembler
from java and from the script
Look up http://www.blackdown.org/~kbs/jas.html for more
documentation. This only tells you how to run the examples. The
documentation is very Unix centric, I apologize.... I have not had
time to set this up on the PC's yet.
simple.java:
simple.jas:
Unexciting program that generates a do nothing class.
Go up a directory and compile simple.java. Run the program,
which generates the bytecode. Disassemble the bytecode
% (cd ..; javac -d . examples/simple.java; java simple; javap -p -c out)
Same thing, but using the script instead of java directly.
% (cd ..; java scm.driver examples/simple.jas; javap -p -c out)
hworld.java:
hworld.jas:
Print a string in a loop.
% (cd ..; javac -d . examples/hworld.java; java hworld; java out)
As before, but use script instead.
% (cd ..; java scm.driver examples/hworld.jas; java out)
exprcomp.java:
Primitive runtime expression compiler. It translates arithmetic
expressions into bytecode and loads it on the fly as a class, which
is run to get the answer. test.inp is an example of the sort of
arithmetic expressions it translates.
% (cd ..; javac -d . examples/exprcomp.java; java exprcomp examples/test.inp)
exprcomp.jas:
Primitive compiler for jas arithmetic expressions (in jas).
jas is fairly expressive, thats about the only point of this
exercise ;-) Unlike the java version, this gets written out
into a file which you'll have to run to get the results.
% (cd ..; java scm.driver examples/exprcomp.jas; java results)

View file

@ -0,0 +1,116 @@
;;; Simple arithmetic expression compiler for jas in jas.
;;;
;;; The compiler is defined in the function
;;; compile-expression
;;;
;;; use as (for instance)
;;; (compile-expression (quote (+ (* 2 (+ 1 3)) 1)))
;;;
;;; This will generate a standalone program called results.class
;;; Run the bytecode interpreter on it as:
;;;
;;; % java results
;;;
;;; which will print the result of the expression
(define compile-expression
(lambda (expr)
(real-compile-expression expr)
(dump-code)))
;; The fun part...
(define real-compile-expression
(lambda (expr)
(cond
((num? expr)
(compile-number expr))
(1 (progn
(real-compile-expression (get-op1 expr))
(real-compile-expression (get-op2 expr))
(compile-op (get-op expr))
(set! cur-stack-height (- cur-stack-height 1)))))))
;; Ah well. Back to boring bookkeeping.
(define compile-number
(lambda (num)
(append-insn (bipush num))
(set! cur-stack-height (+ 1 cur-stack-height))
(cond
((< max-stack-height cur-stack-height)
(set! max-stack-height cur-stack-height)))))
(define compile-op
(lambda (op)
(cond
((eq? op (quote +)) (append-insn (iadd)))
((eq? op (quote -)) (append-insn (isub)))
((eq? op (quote *)) (append-insn (imul)))
((eq? op (quote /)) (append-insn (idiv))))))
(define get-op1
(lambda (expr) (car (cdr expr))))
(define get-op2
(lambda (expr) (car (cdr (cdr expr)))))
(define get-op
(lambda (expr) (car expr)))
(define append-insn
(lambda (insn)
(jas-code-addinsn my-code insn)))
(define cur-stack-height 1)
(define max-stack-height 1)
(define my-code (make-code))
(define my-init-code (make-code))
; define the main() portion,
; and the call to print out the
; results.
(define append-sequence
(lambda (code-part insn-list)
(mapcar (lambda (insn) (jas-code-addinsn code-part insn))
insn-list)))
(append-sequence
my-init-code
(quote
((aload_0)
(invokenonvirtual (make-method-cpe "java/lang/Object" "<init>" "()V"))
(return))))
(define dump-code
(lambda ()
(define my-env (make-class-env))
(jas-class-setclass my-env (make-class-cpe "results"))
(jas-class-setsuperclass my-env (make-class-cpe "java/lang/Object"))
(jas-class-addmethod my-env acc-public "<init>" "()V" my-init-code ())
(append-sequence
my-code
(quote
((getstatic
(make-field-cpe "java/lang/System" "out" "Ljava/io/PrintStream;"))
(swap)
(invokevirtual (make-method-cpe
"java/io/PrintStream" "println" "(I)V"))
(return))))
(jas-code-stack-size my-code max-stack-height)
(jas-class-addmethod my-env
(| acc-public acc-static)
"main" "([Ljava/lang/String;)V" my-code ())
(jas-class-write my-env
(make-outputstream "results.class"))))
;;;
;;; example usage of compiler.
;;;
;;; run the compiled class with
;;; % java results
;;; to get the answer.
(compile-expression (quote (+ (* 2 (+ 1 3)) 1)))

View file

@ -0,0 +1,242 @@
// Primitive runtime code generation of expressions. This is a jas
// implementation of the example in Aho Sethi Ullman.
//
// You pass to it statements of the form
// a = 1*2 + 3*5;
// Only integer operations are allowed, and variables
// are magically created by using them in the LHS of a statement.
//
// You can print out the value of expressions with the println keyword:
// println(a + 10);
//
// It compiles this into a bytearray, and then loads it as
// a new class.
//
// Unfortunately, this trick cannot be used in an applet --- security
// restrictions prevent ClassLoaders from being placed on the
// stack. So much for writing regexp compilers that can do codegen instead of
// state tables.
//
// The grammar is simple, so code generation is part of the parsing
// step. Operator precedence is directly handled by the grammar.
//
// Grammar + production rules:
//
// start -> list EOF
// list -> id = expr ; { emit(istore, id.index); } list
// | println expr ; { emit(<println sequence>); } list
// | lambda
// expr -> term moreterms
// moreterms -> + term { emit(iadd) } moreterms
// | - term { emit(isub) } moreterms
// | lambda
// term -> factor morefactors
// morefactors -> * factor { emit(imul) } morefactors
// | / factor { emit(idiv) } morefactors
// | lambda
// factor -> ( expr )
// | number { emit(iconst, number.value) }
// | id { emit(iload, id.index); }
import java.util.*;
import java.io.*;
import jas.*;
import sun.tools.java.RuntimeConstants;
public class exprcomp implements RuntimeConstants
{
StreamTokenizer inp;
CodeAttr myCode;
short cur_stack_height;
short max_stack_height;
short max_vars;
Hashtable vars;
public exprcomp(StreamTokenizer inp)
throws jasError
{
inp.eolIsSignificant(false);
this.inp = inp;
myCode = new CodeAttr();
// Add initializations
myCode.addInsn(new Insn(opc_aload_0));
myCode.addInsn(new Insn(opc_invokenonvirtual,
new MethodCP("java/lang/Object",
"<init>", "()V")));
cur_stack_height = max_stack_height = 1;
vars = new Hashtable();
max_vars = 1;
}
public void write(DataOutputStream out)
throws IOException, jasError
{
ClassEnv clazz = new ClassEnv();
myCode.setStackSize(max_stack_height);
myCode.setVarSize(max_vars);
// add initializer to class
clazz.addMethod
((short) ACC_PUBLIC, "<init>", "()V", myCode, null);
clazz.setClassAccess((short) ACC_PUBLIC);
clazz.setClass(new ClassCP("results"));
clazz.setSuperClass(new ClassCP("java/lang/Object"));
clazz.write(out);
}
public void parse()
throws IOException, parseError, jasError
{
inp.nextToken();
while(inp.ttype != inp.TT_EOF)
{
if (inp.ttype != inp.TT_WORD)
{
throw new parseError("Expected an id at line " + inp.lineno());
}
if (inp.sval.equals("println"))
{
match(inp.TT_WORD);
expr();
match(';');
emit(new Insn(opc_getstatic,
new FieldCP("java/lang/System",
"out", "Ljava/io/PrintStream;")));
emit(new Insn(opc_swap));
emit(new Insn(opc_invokevirtual,
new MethodCP("java/io/PrintStream",
"println", "(I)V")));
}
else
{ // search, maybe add into var list
Integer idx;
if ((idx = (Integer) vars.get(inp.sval)) == null)
{
idx = new Integer(max_vars++);
vars.put(inp.sval.intern(), idx);
}
match(inp.TT_WORD); match('='); expr(); match(';');
emit(new Insn(opc_istore, idx.intValue()));
}
}
emit(new Insn(opc_return));
}
void expr()
throws IOException, parseError, jasError
{
term();
while (true)
{
switch(inp.ttype)
{
case '+':
match('+'); term(); emit(new Insn(opc_iadd)); break;
case '-':
match('-'); term(); emit(new Insn(opc_isub)); break;
default: return;
}
cur_stack_height--;
}
}
void term()
throws IOException, parseError, jasError
{
factor();
while (true)
{
switch(inp.ttype)
{
case '*': match('*'); factor(); emit(new Insn(opc_imul)); break;
case '/': match('/'); factor(); emit(new Insn(opc_idiv)); break;
default: return;
}
cur_stack_height --;
}
}
void factor()
throws IOException, parseError, jasError
{
switch(inp.ttype)
{
case '(': match('('); expr(); match(')'); break;
case inp.TT_NUMBER:
int val = (int)(inp.nval);
emit(new Insn(opc_bipush, (short)val));
match(inp.TT_NUMBER);
break;
case inp.TT_WORD:
Integer idx;
if ((idx = (Integer) vars.get(inp.sval)) == null)
{
throw new parseError
("Unknown variable " + inp.sval + " at line " + inp.lineno());
}
emit(new Insn(opc_iload, idx.intValue()));
match(inp.TT_WORD);
break;
default:
throw new parseError("Syntax error at line " + inp.lineno());
}
cur_stack_height++;
if (max_stack_height < cur_stack_height)
max_stack_height = cur_stack_height;
}
void match(int val)
throws IOException, parseError
{
if (inp.ttype != val)
{ throw new parseError
("line " + inp.lineno() + ": expected " + val + " but got " + inp); }
inp.nextToken();
}
void emit(Insn insn)
{
myCode.addInsn(insn);
}
public static void main(String argv[])
throws Exception
{
exprcomp compiler =
new exprcomp(new StreamTokenizer(new FileInputStream(argv[0])));
compiler.parse();
ByteArrayOutputStream data = new ByteArrayOutputStream();
compiler.write(new DataOutputStream(data));
dynaloader dl = new dynaloader(data.toByteArray());
dl.exec();
}
}
class dynaloader extends ClassLoader
{
Hashtable cache;
Class ex;
dynaloader(byte[] data)
throws ClassFormatError
{
cache = new Hashtable();
ex = defineClass(data, 0, data.length);
cache.put("results", ex);
resolveClass(ex);
}
void exec() throws Exception { ex.newInstance(); }
public synchronized Class loadClass(String name, boolean resolve)
throws ClassNotFoundException
{
Class c = (Class) cache.get(name);
if (c == null)
{
c = findSystemClass(name);
cache.put(name, c);
}
if (resolve) resolveClass(c);
return c;
}
}
class parseError extends Exception
{ parseError(String s) { super(s); } }

View file

@ -0,0 +1,87 @@
;; create a container
(define my-class (make-class-env))
;; specify class hierarchy
(jas-class-setaccess my-class acc-public)
(jas-class-setclass my-class (make-class-cpe "out"))
(jas-class-setsuperclass my-class (make-class-cpe "java/lang/Object"))
;; write a convenience function to append insns as a list.
(define append-code
(lambda (code-part insn-list)
(mapcar (lambda (insn) (jas-code-addinsn code-part insn))
insn-list)))
;; Define code for initializer
;;
(define init-it (make-code))
(append-code
init-it
(quote
((aload_0)
(invokenonvirtual (make-method-cpe "java/lang/Object" "<init>" "()V"))
(return))))
;; this is the code that comprises
;; the actual task, ie the code for
;; main(String argv[]).
;; print a string 5 times
(define doit (make-code))
(append-code
doit
(quote
(
; store references in local
; variables to avoid field/cp
; lookup
(getstatic
(make-field-cpe "java/lang/System" "out" "Ljava/io/PrintStream;"))
(astore_1)
(ldc (make-string-cpe "Hello World"))
(astore_2)
(bipush 5)
(istore_3) ; store loop index in var reg 3
; loop 5 times, printing out
; the string.
(make-label "loop")
; push arguments to function
; on stack and call it
(aload_1) (aload_2)
(invokevirtual
(make-method-cpe "java/io/PrintStream" "println" "(Ljava/lang/String;)V"))
; decrement loop index
(iinc 3 -1)
(iload_3)
(ifne (make-label "loop"))
(return))))
;; set stack/var size
(jas-code-stack-size doit 3)
(jas-code-var-size doit 4)
;; fill up the class with the methods
;; first the initializer.
(jas-class-addmethod my-class acc-public "<init>" "()V" init-it ())
;; define the printing code as a static main(String argv[]) method
(jas-class-addmethod my-class
(| acc-static acc-public)
"main" "([Ljava/lang/String;)V" doit ())
;; write it out.
(jas-class-write my-class (make-outputstream "out.class"))

View file

@ -0,0 +1,78 @@
import jas.*;
import java.io.*;
import sun.tools.java.RuntimeConstants;
//
// This is program that makes calls into the jas package
// to generate a class that prints a string afew times.
//
class hworld implements RuntimeConstants
{
public static void main(String argv[])
throws jasError, IOException
{
// class hierarchy
ClassEnv nclass = new ClassEnv();
nclass.setClass(new ClassCP("out"));
nclass.setSuperClass(new ClassCP("java/lang/Object"));
nclass.setClassAccess((short)ACC_PUBLIC);
// Initialization code
CodeAttr init = new CodeAttr();
init.addInsn(new Insn(opc_aload_0));
init.addInsn(new Insn(opc_invokenonvirtual,
new MethodCP("java/lang/Object", "<init>", "()V")));
init.addInsn(new Insn(opc_return));
// Actual code to print string
CodeAttr doit = new CodeAttr();
// store refs in local variables
doit.addInsn(new Insn(opc_getstatic,
new FieldCP("java/lang/System",
"out",
"Ljava/io/PrintStream;")));
doit.addInsn(new Insn(opc_astore_1));
doit.addInsn(new Insn(opc_ldc,
new StringCP("Hello World")));
doit.addInsn(new Insn(opc_astore_2));
// Loop index in var reg 3
doit.addInsn(new Insn(opc_bipush, 5));
doit.addInsn(new Insn(opc_istore_3));
// Start the loop
Label loop = new Label("loop");
doit.addInsn(loop);
doit.addInsn(new Insn(opc_aload_1));
doit.addInsn(new Insn(opc_aload_2));
doit.addInsn(new Insn(opc_invokevirtual,
new MethodCP("java/io/PrintStream",
"println",
"(Ljava/lang/String;)V")));
doit.addInsn(new IincInsn(3, -1));
doit.addInsn(new Insn(opc_iload_3));
doit.addInsn(new Insn(opc_ifne, loop));
doit.addInsn(new Insn(opc_return));
// set the right sizes for code
doit.setStackSize((short)3); doit.setVarSize((short)4);
// Add the init code to the class.
nclass.addMethod((short)ACC_PUBLIC, "<init>", "()V", init, null);
// Add the printing code
nclass.addMethod((short)(ACC_PUBLIC|ACC_STATIC), "main",
"([Ljava/lang/String;)V", doit, null);
// write it all out
nclass.write(new DataOutputStream
(new FileOutputStream("out.class")));
}
}

View file

@ -0,0 +1,30 @@
;; script to create a class that does nothing.
; make-class-env creates
; a ClassEnv object which is
; used to store information about
; an object.
(define my-class (make-class-env))
; make-code creates a code object
; which contains the body of a
; method.
(define init-code (make-code))
(jas-code-addinsn init-code
(aload_0))
(jas-code-addinsn init-code
(invokenonvirtual
(make-method-cpe "java/lang/Object" "<init>" "()V")))
(jas-code-addinsn init-code
(return))
; fill up the class with goodies
(jas-class-setsuperclass my-class (make-class-cpe "java/lang/Object"))
(jas-class-setclass my-class (make-class-cpe "out"))
(jas-class-setaccess my-class acc-public)
(jas-class-addmethod my-class acc-public "<init>" "()V" init-code ())
; and write it all out
(jas-class-write my-class (make-outputstream "out.class"))

View file

@ -0,0 +1,45 @@
import jas.*;
import java.io.*;
import sun.tools.java.RuntimeConstants;
//
// This is program that makes calls into the jas package
// to generate a class that does nothing at all.
//
class simple implements RuntimeConstants
{
public static void main(String argv[])
throws jasError, IOException
{
// CodeAttr's contain the body of
// a method.
CodeAttr init = new CodeAttr();
init.addInsn(new Insn(opc_aload_0));
init.addInsn(new Insn(opc_invokenonvirtual,
new MethodCP("java/lang/Object", "<init>", "()V")));
init.addInsn(new Insn(opc_return));
// ClassEnv's are used as a container
// to hold all information about a class.
ClassEnv nclass = new ClassEnv();
nclass.setClass(new ClassCP("out"));
nclass.setSuperClass(new ClassCP("java/lang/Object"));
// Add the init code to the class.
nclass.addMethod((short)ACC_PUBLIC, "<init>", "()V", init, null);
// write it all out
nclass.write(new DataOutputStream
(new FileOutputStream("out.class")));
}
}

View file

@ -0,0 +1,8 @@
a = 10;
println a;
b = a + 5;
println (b);
println(a*b +2);