| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201 |
- #TOYLAN_COMPILER
-
- OPEN REP ' '; --message file is connected with the screen
- $LEXEMS:=#CALL_PAS(35 'A.TOY');
- -- a list of tokens is loaded from the file A.TOY by scanner
- $S_TREE := #A_PROGRAM($LEXEMS);
- -- 1st phase; result of parsing - abstract syntax tree - is
- -- imbedded in the variable $S_TREE; during parsing messages
- -- about discovered errors in file REP can be output.
- IF $S_TREE -> OPEN GEN 'A.BAL'; -- if the tree is created,
- -- then file is opened to output the generated BAL text
- #G_PROGRAM($S_TREE); -- 2nd phase-code generation
- #INTERPRETER($S_TREE) -- 2nd phase-code interpretation
- ELSIF T -> REP << errors are discovered FI;
- REP << end ##
- #A_PROGRAM -- the rule is applied to the list of tokens
- (. PROGRAM $Id
- (* $DECL++:= #A_DECLARATION ';' *)
- --formation of variables table
- (+ $STATEMENTS !.:= #A_STATEMENT + ';' )
- --formation of statements list
- .) / RETURN 'PROGRAM' :: <. NAME : $Id,
- DECLARATIONS : $DECL ,
- STATEMENTS : $STATEMENTS .>/ ##
- #A_DECLARATION $TYPE := ( INTEGER ! BOOLEAN )
- (+ $Id /IF LAST #A_PROGRAM $DECL.$Id OR $REZ.$Id ->
- REP << VARIABLE $Id DOUBLE DEFINED FI;
- $REZ++:= <.$Id : $TYPE .>/ + ',' ) / RETURN $REZ / ##
- #A_STATEMENT $REZ := ( #A_ASSIGNMENT ! #A_INPUT !
- #A_OUTPUT ! #A_CONDITIONAL ) / RETURN $REZ / ;;
- (* $A!.:=S'($$ <> ';' ) *) -- skip until nearest ';'
- / REP << UNRECOGNIZED STATEMENT $A /
- ##
- #A_ASSIGNMENT $Id ':='/ $LPType := LAST #A_PROGRAM $DECL .$Id;
- IF NOT $LPType -> REP << VARIABLE $Id 'IS NOT DEFINED' FI /
- $E:= #A_EXPRESSION
- /IF $LPType <> $E . TYPE ->
- REP<< 'LEFT AND RIGHT SIDE TYPES ARE DIFFERENT '
- 'IN ASSIGNMENT STATEMENT ' FI;
- RETURN ASSIGNMENT::<. LEFT: $Id, RIGHT: $E .> /
- ONFAIL IF $LPType -> REP<< 'WRONG EXPRESSION IN ASSIGNMENT' FI ##
- #A_INPUT GET '('
- (+ $E !.:= $Id /IF LAST #A_PROGRAM $DECL.$Id <> INTEGER ->
- REP << $Id 'IN STATEMENT GET IS NOT OF THE TYPE INTEGER'
- FI / + ',' ) ')' / RETURN INPUT :: $E / ##
- #A_OUTPUT PUT '(' (+ $C := #A_EXPRESSION / $E !.:= $C;
- IF $C . TYPE <> INTEGER ->
- REP << 'OPERAND OF PUT STATEMENT IS NOT OF THE TYPE INTEGER'
- FI / + ',' ) ')'/ RETURN OUTPUT :: $E / ##
- #A_CONDITIONAL 'IF' $BE := #A_EXPRESSION
- /IF $BE . TYPE <> BOOLEAN ->
- REP<< 'CONDITION IS NOT OF BOOLEAN TYPE' FI /
- 'THEN' (+ $P1 !.:= #A_STATEMENT + ';' )
- [ 'ELSE' (+ $P2 !.:= #A_STATEMENT + ';' ) ] 'FI'
- / RETURN CONDITIONAL :: <. COND : $BE , THEN : $P1 ,
- ELSE : $P2 .> / ##
- #A_EXPRESSION $A := #A_SUM [ '=' $B := #A_SUM
- / $A := COMPARE::<. ARG1 : $A, ARG2 : $B, TYPE : BOOLEAN.>/ ]
- / RETURN $A / ##
- #A_SUM $A := #A_FACTOR (* '+' $B := #A_FACTOR
- / $A := ADD::<. ARG1: $A, ARG2: $B, TYPE: INTEGER .>/ *)
- / RETURN $A / ##
- #A_FACTOR $A := #A_TERM (* '*' $B := #A_TERM
- /$A := MULT::<. ARG1: $A, ARG2: $B, TYPE: INTEGER .>/ *)
- / RETURN $A / ##
- #A_TERM
- $N / RETURN <. CONSTANT : $N , TYPE : INTEGER .>/;;
- ( ( TRUE / $K :=1/ ) ! ( FALSE / $K :=0 / ) )
- /RETURN <. CONSTANT: $K, TYPE: BOOLEAN .>/ ;;
- $Id / $X:= LAST #A_PROGRAM $DECL.$Id;
- IF NOT $X -> REP << VARIABLE $Id IS NOT DECLARED
- ELSIF T -> RETURN <. VARIABLE: $Id, TYPE: $X .> FI / ;;
- '(' $E := #A_EXPRESSION ')' / RETURN $E / ##
- #INTERPRETER
- $P
- / $++:= <. VARIABLES : #CREATE_TABLE ($P.DECLARATIONS) .>;
- --PRINT $;
- #I_PROGRAM ($);
- PRINT $.VARIABLES;
- /
- ##
- #CREATE_TABLE
- <* $Id : $Type / $Y ++ := <. $Id : 0 .> / *>
- / RETURN $Y /
- ##
- #I_PROGRAM
- <. STATEMENTS : #I_STATEMENTS .>
- ##
- #I_STATEMENTS (. (* #I_STATEMENT
- / PRINT LAST #INTERPRETER $.VARIABLES;
- #CALL_PAS(1) /
- *) .) ##
- #I_STATEMENT
- ( #I_INPUT ! #I_OUTPUT ! #I_ASSIGNMENT ! #I_CONDITIONAL ) ##
- #I_INPUT
- INPUT :: (. (* $Id
- /
- LAST #INTERPRETER $.VARIABLES.$Id:=
- #CALL_PAS(1 'toylan>') /
- *) .)
- ##
- #I_OUTPUT
- OUTPUT :: (. (* $E:= #I_EXPRESSION
- / REP << $E /
- *) .)
- ##
- #I_ASSIGNMENT
- ASSIGNMENT :: <. LEFT : $Id,
- RIGHT : $R:=#I_EXPRESSION
- .>
- / LAST #INTERPRETER $.VARIABLES.$Id:=$R/
- ##
- #I_CONDITIONAL
- CONDITIONAL :: <. COND : $E:=#I_EXPRESSION .>
- / IF $E<>0 -> #I_STATEMENTS ($.THEN)
- ELSIF $.ELSE -> #I_STATEMENTS ($.ELSE)
- FI /
- ##
- #I_EXPRESSION
- <. CONSTANT : $N .> / RETURN $N /;;
- <. VARIABLE : $Id .>
- / RETURN LAST #INTERPRETER $.VARIABLES.$Id/;;
- ADD:: <. ARG1 : $E1:=#I_EXPRESSION,
- ARG2 : $E2:=#I_EXPRESSION
- .>
- / RETURN $E1+$E2 /;;
- MULT:: <. ARG1 : $E1:=#I_EXPRESSION,
- ARG2 : $E2:=#I_EXPRESSION
- .>
- / RETURN $E1*$E2 /;;
- COMPARE:: <. ARG1 : $E1:=#I_EXPRESSION,
- ARG2 : $E2:=#I_EXPRESSION
- .> / IF $E1=$E2 -> RETURN 1
- ELSIF T -> RETURN 0
- FI/ ##
- #G_PROGRAM / $LABEL := 0 / --global variable $LABEL serves
- --to generate unique labels.
- PROGRAM::<.DECLARATIONS: $TAB := #TABLE_OF_NUMBERS,
- --creation of the table of unique variable numbers
- STATEMENTS: (.(* #G_STATEMENT *).) / GEN << 'EOJ' /,
- DECLARATIONS : #G_DECLARATIONS .> ##
- #TABLE_OF_NUMBERS <* $Id: $TYPE /$N :=$N+1; $T++:=<. $Id: $N.>/ *>
- /RETURN $T/ ##
- #G_STATEMENT ( #G_ASSIGNMENT ! #G_INPUT !
- #G_OUTPUT ! #G_CONDITIONAL ) ##
- #G_ASSIGNMENT ASSIGNMENT::<. LEFT: $Id := #NAME,
- RIGHT :( ( <. VARIABLE: $Id1:=#NAME .>
- /GEN << MOV @ $Id1 ',' $Id / ) !
- ( <. CONSTANT : $N .> /GEN << MOV @ '=' $N ',' $Id /) !
- ( $NREG := #G_EXPRESSION
- /GEN << 'SAVE' @ 'R' $NREG ',' $Id / ) ) .> ##
- #G_INPUT INPUT::(. (* $Id := #NAME /GEN << READ $Id / *) .) ##
- #G_OUTPUT OUTPUT :: (. (*
- ( ( <. VARIABLE : $Id := #NAME .> /GEN << WRITE $Id / ) !
- ( <. CONSTANT : $N .> /GEN << WRITE @ '=' $N / ) !
- ( $NREG := #G_EXPRESSION /GEN << WRITE @ 'R' $NREG /) )
- *) .) ##
- #G_CONDITIONAL CONDITIONAL ::
- <. COND : $NREG := #G_EXPRESSION
- / $LABEL1 :=#NEW_LABEL(); $LABEL2 :=#NEW_LABEL() /,
- THEN : / GEN << BRANCH @ 'R' $NREG ',L' $LABEL1 /
- (. (* #G_STATEMENT *) .)
- / IF $.ELSE -> GEN << JUMP @ 'L' $LABEL2 FI;
- GEN << @ 'L' $LABEL1 ': NOP' / ,
- [ ELSE : (. (* #G_STATEMENT *) .)
- / GEN << @ 'L' $LABEL2 ': NOP' / ] .> ##
- #G_EXPRESSION --returns the number of the register containing
- --result of the evaluation of expression
- $EXPR
- / $NREG := 0 / -- number of the first accessible register
- /RETURN #G_EXPR($EXPR)/
- ##
- #G_EXPR ( <. VARIABLE: $ID :=#NAME .> !
- <. CONSTANT: $N / $ID := #IMPLODE('=' $N)/ .>)
- / $REG := COPY( LAST #G_EXPRESSION $NREG ) ;
- GEN << 'LOAD' @ 'R' $REG ',' $ID ;
- LAST #G_EXPRESSION $NREG + := 1; RETURN $REG / ;;
- $OP::<. ARG1 : $R1 := #G_EXPR, ARG2 : $R2 := #G_EXPR .>
- / GEN << $OP @ 'R' $R1 ',R' $R2 ; RETURN $R1 / ##
- #G_DECLARATIONS
- <* $ID: $TYPE /$ID1 := #NAME($ID); GEN<< $ID1 ':' DEFWORD 0 /*> ##
- #NEW_LABEL --auxiliary rule
- /LAST #G_PROGRAM $LABEL+:=1;
- RETURN COPY (LAST #G_PROGRAM $LABEL )/ ##
- #NAME $ID --returns standard name of the variable $ID in $TAB
- / RETURN #IMPLODE( VAR LAST #G_PROGRAM $TAB.$ID)/ ##
|