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 }