001 package ca.ryerson.kclowes.digsim.ui; 002 import ca.ryerson.kclowes.digsim.*; 003 import java.io.*; 004 import java.util.*; 005 006 /** 007 * Preprocess a circuit description interpreting/expanding macros. 008 * 009 * <p> 010 * A circuit description to preprocess contains (BNF description): 011 * 012 * <pre> 013 * description = defBlock | circuitBlock 014 * defBlock = 'defBlock' blockName blockArgs '\n' body 'enddef' 015 * blockName = <i>sequence of printable characters EXCEPT whitespace</i> 016 * blockArgs = arg* 017 * arg = <i>formal name</i> 018 * body = circuitBlock* 019 * circuitBlock = <i>DEFINED IN</i> CircuitParser <i>(as block)</i> 020 * </pre> 021 * <p> A comment can be added with '//'; the rest of the line is ignored. 022 * 023 * @author Ken Clowes (kclowes@ee.ryerson.ca) 024 * @version 1.0 (27 February 2004) 025 */ 026 public class CircuitPreprocessor { 027 private static CircuitPreprocessor INSTANCE = null; 028 private LineNumberReader lineReader; 029 private Writer writer; 030 031 private CircuitPreprocessor() {} 032 033 public static CircuitPreprocessor getInstance() 034 { 035 if (INSTANCE == null) { 036 INSTANCE = new CircuitPreprocessor(); 037 } 038 return INSTANCE; 039 } 040 /** 041 * Expand a circuit description. 042 * 043 * @param in The source of the circuit description. 044 * @param out Where the expansion is written. 045 */ 046 public void expand(Reader in, Writer out) 047 { 048 writer = out; 049 String line = null; 050 lineReader = new LineNumberReader(in); 051 try { 052 while ((line = lineReader.readLine()) != null) { 053 int commentStart = -1; 054 if ((commentStart = line.indexOf("//")) != -1) { 055 String comment = line.substring(commentStart); 056 line = line.substring(0, commentStart) + "\n"; 057 } 058 line = line.trim(); 059 if (line.equals("")) continue; 060 String [] words = line.split(" *", 2); 061 String firstWord = words[0]; 062 String rest = words[1]; 063 if (line.startsWith("defBlock ")) { 064 registerBlockDef(line); 065 continue; 066 } 067 if (isPrimitiveBlock(firstWord)) { 068 writer.write(line + "\n"); 069 writer.flush(); 070 continue; 071 } 072 if (MacroDefinition.containsMacro(firstWord)) { 073 MacroDefinition macro = MacroDefinition.getMacroNamed(firstWord); 074 String [] nodeNames = rest.split(" *"); 075 String expansion = macro.parse(nodeNames); 076 writer.write(expansion); 077 writer.flush(); 078 continue; 079 } 080 } 081 } catch (IOException e) { 082 System.err.println("Unexpected: " + e ); 083 System.exit(1); 084 } 085 } 086 087 private void registerBlockDef(String line) 088 { 089 line = removeComments(line); 090 String [] words = line.split(" *", 3); 091 String blockName = words[1]; 092 String [] nodeNames = words[2].split(" *"); 093 Vector macroLines = new Vector(); 094 try { 095 while ((line = lineReader.readLine()) != null) { 096 line = removeComments(line); 097 if (line.equals("")) continue; 098 if (line.startsWith("enddef")) { 099 break; 100 } 101 macroLines.add(line); 102 } 103 } catch (IOException e) { 104 System.err.println("Unexpected: " + e ); 105 System.exit(1); 106 } 107 String [] bodyStrings = new String[0]; 108 bodyStrings = (String []) macroLines.toArray(bodyStrings); 109 MacroDefinition macro = new MacroDefinition(blockName, nodeNames, bodyStrings); 110 } 111 112 private boolean isPrimitiveBlock(String b) 113 { 114 return b.equals("Nand"); 115 } 116 117 private String removeComments(String l) 118 { 119 int commentStart = -1; 120 if ((commentStart = l.indexOf("//")) != -1) { 121 String comment = l.substring(commentStart); 122 l = l.substring(0, commentStart) + "\n"; 123 } 124 l = l.trim(); 125 return l; 126 } 127 128 /** 129 * The <tt>main</tt> method allows the <tt>CircuitPreprocessor</tt> to be used 130 * as an application. 131 * 132 * <p>With no arguments, it works as a filter: a circuit description is read from 133 * <i>stdin</i> and its expansion is written to <i>stdout</i>. 134 */ 135 public static void main(String [] args) 136 { 137 CircuitPreprocessor p = CircuitPreprocessor.getInstance(); 138 Reader r = new InputStreamReader(System.in); 139 Writer w = new BufferedWriter(new OutputStreamWriter(System.out)); 140 p.expand(r, w); 141 System.exit(0); 142 } 143 }