{       PROGRAM ASSEMBLEY CODE GENERATOR
        PROGRAMMER:SEYED MOHAMMAD HOSSEIN HAMIDI
        STUDENT ID:79121207
        PROGRAMMING EXERCISE:1
        TEACHER:DR. GHODSI
}
CONST  OPERATORS =['+','*','-','/','~','^','(',')'];
       BINARY_OPERATORS=['+','*','-','/','^'];
       BLANK=' ';   
       MAX_LENGTH=200;
TYPE
    STACK_DATA=STRING[20];   
    LABEL_TYPE=STRING[20];   
    STACK=^CELL;
    CELL=RECORD
               INFO:STACK_DATA;
               LINK:STACK;
         END;

	ACTION_TYPE=ARRAY ['('..'~' ,'('..'~' ] OF CHAR;
	POSTFIX_TYPE=ARRAY [1..MAX_LENGTH] OF LABEL_TYPE;
	TREE_TYPE=^NODE;
	NODE=RECORD
                 TREE_LABEL:LABEL_TYPE;
                 LEFT,RIGHT:TREE_TYPE;
           END;
VAR
      POSTFIX:POSTFIX_TYPE;
      N,I,A:INTEGER;
      TREE:TREE_TYPE;
      INF,OUTF:TEXT;
      IN_FILE_NAME,OUT_FILE_NAME:STRING[8];

   PROCEDURE MAKE_NULL(VAR S:STACK);
   BEGIN
        S:=NIL;
   END;

   FUNCTION EMPTY (VAR S:STACK):BOOLEAN;
   BEGIN
        EMPTY := (S=NIL);
   END;

   FUNCTION TOP (VAR S:STACK):STACK_DATA;
   BEGIN
        TOP:=S^.INFO;
   END;

   PROCEDURE PUSH (X:STACK_DATA; VAR S:STACK);
   VAR       OLD_HEAD:STACK;
   BEGIN
        OLD_HEAD:=S;
        NEW(S);
        S^.INFO:=X;
        S^.LINK:=OLD_HEAD;
   END;

   PROCEDURE POP(VAR S:STACK);
   VAR       OLD_HEAD:STACK;
   BEGIN
        OLD_HEAD:=S;
        S:=S^.LINK;
        DISPOSE(OLD_HEAD);
   END;


   PROCEDURE INITIALIZE_ACTIONS(VAR ACTION:ACTION_TYPE);
   BEGIN
        ACTION['(','(']:='P'; ACTION['(','-']:='P'; ACTION['(','+']:='P'; ACTION['(','*']:='P';
        ACTION['(','/']:='P'; ACTION['(','^']:='P'; ACTION['(','~']:='P';

        ACTION['-','(']:='P'; ACTION['-','-']:='O'; ACTION['-','+']:='O'; ACTION['-','*']:='O';
        ACTION['-','/']:='O'; ACTION['-','^']:='O'; ACTION['-','~']:='O';

        ACTION['+','(']:='P'; ACTION['+','-']:='O'; ACTION['+','+']:='O'; ACTION['+','*']:='O';
        ACTION['+','/']:='O'; ACTION['+','^']:='O'; ACTION['+','~']:='O';

        ACTION['*','(']:='P'; ACTION['*','-']:='P'; ACTION['*','+']:='P'; ACTION['*','*']:='O';
        ACTION['*','/']:='O'; ACTION['*','^']:='O'; ACTION['*','~']:='O';

        ACTION['/','(']:='P'; ACTION['/','-']:='P'; ACTION['/','+']:='P'; ACTION['/','*']:='O';
        ACTION['/','/']:='O'; ACTION['/','^']:='O'; ACTION['/','~']:='O';

        ACTION['^','(']:='P'; ACTION['^','-']:='P'; ACTION['^','+']:='P'; ACTION['^','*']:='P';
        ACTION['^','/']:='P'; ACTION['^','^']:='P'; ACTION['^','~']:='O';

        ACTION['~','(']:='P'; ACTION['~','-']:='P'; ACTION['~','+']:='P'; ACTION['~','*']:='P';
        ACTION['~','/']:='P'; ACTION['~','^']:='P'; ACTION['~','~']:='P';

        ACTION[')','(']:='*'; ACTION[')','-']:='O'; ACTION[')','+']:='O'; ACTION[')','*']:='O';
        ACTION[')','/']:='O'; ACTION[')','^']:='O'; ACTION[')','~']:='O';

   END;

   PROCEDURE INFIX_TO_POSTFIX(VAR POSTFIX:POSTFIX_TYPE; VAR N:INTEGER);
   VAR       S:STACK;
             CH,X:CHAR;
             C,XX:STACK_DATA;
             DONE:BOOLEAN;
             OPERATOR:BOOLEAN;
             ACTION:ACTION_TYPE;
   BEGIN
      MAKE_NULL(S); INITIALIZE_ACTIONS(ACTION); N:=0;
      WHILE NOT EOLN(INF) DO BEGIN
         C:='';
         REPEAT
            READ (INF,CH);
            OPERATOR:=(CH IN OPERATORS);
            IF NOT OPERATOR AND(CH<> BLANK) THEN
               C:=C+CH;
         UNTIL EOLN(INF) OR OPERATOR;

         IF C<>'' THEN BEGIN
            WRITE (OUTF,C); WRITE (OUTF,BLANK);
            INC(N); POSTFIX[N]:=C;
         END;

         IF OPERATOR THEN BEGIN
            DONE:=FALSE;
            WHILE NOT  DONE  DO BEGIN
               IF EMPTY(S) THEN BEGIN
                  PUSH (CH,S); DONE:=TRUE
               END
               ELSE  BEGIN
                 XX:=TOP(S);
                 X:=XX[1];
                 IF (CH=')') AND (X='(')
                   THEN BEGIN
                      POP (S); DONE:=TRUE
                   END
                 ELSE IF ACTION[CH,X]='P'
                      THEN BEGIN
                         PUSH(CH,S); DONE:=TRUE;
                      END
                      ELSE IF ACTION[CH,X]='O'
                      THEN BEGIN
                         WRITE(OUTF,X); WRITE (OUTF,BLANK); POP(S);
                         INC(n); POSTFIX[N]:=X;
                      END;
               END;
            END; {WHILE}
         END;
      END; {WHILE}
      WHILE NOT EMPTY (S) DO BEGIN
         WRITE (OUTF,TOP(S));
         INC(N); POSTFIX[N]:=TOP(S);
         POP(S);
      END;

   END; {INFIX_TO_POSTFIX}
   FUNCTION POSTFIX_TO_TREE (VAR POSTFIX:POSTFIX_TYPE; VAR J:INTEGER):TREE_TYPE;
   VAR      T:TREE_TYPE;
            CH:CHAR;
   BEGIN
      NEW(T);
      T^.TREE_LABEL:=POSTFIX[J];
      CH:=POSTFIX[J][1];
      CASE CH OF
         '+','*','-','/','^':BEGIN
            DEC(J);
            T^.RIGHT:=POSTFIX_TO_TREE(POSTFIX,J);
            DEC(J);
            T^.LEFT:=POSTFIX_TO_TREE(POSTFIX,J);
         END;
         '~':BEGIN
             DEC(J);
             T^.RIGHT:=POSTFIX_TO_TREE(POSTFIX,J);
             T^.LEFT:=NIL;
         END;
         ELSE BEGIN
             T^.RIGHT:=NIL;
             T^.LEFT:=NIL;
         END;
      END;
      POSTFIX_TO_TREE:=T;
   END; {POSTFIX_TO_TREE}

   PROCEDURE FULLY_PARENTHESIZED(VAR TREE:TREE_TYPE);
   VAR       R,P,Q:TREE_TYPE;
             CH:CHAR;
   BEGIN
      IF (TREE<>NIL) THEN BEGIN
         R:=TREE;
         P:=R^.LEFT;
         CH:=R^.TREE_LABEL[1];
         IF CH IN OPERATORS THEN WRITE(OUTF,'(');
         FULLY_PARENTHESIZED(P);
         WRITE (OUTF,R^.TREE_LABEL);
         Q:=R^.RIGHT;
         FULLY_PARENTHESIZED(Q);

         IF Q<>NIL THEN WRITE(OUTF,')');
      END;
   END;
   FUNCTION MAX(X:INTEGER;Y:INTEGER):INTEGER;
   VAR      TEMP_MAX:INTEGER;
   BEGIN
      TEMP_MAX:=X;
      IF Y>TEMP_MAX THEN TEMP_MAX:=Y;
      MAX:=TEMP_MAX;
   END;

   FUNCTION HEIGHT(T:TREE_TYPE):INTEGER;
   VAR      X,Y:INTEGER;
            TEMP:INTEGER;
   BEGIN
      IF (T<>NIL) THEN BEGIN
         X:=HEIGHT(T^.LEFT);
         Y:=HEIGHT(T^.RIGHT);
         HEIGHT:=MAX(X,Y)+1;
      END
      ELSE HEIGHT:=-1;
   END; {HEIGHT}
   FUNCTION MAX_HEIGHT(T1,T2:TREE_TYPE):TREE_TYPE;
   BEGIN
        IF HEIGHT(T1)>HEIGHT(T2) THEN
           MAX_HEIGHT:=T1
        ELSE
           MAX_HEIGHT:=T2;
   END;
   FUNCTION MIN_HEIGHT(T1,T2:TREE_TYPE):TREE_TYPE;
   BEGIN
        IF HEIGHT(T1)<=HEIGHT(T2) THEN
           MIN_HEIGHT:=T1
        ELSE
           MIN_HEIGHT:=T2;
   END;

   PROCEDURE BINARY_OPERATION(OP:CHAR; T_LABEL:LABEL_TYPE);
   BEGIN
      CASE OP OF
         '+':
         WRITE(OUTF,'ADD ');
         '-':
         WRITE(OUTF,'SUB ');
         '*':
         WRITE(OUTF,'MUL ');
         '/':
         WRITE(OUTF,'DIV ');
         '^':
         WRITE(OUTF,'PWR ');
      END;
      WRITELN(OUTF,T_LABEL);
   END;
   PROCEDURE TRANSLATE(VAR TREE:TREE_TYPE);
   VAR       L,R:TREE_TYPE;
             CH,L_T_LABEL,R_T_LABEL:CHAR;
             T_LABEL,XX,S:LABEL_TYPE;
             MAX_HEIGHT_TREE,MIN_HEIGHT_TREE:TREE_TYPE;
             DONE:BOOLEAN;
   BEGIN

      IF (TREE<>NIL) THEN BEGIN
         DONE:=FALSE;
         T_LABEL:=TREE^.TREE_LABEL;
         CH:=T_LABEL[1];
         L:=TREE^.LEFT; L_T_LABEL:=L^.TREE_LABEL[1];
         R:=TREE^.RIGHT; R_T_LABEL:=R^.TREE_LABEL[1];
         IF NOT (CH IN OPERATORS) THEN BEGIN
            WRITE (OUTF,'LDE ');WRITELN(OUTF,T_LABEL);
         END
         ELSE IF CH IN BINARY_OPERATORS THEN BEGIN

            IF NOT ((L_T_LABEL IN OPERATORS) OR (R_T_LABEL IN OPERATORS)) THEN BEGIN
               TRANSLATE(L);
               XX:=R^.TREE_LABEL;
            END
            ELSE BEGIN
              IF ((L_T_LABEL IN OPERATORS) XOR (R_T_LABEL IN OPERATORS))
               THEN BEGIN
                  IF MAX_HEIGHT(L,R)=L THEN BEGIN
                     TRANSLATE(L);
                     XX:=R^.TREE_LABEL; DONE:=TRUE;
                  END
                  ELSE IF (CH IN ['+','*']) THEN BEGIN
                     TRANSLATE(R);
                     XX:=L^.TREE_LABEL ; DONE:=TRUE;
                  END
               END;
              IF ((L_T_LABEL IN OPERATORS) OR (R_T_LABEL IN OPERATORS))AND NOT DONE THEN BEGIN
                 MAX_HEIGHT_TREE:=MAX_HEIGHT(L,R);
                 TRANSLATE(MAX_HEIGHT_TREE);

                    INC(i);
                    STR(I,S);
                    XX:='TEMP'+S;
                    WRITE(OUTF,'STR '); WRITELN(OUTF,XX);

                 MIN_HEIGHT_TREE:=MIN_HEIGHT(L,R);
                 TRANSLATE(MIN_HEIGHT_TREE);
              END;
            END;

            BINARY_OPERATION(CH,XX);
            IF XX='TEMP'+S THEN DEC(I);
         END
         ELSE IF CH='~' THEN BEGIN
            TRANSLATE(R);
            WRITELN(OUTF,'NEG');
         END;

      END;

   END;{TRANSLATE}


BEGIN
    WRITELN ('CHOOSE YOUR FAVORITE I/O');
    WRITELN ('1.STANDARD I/O(MONITOR)');
    WRITELN ('2.FILE (e.g. DATA.IN & DATA.OUT)');
    READ(A);
    IF A=1 THEN BEGIN
       IN_FILE_NAME:='';
       OUT_FILE_NAME:='';
    END
    ELSE BEGIN
       IN_FILE_NAME:='DATA.IN';
       OUT_FILE_NAME:='DATA.OUT';
    END;
    ASSIGN (INf,IN_FILE_NAME);
    ASSIGN (OUTF,OUT_FILE_NAME);
    RESET(INF); REWRITE(OUTF);

    INFIX_TO_POSTFIX(POSTFIX,N);
    WRITELN(OUTF);
    TREE:=POSTFIX_TO_TREE(POSTFIX,N);

    FULLY_PARENTHESIZED(TREE);
    WRITELN(OUTF);
    I:=0;
    TRANSLATE(TREE);
    WRITELN (OUTF);
    CLOSE(INF); CLOSE(OUTF);
END. {MAIN}
