/* * $Id$ * * Copyright (C) 2003-2014 JNode.org * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this library; If not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ package org.jnode.jnasm.assembler; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.io.RandomAccessFile; import java.io.Reader; import java.io.StringReader; import java.io.StringWriter; import java.lang.reflect.Constructor; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import org.jnode.assembler.Label; import org.jnode.assembler.NativeStream; import org.jnode.jnasm.assembler.x86.X86Support; /** * @author Levente S\u00e1ntha (lsantha@users.sourceforge.net) */ public abstract class Assembler { private static final String PARSER_CLASS = "org.jnode.jnasm.assembler.gen.JNAsm"; public static final boolean THROW = false; protected static final Object UNDEFINED = "UNDEFINED"; protected final List<Instruction> instructions = new ArrayList<Instruction>(); private final Map<String, Integer> constants = new HashMap<String, Integer>(); private final Map<String, Label> labels = new HashMap<String, Label>(); private int pass = 0; protected final HardwareSupport hwSupport; private final PseudoInstructions pseudo; protected Instruction crtIns; public static Assembler newInstance(InputStream in) { try { Class<?> clazz = Class.forName(PARSER_CLASS); Constructor<?> cons = clazz.getConstructor(new Class[]{InputStream.class}); return (Assembler) cons.newInstance(in); } catch (Exception e) { throw new RuntimeException(e); } } public static Assembler newInstance(Reader reader) { try { Class<?> clazz = Class.forName("org.jnode.jnasm.assembler.gen.JNAsm"); Constructor<?> cons = clazz.getConstructor(new Class[]{Reader.class}); return (Assembler) cons.newInstance(reader); } catch (Exception e) { throw new RuntimeException(e); } } public static void main(String[] argv) throws Exception { Assembler jnasm = newInstance(System.in); FileOutputStream out = new FileOutputStream("out"); jnasm.performTwoPasses(new InputStreamReader(System.in), out); out.flush(); out.close(); } protected Assembler() { pseudo = new PseudoInstructions(labels, constants); hwSupport = new X86Support(this, instructions, labels, constants); } public PseudoInstructions getPseudo() { return pseudo; } public void performTwoPasses(Reader reader, OutputStream out) throws Exception { String data = readToString(reader); //1st pass ReInit(new StringReader(data)); setPass(1); jnasmInput(); assemble(0); //2nd pass setPass(2); instructions.clear(); ReInit(new StringReader(data)); jnasmInput(); emit(out); } public void performTwoPasses(Reader reader, NativeStream asm) throws Exception { String data = readToString(reader); //new RandomAccessFile("jnode.lst", "rw").write(data.getBytes()); //1st pass ReInit(new StringReader(data)); setPass(1); jnasmInput(); assemble((int) asm.getBaseAddr()); //2nd pass setPass(2); instructions.clear(); ReInit(new StringReader(data)); jnasmInput(); emit(asm); //asm.writeTo(new FileOutputStream("jnode.out")); } private static String readToString(Reader reader) throws IOException { StringWriter sw = new StringWriter(); char[] buf = new char[1024]; int count; while ((count = reader.read(buf)) > -1) { sw.write(buf, 0, count); } sw.flush(); sw.close(); return sw.toString(); } public void assemble(int baseAddress) { hwSupport.assemble(baseAddress); } public void assemble(NativeStream out) { hwSupport.assemble(out); } public void setPass(int pass) { this.pass = pass; hwSupport.setPass(pass); } public abstract void jnasmInput() throws Exception; public abstract void ReInit(Reader stream); public void emit(OutputStream out) throws IOException { assemble(0); hwSupport.writeTo(out); } public void emit(NativeStream out) throws IOException { assemble(out); } public void putConstant(String name, int value) { if (constants.get(name) != null && pass == 1) throw new IllegalArgumentException("Constant already defined: " + name); constants.put(name, value); } protected int getConstant(String name, int line) { Integer i = constants.get(name); try { if (i == null) throw new IllegalArgumentException("Undefined constant at line " + line + ": " + name); } catch (RuntimeException x) { if (THROW) { throw x; } else { if (pass == 2) { //todo verify these conversions if (name.startsWith("0x")) { try { return Integer.parseInt(name.substring(2), 16); } catch (NumberFormatException nfe) { //ignore } } try { return Integer.parseInt(name, 16); } catch (NumberFormatException nfe) { //ignore } try { return Integer.parseInt(name); } catch (NumberFormatException nfe) { //ignore } try { return Integer.parseInt(name, 8); } catch (NumberFormatException nfe) { //ignore } try { return Integer.parseInt(name, 2); } catch (NumberFormatException nfe) { //ignore } System.out.println(x.getMessage()); throw new UndefinedConstantException(name); } return Integer.MAX_VALUE; } } return i; } protected final void setSizeInfo(String size) { crtIns.setSizeInfo(size); } protected final void setJumpType(String jumpType) { crtIns.setJumpType(jumpType); } public static class UndefinedConstantException extends RuntimeException { private static final long serialVersionUID = 1L; private String constant; public UndefinedConstantException(String constant) { super(constant); this.constant = constant; } public String getConstant() { return constant; } } }