/media/sda-magnetic/david/Dokumente-15/fernuni-hagen/cs-i-ii/old-cs-2-03/yun7x/Arithmetic9/Arithmetic.java


/*
Subklassen:

Expression
Term 
Factor

Terminals:
+ Plus 
* Mal
( OpenRoundBracket
) ClouseRoundBracket

Terminals:
0000 to 9999
aaaa to zzzz

Jetzt machen wir das so:

Wir rufen jedes Mal, wenn Expression aufgerufen wird, ein neues Objekt, zum Beispiel. Term wiederum kann ein neues Objekt erzeugen Faktor. 
Das heißt, wir haben drei Objekte. Die nicht voneinander vererbt sind

expression()
term()
factor()

Und jedes Mal, wenn wir einen Expression() erzeugen, erzeugen wir vielleicht einen Term()

Jeder diese Teile, zum Beispiel in

(5+6)*4

erzeugt ein eigenes Objekt Expression, Term, .... Es ist gleich gesagt, dass das viel Speicher in Anspruch nimmt, aber das ist uns jetzt egal.

Jetzt müssen wir unsere Objekte anschauen, wir haben 

Terminale: +, *, (, ), 99, aa
Nichtterminale: Expression, Term, Factor

Es bietet sich, Expression, Term, Factor zwar nicht voneinander zu vererben, aber eine Superklass

NichtTermal zu erstellen.
Genauso wie wir eine Superklasse Terminal haben

Wir müssen bedenken, dass auf Grund unserer Linksrekursion, die Regel 

expr ::= expr + term
term ::= term * factor
factor ::= const | id | (expr)

nicht gilt. Sondern wir haben expr2 und term2

Also wir haben 5

expr
expr2
term
term2
factor

Das interessante ist, dass sich unsere Vererbung schon augenscheinlich lohnt. Weil, wir haben eine lexikalische Analyse. Und die lautet gettoken()

Was wir bisher machen können, ist einen Lexer schreiben und wir ein kleines Programm bringen wir den Lexer, beim Parser unter.
Wir haben in C eine alleine stehe Funktion gettoken()

Wenn wir eine Superklasse terminal haben, dann bringen wir darin unter gettoken().

Und die gilt für alle Subklassen. 

Jetzt erzeugen wir ein Objekt, von der Klasse Expression. Dann kommt bei

(5+6)*4

Ein Expression. Wir erzeugen als ein Objekt von der Klasse Expression()

Der Term

Wir haben zwei Teile vom Term 

(5+6)
und 
4

Wir erzeugen zwei Objekte. Dann kommt der Faktor ("").
Und darin der Expresion 5+6.
Das heißt, wir erzeugen so viele Objekte, wie Bestandteile in unserem Ausdruck. Das kann nachher nützlich sein, wenn wir zum Beispiel einen Baum machen.

Jetzt fangen wir an:

Wir verzichten auf id, das heißt, aaa
*/
public class Arithmetic {
    static String SourceCode;
    static Register reg = new Register();
    static Terminal tr = new Terminal();
    static Asm asm = new Asm();
    
    
    static public class Asm {
        static String [][] asm;
        static int asmcount;
        static int [] regs; 
        static int [] vars;
    
        Asm () {
            asmcount = 0;
            asm = new String [1024*64][4];
            regs = new int[1024*64];
            vars = new int[26];
        }
        static void asmcounter (String opcode, String op1, String op2, String op3) {
            try {
                asm[asmcount][0] = opcode;
                asm[asmcount][1] = op1;
                asm[asmcount][2] = op2;
                asm[asmcount][3] = op3;
                asmcount++;
            }
            catch (ArrayIndexOutOfBoundsException e) {
                System.out.println ("Your code doesn't fit in the space given within the memory model of the programs virtual machine");
                System.exit(-1);
            }
        }
        
