home *** CD-ROM | disk | FTP | other *** search
- unit compile;
-
- { Main program for compiler }
-
- interface
- uses global, util, state;
- procedure compiler(var result: boolean);
-
- implementation
-
- procedure block(level: integer);
-
- { Compile a block -
- all routines except initialization are local to block }
- type
- conrec = { constant record }
- record
- tp: types; { constant type }
- i: integer { constant value }
- end;
-
- var dx: integer; { counter for stack memory requirements }
- prt: integer; { symbol table pointer for this block }
- prb: integer; { block table pointer for this block }
-
- procedure constant(var c: conrec);
- { Constant declaration:
- character or integer constants,
- also equate one constant to another.
- Called from variable declaration in Ada }
- var x, sign: integer;
- begin
- c.tp := notyp;
- c.i := 0;
- if sy in constbegsys then
- if sy = charcon then
- begin
- c.tp := chars;
- c.i := inum;
- insymbol
- end
- else begin
- sign := 1;
- if sy in [plus, minus] then
- begin
- if sy = minus then sign := -1;
- insymbol
- end;
- if sy = ident then
- begin
- x := loc(level, id);
- if x = 0 then error(ernf);
- if tab[x].obj <> konstant then error(ertyp);
- c.tp := tab[x].typ;
- c.i := sign * tab[x].adr;
- insymbol
- end
- else if sy = intcon then
- begin
- c.tp := ints;
- c.i := sign * inum;
- insymbol
- end
- else error(erkey)
- end
- end;
-
- procedure typ(var tp: types; var rf, sz: integer);
- { Compilation of "subtype indication":
- Only allowed to equate to an existing type and
- to define a one dimensional array}
- var x: integer;
- eltp: types;
- elrf: integer;
- elsz, offset, t0, t1: integer;
-
- procedure arraytyp(var aref, arsz: integer);
- var eltp: types;
- low, high: conrec;
- elrf, elsz: integer;
- begin
- constant(low);
- if sy = colon then insymbol else error(erpun);
- constant(high);
- if high.tp <> low.tp then error(ertyp);
- enterarray(low.tp, low.i, high.i);
- aref := a;
- if sy = rparent then insymbol else error(erpun);
- if sy = ofsy then insymbol else error(erkey);
- typ(eltp, elrf, elsz);
- with atab[aref] do
- begin
- arsz := (high-low+1) * elsz;
- size := arsz;
- eltyp := eltp;
- elsize := elsz
- end
- end;
-
- begin (* typ *)
- tp := notyp;
- rf := 0;
- sz := 0;
- if sy in typebegsys then
- if sy = ident then
- begin
- x := loc(level, id);
- if x = 0 then error(ernf);
- with tab[x] do begin
- if obj <> type1 then error(ertyp);
- tp := typ;
- rf := ref;
- sz := adr;
- if tp = notyp then error(ertyp)
- end;
- insymbol
- end
- else if sy = arraysy then
- begin
- insymbol;
- if sy = lparent then insymbol else error(erpun);
- tp := arrays;
- arraytyp(rf, sz)
- end
- else error(erkey)
- end;
-
- procedure parameterlist;
- { Parameter list declarations:
- in parameter like Pascal value copy semantics
- out and in out parameter like Pascal var reference semantics }
- var tp: types;
- rf, x, t0: integer;
- valpar: boolean;
- begin
- insymbol;
- tp := notyp;
- rf := 0;
- while sy = ident do
- begin
- valpar := true;
- t0 := t;
- repeat
- enter(id, variable, level);
- insymbol;
- if sy = comma then insymbol
- until sy <> ident;
- if sy = colon then insymbol else error(erpun);
- if sy = insy then insymbol;
- if sy = outsy then
- begin valpar := false; insymbol end;
- if sy <> ident then error(erid);
- x := loc(level, id);
- insymbol;
- if x = 0 then error(ernf);
- with tab[x] do begin
- if obj <> type1 then error(ertyp);
- tp := typ;
- rf := ref;
- if valpar and (typ=arrays) then error(ertyp)
- end;
- while t0 < t do
- begin
- t0 := t0 + 1;
- with tab[t0] do
- begin
- typ := tp;
- ref := rf;
- normal := valpar;
- adr := dx;
- lev := level;
- dx := dx + 1
- end
- end;
- if sy <> rparent then
- if sy = semicolon then insymbol else error(erpun);
- end (* while *);
- if sy = rparent then insymbol else error(erpun)
- end;
-
- procedure typedeclaration;
- var tp: types;
- rf, sz, t1: integer;
- begin
- insymbol;
- enter(id, type1, level);
- t1 := t;
- insymbol;
- if sy = issy then insymbol else error(erpun);
- typ(tp, rf, sz);
- with tab[t1] do
- begin
- typ := tp;
- ref := rf;
- adr := sz
- end;
- if sy = semicolon then insymbol else error(erpun)
- end;
-
- procedure variabledeclaration;
- { Variable declaration:
- includes Ada constant declarations,
- initial values are noted in a special table which
- causes code to be emitted upon entry to the program }
- var t0, t1, rf, sz: integer;
- tp: types;
- c: conrec;
- cflag, initflag: boolean;
- begin
- while sy = ident do
- begin
- cflag := false;
- initflag := false;
- t0 := t;
- repeat
- enter(id, variable, level);
- insymbol;
- if sy = comma then insymbol
- until sy <> ident;
- if sy = colon then insymbol else error(erpun);
- if sy = constsy then { note that this is a constant }
- begin
- insymbol;
- cflag := true
- end;
- t1 := t;
- if sy = becomes then tp := ints
- else typ(tp, rf, sz);
- if sy = becomes then { either initial value or constant }
- begin
- insymbol;
- if (sy = ident) and (id = 'init ') then
- begin { special form for semaphore initialization }
- insymbol;
- if sy = lparent then insymbol else error(erpun);
- constant(c);
- if sy = rparent then insymbol else error(erpun)
- end
- else constant(c);
- initflag := true;
- if c.tp <> tp then error(ertyp)
- end;
- while t0 < t1 do
- begin
- t0 := t0 + 1;
- with tab[t0] do
- if cflag then { constant must be initialized }
- if not initflag then error(erkey)
- else begin
- typ := c.tp;
- adr := c.i;
- ref := 0;
- obj := konstant
- end
- else begin
- typ := tp;
- ref := rf;
- lev := level;
- adr := dx;
- normal := true;
- dx := dx + sz;
- if initflag then { store info on initialization }
- begin
- if c.tp <> typ then error(ertyp);
- inits := inits + 1;
- inittab[inits].addr := adr;
- inittab[inits].value := c.i
- end
- end
- end;
- if sy = semicolon then insymbol else error(erpun)
- end
- end;
-
- procedure procdeclaration;
- { Procedure declaration - also used for tasks }
- var istask: boolean;
- id1: alfa;
- begin
- istask := sy = tasksy;
- if sy = tasksy then { ignore task specification !! }
- repeat insymbol until sy = bodysy;
- insymbol;
- if sy <> ident then error(erid);
- id1 := id; { save name to check at end }
- if istask then enter(id, task, level)
- else enter(id, prozedure, level);
- if istask then curtask := t;
- tab[t].normal := true;
- if istask then { tasks must be elaborated }
- begin
- elabs := elabs + 1;
- elabtab[elabs] := loc(level, id)
- end;
- insymbol;
- block(level+1);
- if sy = ident then
- begin
- if id <> id1 then error(erkey);
- insymbol
- end;
- if sy = semicolon then insymbol else error(erpun);
- emit(32) (* exit *)
- end;
-
- procedure initouterblock;
- { Outermost block emits code for initializing global variables
- and elaborating tasks }
- var x: integer;
- begin
- for x := 1 to inits do
- begin
- emit2(0,1,inittab[x].addr); { load variable address }
- emit1(24,inittab[x].value); { load initial value }
- emit1(38,0) { store }
- end;
- if elabs <> 0 then
- begin
- emit(4); { cobegin from Pascal-S }
- for x := 1 to elabs do
- begin
- emit1(18, elabtab[x]); { markstack and call task }
- emit1(19, btab[tab[elabtab[x]].ref].psize-1)
- end;
- emit(5) { coend from Pascal-S }
- end
- end;
-
- begin (* block *)
- dx := 5;
- prt := t;
- if level > lmax then fatal(5);
- enterblock;
- display[level] := b;
- prb := b;
- tab[prt].typ := notyp;
- tab[prt].ref := prb;
- if (sy = lparent) and (level > 1) then parameterlist;
- btab[prb].lastpar := t;
- btab[prb].psize := dx;
- if sy = issy then insymbol else error(erpun);
- repeat { no predefined order in Ada }
- if sy = typesy then typedeclaration;
- if sy in [proceduresy, tasksy] then procdeclaration;
- if sy <> beginsy then variabledeclaration;
- if sy = pragmasy then { ignore pragmas }
- begin
- repeat insymbol until sy = semicolon;
- insymbol
- end;
- until sy = beginsy; { terminate upon begin of statement part }
- btab[prb].vsize := dx;
- tab[prt].adr := lc;
- if level = 1 then initouterblock;
- insymbol;
- statement(dx, level);
- while sy in [semicolon] + statbegsys do
- statement(dx, level);
- if sy = endsy then insymbol else error(erkey);
- btab[prb].vsize := dx;
- end;
-
- procedure initentries;
- { predefined symbol table entries }
- begin
- enterst(' ', variable, notyp, 0); (* sentinel *)
- enterst('false ', konstant, bools, 0);
- enterst('true ', konstant, bools, 1);
- enterst('character ', type1, chars, 1);
- enterst('boolean ', type1, bools, 1);
- enterst('integer ', type1, ints, 1);
- enterst('semaphore ', type1, ints, 1);
-
- enterst('get ', prozedure,notyp, 1);
- enterst('skip_line ', prozedure,notyp, 2);
- enterst('put ', prozedure,notyp, 3);
- enterst('new_line ', prozedure,notyp, 4);
- enterst('put_line ', prozedure,notyp, 4);
- enterst('wait ', prozedure,notyp, 5);
- enterst('signal ', prozedure,notyp, 6);
- enterst(' ', prozedure,notyp, 0);
- end;
-
- procedure initcompiler;
- begin
- inits := 0;
- elabs := 0;
- t := -1;
- a := 0;
- b := 1;
- display[0] := 1;
- with btab[1] do
- begin
- lastpar := 1;
- psize := 0;
- vsize := 0
- end;
- entries := 0;
- initutil;
- end;
-
- procedure compiler(var result: boolean);
- { Prompt for file name and then call compiler }
- var ok: boolean;
- ch: char;
- progname: alfa;
- begin
- write('Listing (y/n) ');
- readln(ch);
- listing := ch = 'y';
- {$I-}
- assign(inp, inputfile+'.ada');
- ok := ioresult = 0;
- reset(inp);
- ok := ok and (ioresult = 0);
- if listing then
- begin
- assign(list, inputfile+'.lis');
- ok := ioresult = 0;
- rewrite(list);
- ok := ok and (ioresult = 0);
- end;
- {$I+}
- if not ok then writeln('Can''t open') else
- begin
- initcompiler;
- insymbol;
- while sy <> proceduresy do insymbol;
- insymbol;
- if sy <> ident then error(erid);
- progname := id;
- insymbol;
-
- initentries;
- btab[1].last := t;
- block(1);
- if (sy = ident) and (id = progname) then insymbol;
- if sy <> semicolon then error(erpun);
- if btab[2].vsize > stmax-stkincr*pmax then error(erln);
- emit(31); (* halt *)
- if not eof(inp) then readln(inp);
- if listing then close(list);
- writeln('Compilation OK')
- end;
- result := ok
- end;
-
- end.