Back to index

wims  3.65+svn20090927
SimpleCodeGen.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 /* Non-optimizing Code Generator
00020    Reads tokens in RPN (Reverse Polish Notation) order,
00021    and generates VM opcodes,
00022    without any optimization.
00023  */
00024 
00025 class SimpleCodeGen extends TokenConsumer {
00026     private CompiledFunction compiledFunction = new CompiledFunction();
00027     static final SyntaxException HAS_ARGUMENTS = new SyntaxException();
00028 
00029     ByteStack code      = new ByteStack();
00030     DoubleStack consts  = new DoubleStack();
00031     FunctionStack funcs = new FunctionStack();
00032 
00033     //String argNames[];
00034     Symbols symbols;
00035 
00036     SyntaxException exception;
00037 
00038     SimpleCodeGen(SyntaxException exception) {
00039         this.exception = exception;
00040     }
00041 
00042     SimpleCodeGen setSymbols(Symbols symbols) {
00043         this.symbols = symbols;
00044         return this;
00045     }
00046 
00047     //@Override
00048     void start() {
00049         code.clear();
00050         consts.clear();
00051         funcs.clear();
00052     }
00053     
00054     void push(Token token) throws SyntaxException {
00055         byte op;
00056         switch (token.id) {
00057         case Lexer.NUMBER:
00058             op = VM.CONST;
00059             consts.push(token.value);
00060             break;
00061             
00062         case Lexer.CONST:
00063         case Lexer.CALL:
00064             Symbol symbol = symbols.lookup(token.name, token.arity);
00065             if (symbol == null) {
00066                 throw exception.set("undefined '" + token.name + "' with arity " + token.arity, token.position); 
00067             }
00068             if (symbol.op > 0) { // built-in
00069                 op = symbol.op;
00070                 if (op >= VM.LOAD0 && op <= VM.LOAD4) {
00071                     throw HAS_ARGUMENTS.set("eval() on implicit function", exception.position);
00072                 }
00073             } else if (symbol.fun != null) { // function call
00074                 op = VM.CALL;
00075                 funcs.push(symbol.fun);
00076             } else { // variable reference
00077                 op = VM.CONST;
00078                 consts.push(symbol.value);
00079             }
00080             break;
00081                         
00082         default:
00083             op = token.vmop;
00084             if (op <= 0) {
00085                 throw new Error("wrong vmop: " + op);
00086             }
00087         }
00088         code.push(op);
00089     }
00090     
00091     double getValue() {
00092         compiledFunction.init(0, code.toArray(), consts.toArray(), funcs.toArray());
00093         try {
00094             return compiledFunction.eval();
00095         } catch (ArityException e) {
00096             throw new Error("" + e); //never
00097         }
00098     }
00099 }