        static void virtualMachine () {
            int i;
            int reg1;
            int var1 = 0;
            int op2 = 0;
            int op3 = 0;
            
            try {
                for (i = 0;  i < asmcount;  i++) {
                    if (asm[i][0].equals("add") || asm[i][0].equals("mul")) {
                        if(asm[i][1].length() >= 3) {
                            if((asm[i][1].charAt(0) == '_') && (asm[i][1].charAt(1) == 'r')) {
                                reg1 = Integer.parseInt(asm[i][1].substring(2));
                    
                                if(asm[i][2].length() >= 3) {
                                    if((asm[i][2].charAt(0) == '_') && (asm[i][2].charAt(1) == 'r')) 
                                        op2 = regs[Integer.parseInt(asm[i][2].substring(2))];
                                    else if((asm[i][2].charAt(0) >= '0') && (asm[i][2].charAt(0) <= '9')) 
                                        op2 = Integer.parseInt(asm[i][2]);
                                    else if((asm[i][2].charAt(0) >= 'a') && (asm[i][2].charAt(0) <= 'z')) 
                                        op2 = vars[(int)(asm[i][2].charAt(0)) - (int)('a')];

                                }
                                else if((asm[i][2].charAt(0) >= '0') && (asm[i][2].charAt(0) <= '9')) {
                                    op2 = Integer.parseInt(asm[i][2]);
                                } 
                                else if((asm[i][2].charAt(0) >= 'a') && (asm[i][2].charAt(0) <= 'z')) {
                                    op2 = vars[(int)(asm[i][2].charAt(0)) - (int)('a')];
                                } 
                    
                                if(asm[i][3].length() >= 3) {
                                    if((asm[i][3].charAt(0) == '_') && (asm[i][3].charAt(1) == 'r')) 
                                        op3 = regs[Integer.parseInt(asm[i][3].substring(2))];
                                    else if((asm[i][3].charAt(0) >= '0') && (asm[i][3].charAt(0) <= '9')) 
                                        op3 = Integer.parseInt(asm[i][3]);
                                    else if((asm[i][3].charAt(0) >= 'a') && (asm[i][3].charAt(0) <= 'z')) 
                                        op3 = vars[(int)(asm[i][3].charAt(0)) - (int)('a')];

                                }
                                else if((asm[i][3].charAt(0) >= '0') && (asm[i][3].charAt(0) <= '9')) 
                                    op3 = Integer.parseInt(asm[i][3]);
                                else if((asm[i][3].charAt(0) >= 'a') && (asm[i][3].charAt(0) <= 'z')) 
                                    op3 = vars[(int)(asm[i][3].charAt(0)) - (int)('a')];

                                if (asm[i][0].equals("add")) 
                                    regs[reg1] = op2 + op3;
                                else if (asm[i][0].equals("mul")) 
                                    regs[reg1] = op2 * op3;
                        
                            }
                        }
                    }
                    else if (asm[i][0].equals("mov")) {               
                        if((asm[i][1].charAt(0) >= 'a') && (asm[i][1].charAt(0) <= 'z')) {
                            var1 = (int)(asm[i][1].charAt(0)) - (int)('a');
                            if(asm[i][2].length() >= 3) {
                                if((asm[i][2].charAt(0) == '_') && (asm[i][2].charAt(1) == 'r')) 
                                    op2 = regs[Integer.parseInt(asm[i][2].substring(2))];
                                else if((asm[i][2].charAt(0) >= '0') && (asm[i][2].charAt(0) <= '9')) 
                                    op2 = Integer.parseInt(asm[i][2]);
                            }
                            else if((asm[i][2].charAt(0) >= '0') && (asm[i][2].charAt(0) <= '9')) {
                                op2 = Integer.parseInt(asm[i][2]);
                            } 
                        }
                        vars[var1] = op2;
                    }
                    else if (asm[i][0].equals("print")) {               
                        if((asm[i][1].charAt(0) == '_') && (asm[i][1].charAt(1) == 'r')) {
                            reg1 = Integer.parseInt(asm[i][1].substring(2));
                            System.out.println ("print line: " + i + " - register: " + reg1 + " - value : "  + regs[reg1]);
                        }
                        else if((asm[i][1].charAt(0) >= 'a') && (asm[i][1].charAt(0) <= 'z')) {
                            var1 = (int)(asm[i][1].charAt(0)) - (int)('a');
                            System.out.println ("print line: " + i + " - variable: " + var1 + " - value : "  + vars[var1]);
                        }
                    }
                }
            }
            catch (ArrayIndexOutOfBoundsException e) {
                System.out.println ("Your code uses more than the maximum of the allowed number of registers");
                System.exit(-1);
            }
            for (i = 0;  i < asmcount;  i++)
                System.out.println (asm[i][0]+asm[i][1]+asm[i][2]+asm[i][3]);
            System.out.println (vars[(int)('i'-'a')]);
            
            for (i = 0;   i < 5;  i++)
               System.out.println (regs[i]);
            
        }
    }
        
    static public class Register {
        int regcount;
        Register () {
            this.regcount = -1;
        }
        
        String getnext() {
            regcount++;
            return "_r" + regcount;
        }
    }
    
    public static void main (String [] args) {
        SourceCode = "print(((10+10)*10)+2)+4;i:=4+5+4+5+19+40;printi;print5+5+i;print2";
        Squnce sq = new Squnce();
        System.out.println(sq.squnce());
        asm.virtualMachine();

    }
    
    static public class Terminal {
        int count;
        Terminal() {
            this.count = 0;
        }
        
        int getCount() {
            return this.count;
        }
        void setCount(int count) {
            this.count = count;
        }
            
        boolean isPlus() {
            if (SourceCode.length() <= count)
                return false;
            if(SourceCode.charAt(count) == '+') {
                count++;
                return true;
            }   
            return false;
        }
        boolean isMult() {
            if (SourceCode.length() <= count)
                return false;
            if(SourceCode.charAt(count) == '*') {
                count++;
                return true;
            }
            return false;
        }
        boolean isOpenRoundBracket() {
            if (SourceCode.length() <= count)
                return false;
            if(SourceCode.charAt(count) == '(') {
                count++;
                return true;
            }
            return false;
        }
        boolean isClosedRoundBracket() {
            if (SourceCode.length() <= count)
                return false;
            if(SourceCode.charAt(count) == ')') {
                count++;
                return true;
            }
            return false;
        }
        boolean isSemicolon() {
            if (SourceCode.length() <= count)
                return false;
            if(SourceCode.charAt(count) == ';') {
                count++;
                return true;
            }
            return false;
        }
        boolean isSet() {
            if (SourceCode.length() <= count+1)
                return false;
            if((SourceCode.charAt(count) == ':') && (SourceCode.charAt(count+1) == '=')) {
                count+=2;
                return true;
            }
            return false;
        }

