import easyIO.*; /*** * Forfatter Arne Hanssen * * Gitt en gramatikk: * exp ::- exp op term | term * term ::- number | (exp) * op ::- +|-|* * * Skriver om til EBNF (programmet under er laget ut fra det): * exp ::- term { op term} * term ::- number | (exp) * op ::- +|-|* * * * * Kommentar fra Arne Hanssen: Jeg har testet programmet ?s?der?. S? jeg tror * koden er ganske grei. Det eneste jeg har funnet er at siden en i scanneren * aldri tester p? om det leste tegn er en char vil scanneren ikke luke ut de * tilfellene der vi har et velformet uttrykk med en karakter som siste tegn f?r * linjeskifte eller som siste tegn i fila som i "1+1a". * Men denne vil bli oppdaget "1+1a ". Dette kan jo lett fiskes med f?lgende * clause i Scannerklassen: * * else if(Character.isLetter(c)) * error(....); * * Men da m? en definer en error metode i scanneren osv. ***/ class SimpleCalc { public static void main (String[] args) { Parser parser = new Parser(args[0]); //Init parser Exp tree= parser.expression(); System.out.print(" Prefix:"); tree.prefix(); System.out.print("\n Postfix:"); tree.postfix(); System.out.println("\n Value: " + tree.value()); } } /** * Simple parser for expressions */ class Parser { private Scanner scanner; // Let the parser bootstrap the scanner. Parser (String filnavn) {scanner = new Scanner(filnavn);} // Builds and return the whole expression public Exp expression() { Exp expTree = exp(); // Check if no more char on line if(scanner.curToken != scanner.DOLR) error("More on line"); return expTree; } private Exp exp() { Exp tmp, newTmp; char operator; tmp= term(); while (scanner.curToken == scanner.OPRT) { operator = op(); if (scanner.curToken == scanner.DOLR) error("Expecting a term, found EOF"); newTmp = term(); // Parse the right child tmp = new OpNode(operator, tmp, newTmp); } return tmp; } // Parsing a term private Exp term() { Exp tmp; /* term ::- number */ if(scanner.curToken == scanner.NUMB) { tmp = new NumNode(Integer.parseInt(scanner.curLex)); scanner.readNext(); return tmp; } /* term ::- ( exp ) */ else if (scanner.curToken == scanner.LPAR) { scanner.readNext(); tmp = exp(); if(scanner.curToken == scanner.RPAR) { scanner.readNext(); return tmp; } else error("Expecting \')\', found " + scanner.curLex); } return null; // Dummy return } private char op() { char operator; if(scanner.curToken == scanner.OPRT) { operator = scanner.curLex.charAt(0); scanner.readNext(); return operator; } else error("..."); return '.'; // Dummy return, state not reached } private void error(String err) {System.out.println(err);System.exit(0);} } /** * Represents an expression **/ abstract class Exp { abstract void prefix(); abstract void postfix(); abstract int value(); } class OpNode extends Exp { private char operator; private Exp leftChild, rightChild; OpNode(char operator, Exp leftChild, Exp rightChild) { this.operator= operator; this.leftChild= leftChild; this.rightChild= rightChild; } // Prints the tree in prefix form public void prefix() { System.out.print(" " + operator); leftChild.prefix(); rightChild.prefix(); } // Prints the tree in postfix form public void postfix() { leftChild.postfix(); rightChild.postfix(); System.out.print(" " + operator); } // Calculate and return the value of the node public int value() { int lv= leftChild.value(); int rv= rightChild.value(); int v = 0; switch(operator) { case '+': v = lv + rv; break; case '-': v = lv - rv; break; case '*': v = lv * rv; break; } return v; } } class NumNode extends Exp { private int value; NumNode(int value) {this.value= value;} public void prefix() {System.out.print(" " + value);} public void postfix() {System.out.print(" " + value);} public int value() {return value;} } /** * Quick and dirty scanner for simple expressions */ class Scanner { private In infile; private char c; public final int NUMB = 1,OPRT = 2,LPAR = 3,RPAR= 4,DOLR = 5; public int curToken; public String curLex; // Bootstrap the scanner, // let 'c' be the next untreated lexem Scanner(String filename) { infile = new In(filename); c = infile.inChar(" "); readNext();// make first token } public void readNext() { curLex = c + ""; //Convert char -> String if (c=='+'|| c=='-'|| c=='*') { curToken = OPRT; c = infile.inChar(" "); } else if (c=='(') { curToken = LPAR; c = infile.inChar(" "); } else if (c==')') { curToken = RPAR; c = infile.inChar(" "); } else if (isNumber(c)) { StringBuffer buffer = new StringBuffer(); while (isNumber(c)) { buffer.append(c); c = infile.inChar(); } curToken= NUMB; curLex = buffer.toString(); if (c == ' ') // Skip trailing whitespace c = infile.inChar(" "); } // Treats newline or EOF as end of exp else if (infile.endOfFile() || c == '\n') curToken = DOLR; } // Simple number check private boolean isNumber(char c) { return (c == '1' || c=='2'|| c=='3'|| c=='4' || c== '5'|| c=='6'|| c=='7'|| c=='8' || c== '9'|| c=='0'); } }