Back to index

wims  3.65+svn20090927
OptCodeGen.java
Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2007-2008 Mihai Preda.
00003  *
00004  * Licensed under the Apache License, Version 2.0 (the "License");
00005  * you may not use this file except in compliance with the License.
00006  * You may obtain a copy of the License at
00007  *
00008  *      http://www.apache.org/licenses/LICENSE-2.0
00009  *
00010  * Unless required by applicable law or agreed to in writing, software
00011  * distributed under the License is distributed on an "AS IS" BASIS,
00012  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00013  * See the License for the specific language governing permissions and
00014  * limitations under the License.
00015  */
00016 
00017 package org.javia.arity;
00018 
00019 /* Optimizing Code Generator
00020    Reads tokens in RPN (Reverse Polish Notation) order,
00021    and generates VM opcodes,
00022    doing constant-folding optimization.
00023  */
00024 
00025 class OptCodeGen extends SimpleCodeGen {
00026     double stack[]  = new double[CompiledFunction.MAX_STACK_SIZE];        
00027     int sp = -1;
00028 
00029     double traceConsts[] = new double[1];
00030     Function traceFuncs[] = new Function[1];
00031     byte traceCode[] = new byte[1];
00032     CompiledFunction tracer = new CompiledFunction(0, traceCode, traceConsts, traceFuncs);
00033 
00034     int intrinsicArity;
00035     
00036     OptCodeGen(SyntaxException e) {
00037         super(e);
00038     }
00039 
00040     //@Override
00041     void start() {
00042         super.start();
00043         sp = -1;
00044         intrinsicArity = 0;
00045     }
00046 
00047     //@Override
00048     void push(Token token) throws SyntaxException {
00049         byte op;
00050         switch (token.id) {
00051         case Lexer.NUMBER:
00052             op = VM.CONST;
00053             traceConsts[0] = token.value;
00054             break;
00055             
00056         case Lexer.CONST:
00057         case Lexer.CALL:
00058             Symbol symbol = symbols.lookup(token.name, token.arity);
00059             if (symbol == null) {
00060                 throw exception.set("undefined '" + token.name + "' with arity " + token.arity, token.position); 
00061             }
00062             if (symbol.op > 0) { // built-in
00063                 op = symbol.op;
00064                 if (op >= VM.LOAD0 && op <= VM.LOAD4) {
00065                     int arg = op - VM.LOAD0;
00066                     if (arg + 1 > intrinsicArity) {
00067                         intrinsicArity = arg + 1;
00068                     }
00069                 }
00070             } else if (symbol.fun != null) { // function call
00071                 op = VM.CALL;
00072                 traceFuncs[0] = symbol.fun;
00073             } else { // variable reference
00074                 op = VM.CONST;
00075                 traceConsts[0] = symbol.value;
00076             }
00077             break;
00078                         
00079         default:
00080             op = token.vmop;
00081             if (op <= 0) {
00082                 throw new Error("wrong vmop: " + op);
00083             }
00084         }
00085         int oldSP = sp;
00086         traceCode[0] = op;
00087         if (op != VM.RND) {
00088             sp = tracer.execWithoutCheck(stack, sp);
00089         } else {
00090             stack[++sp] = Double.NaN;
00091         }
00092 
00093         //constant folding
00094         if (!Double.isNaN(stack[sp]) || op == VM.CONST) {
00095             code.pop(oldSP + 1 - sp);
00096             consts.pop(oldSP + 1 - sp);
00097             consts.push(stack[sp]);
00098             op = VM.CONST;
00099         } else if (op == VM.CALL) {
00100             funcs.push(traceFuncs[0]);
00101         }
00102         code.push(op);
00103     }
00104 
00105     CompiledFunction getFun(int arity) {
00106         return new CompiledFunction(arity, code.toArray(), consts.toArray(), funcs.toArray());
00107     }
00108 }