        boolean isPrint() {
            if ((SourceCode.length() + "print".length()) <= count)
                return false;
            if(SourceCode.substring(count, count + "print".length()).equals("print")) {
                count += "print".length();
                return true;
            }
            return false;
        }
        String isConst () {
            String str = "";
            
            if (SourceCode.length() <= count)
                str = null;
            if (!((SourceCode.charAt(count) >= '0') && (SourceCode.charAt(count) <= '9')))
                str = null;
                
            if (count < SourceCode.length()) {
                while ((SourceCode.charAt(count) >= '0') && (SourceCode.charAt(count) <= '9')) {
                    str = str + Character.toString(SourceCode.charAt(count));
                    count++;
                    if (count >= SourceCode.length())
                        break;
                }
            }
            return str;
        }
        String isVarName () {
            String str = "";
            
            if (SourceCode.length() <= count)
                return null;
            if (!((SourceCode.charAt(count) >= 'a') && (SourceCode.charAt(count) <= 'z')))
                return null;        
            str = Character.toString(SourceCode.charAt(count));
            count++;
            return str;
        }
    }
    
    static public class NotTerminal {
        NotTerminal() {}
    }

    static public class Squnce extends NotTerminal {
        String op1;
        Stmnt st = new Stmnt();
        boolean flag = false;
        
        Squnce () {}
        
        boolean squnce() {
            if (flag = st.stmnt()) {
                if (tr.isSemicolon()) {
                    Squnce sq = new Squnce();
                    sq.squnce();
                }
            }
            return flag;
        }
    }
    
    static public class Assgnmnt extends NotTerminal {
        int oldCount;
        String varnam;
        String op2;
        
        Assgnmnt() {}
        
        boolean assgnmnt () {
            oldCount = tr.getCount();
            if ((varnam = tr.isVarName()) != null) {
                if (tr.isSet()) {
                    NumExpr ne = new NumExpr();
                    op2 = ne.numexpr();
                    Asm.asmcounter("mov", varnam, op2, null);
                    System.out.println ("mov " + varnam + ", " + op2);
                }
                else {
                    tr.setCount(oldCount);
                    return false;
                }
            }
            else {
                tr.setCount(oldCount);
                return false;
            }
            return true;
        }
    }

    static public class Stmnt extends NotTerminal {
        String op1;
        Stmnt () {}
        Assgnmnt as = new Assgnmnt();
        
        boolean stmnt () {
            if (tr.isPrint()) {
                NumExpr ne = new NumExpr();
                op1 = ne.numexpr();
                Asm.asmcounter("print", op1, null, null);
                return true;
            }
            else if (as.assgnmnt()) return true;
            return false;
        }
    }

    
    static public class NumExpr extends NotTerminal {
        String op1;
        String op2;
        String op3;
        
        NumExpr () {}
        
        String numexpr () {
            Term t = new Term();
            op1 = t.term();
            if (tr.isPlus()) {
                NumExpr e = new NumExpr();
                op2 = e.numexpr();
                op3 = reg.getnext();
                System.out.println ("add " + op3 + ", " + op1 + ", " + op2);
                Asm.asmcounter ("add", op3, op1, op2);
                return op3;
            }
            return op1;
        }
    }

    static public class Term extends NotTerminal {
        String op1;
        String op2;
        String op3;
        
        Term () {}
        
        String term () {
            Factor f = new Factor();
            op1 = f.factor();
            if (tr.isMult()) {
                Term t = new Term(); 
                op2 = t.term();
                op3 = reg.getnext();
                System.out.println ("mul " + op3 + ", " + op1 + ", " + op2);
                Asm.asmcounter ("mul", op3, op1, op2);
                return op3;
            }
            return op1;
        }
    }

    static public class Factor extends NotTerminal {
        String op1, op2, op3;
        
        Factor () {}
        
        String factor () {
            if (tr.isOpenRoundBracket()) {
                NumExpr e = new NumExpr();
                op1 = e.numexpr();
                if (tr.isClosedRoundBracket()) {
                    return op1;
                }
                else
                    System.out.println ("Error");
            }
            else if ((op1 = tr.isConst()) != null) {
                op3 = reg.getnext();
                System.out.println ("add " + op3 + ", 0, " + op1);
                Asm.asmcounter ("add", op3, "0", op1);
                return op3;
            }
            else if ((op1 = tr.isVarName()) != null) {
                op3 = reg.getnext();
                System.out.println ("add " + op3 + ", 0, " + op1);
                Asm.asmcounter ("add", op3, "0", op1);
                return op3;
            }

            else {
                System.out.println ("Error");
                op1 = null;
            }
            return op1;
        }
    }
}