Anda di halaman 1dari 186

DUDLEY

NAVAL POSTGRADUATE SCHOOL


Monterey, California

THESIS
IMPLEMENTATION OF A COMPILER FOR THE
FUNCTIONAL PROGRAMMING LANGUAGE PHI -

(D

by

Eugene J. Cole
and
Joseph E. Connell II
June 1987

Th esis Advisor:

Daniel Davis

Approved for public release; distribution is unlimited

233190

UNCLASSIFIED
security ClaSS. fiCaTiQn Of Tm.S paGE

REPORT DOCUMENTATION PAGE


seport security classification

'a

RESTRICTIVE

'b

MARKINGS

Unclassified
SfCuR'TY classification authority

2a

Approved for public release;


Distribution is Unlimited

DtCASS FiCAT.QN DOWNGRADING SCHEDULE

2b

PERFORM. NG ORGANIZATION REPORT NuMBER(S)

NAME OF PERFORMING ORGANiZAT.ON

6a

6b OFF.CE

Naval Postgraduate School


ADDRESS Cry

and

Stare

8a

NAME OF FUNDING SPONSORING


ORGAN'ZAT ON

8c

ADDRESS (Cry

''

".

and

7a

NAME OF MONiTORiNG ORGANIZATION

Code 52

Naval Postgraduate School


ADDRESS

939^3-5000

State

(O'fy,

and

ZIP Code)

Monterey, California

8b OFFICE SYMBOL
(it apphcabie)

Sfare

SYMBOL

applicable)

ZIP Cod*)

Monterey, California

MON1TOR1NG ORGANIZATION REPORT NUM3P(S)

(if

6<

DISTRIBUTION/ AVAILABILITY OF REPORT

PROCUREMENT INSTRUMENT IDEN T.F NATION NUMBER

ZIP Cod*)

93943-5000

'0

SOURCE OF FUNDING NUMBERS

PROGRAM

PROJECT

TAS<

WORK

ELEMENT NO

NO

NO

ACCESSION NO

jNI

(include Security Classification)

IMPLEMENTATION OP A COMPILER FOR THE FUNCTIONAL PROGRAMMING


LANGUAGE PHI (u)
03

PERSONA L AuThOR(S)

!ole,
jj

Eugene J. and Connell, Joseph

-yP OF p.fpOR''

'ME COVERED
TQ
FROM

"(aster's Thesis
6

DATE OF REPORT

19 87

(Year

Month Day)

15

PAG

Dl-NT

1""

June

Supplementary no t at:qn

COSAT. CODES

group

E
14

3b

Su9-GR0UP

ASS-RjiC T {Continue on reverse

it

SUBJECT

ERMS \Contmue on

revert*

if

neceisary and identify by block number)

Functional Language; Applicative Languages;


Compiler Design

necessary and identify by bloxk number)

This thesis describes the design and implement


for the functional programming language PHI.
The
1 z e 1 a n d the authors
think this should facilitate
concept and implementation.
The front-end of the

of a prototy pe comrii er
design is hi ghly modu larthe understa nding of both
compiler imp lements

machine independent lexical and syntactic analyze s: too-down parsing


technics ues are employed.
The back-end implements a machine dependent ones e mantic analyzer and code generator,
p a s s
Sine e this implementation is a prototype, it d oes not posse ss all of
nualiti es desirable in a full implementation.
Th e basic contr ucts of F HI:
functio ns and data definitions are implemented, a s well as the integer,
na tural number, and boolean types.
However, the necessary hoo ks are
present and the design is mature enough to allow expanding the prototvn
to a fu 11 imclementation
I'TM/ON AVAILABILITY OF ABSTRACT
:0
21 ABSTRACT SECURITY CLASSiFiCA iON
SAME AS RPT
(Z. .NClASSiF'ED-'uNL'MITED
nclassif ied
D DTiC USERS
t

>a

NAME OF RESPONSIBLE NOiViOUAl

"rsf. Daniel Davis


DD FORM 1473, 84 mar

22b TELEPHONE (Include ArtaCod*)

(408
83

APR

edition -ray be used until ehauiTed


All

other

edt.om

are.

obsolete

646-309

22c

OFFICE

Code

SyMBO:
5

2~v

SECURITY CLASSIFICATION QF 'mS

WL

ur

Approved

for public release; distribution

is

unlimited.

Implementation of a Compiler for the


Functional Programming Language

PHI

by

Eugene

J.

Cole

Major, United States Marine Corps


B. A., The Citadel, 1975

and

Joseph E. Connell II
Captain, United States Marine Corps
B. S., University of Missouri
Rolla, 1974

Submitted in partial fulfillment of the


requirements for the degree of

MASTER OF SCIENCE

IN

COMPUTER SCIENCE

from the

NAVAL POSTGRADUATE SCHOOL


June 1987

ABSTRACT
This thesis describes the design and implement of a prototype compiler for the
functional

programming language PHI. The design

is

highly modularized and the authors

think this should facilitate the understanding of both concept and implementation.

The

front-end of the compiler implements machine independent lexical and syntactic analyzers;

top-down parsing techniques

employed.

are

The back-end implements

machine

dependent one-pass semantic analyzer and code generator.


Since this implementation

is

a prototype,

desirable in a full implementation.

it

does not possess

The basic constructs of PHI:

definitions are implemented, as well as the integer, natural number,

However, the necessary hooks


expanding the prototype

to a full

are present

and the design

implementation.

is

all

of the qualities

functions and data

and boolean types.

mature enough

to

allow

1$

TABLE OF CONTENTS
I.

II.

INTRODUCTION
A.

BACKGROUND GENERAL

B.

BACKGROUND THESIS

C.

BACKGROUND FUNCTIONAL PROGRAMMING

IV.

V.

Problems with Conventional Languages

2.

Functional

Languages

10

D.

ASSUMPTIONS

11

E.

CONSTRAINTS

12

FRONT-END OF THE COMPILER

B.

THE SCANNER
SYNTACTIC ANALYSIS THE PARSER

C.

ERROR HANDLING

A.

III.

LEXICAL ANALYSIS

BACK-END OF THE COMPILER

13
13
18

23
25

A.

OVERVIEW

25

B.

RUN-TIME ORGANIZATION

25

C.

SEMANTIC CHECKING AND CODE GENERATION

31

D.

OPTIMIZATION

40

RESULTS & CONCLUSIONS

42

A.

RESULTS

42

B.

CONCLUSIONS

43

FURTHER RESEARCH

LIST

OF REFERENCES

44

46

APPENDIX A THE FUNCTIONAL LANGUAGE PHI O

(concrete syntax

APPENDIX B THE FUNCTIONAL LANGUAGE PHI O

(concrete syntax of <D

of*

10/16/86

03/03/87

47

50

APPENDIX C ASCn REPRESENTATION OF PHI CD


APPENDIX D THE FUNCTIONAL LANGUAGE PHI O

APPENDIX E

APPENDIX F
APPENDIX G
APPENDIX H
APPENDLX

APPENDIX J
APPENDIX K
APPENDIX L
APPENDIX

53

(right recursive

HEADER FILES
ROCK COMPILER MAIN MODULE
ROCK COMPILER SCANNER
ROCK COMPILER PARSER
ROCK COMPILER ERROR HANDLER
ROCK COMPILER SEMANTIC CHECKER
ROCK COMPILER CODE GENERATION MODULE
ROCK COMPILER USER INTERFACE
ROCK COMPILER RUNTIME UTILITIES

54

grammar)

ROCK COMPILER

APPENDLX N TEST SUITE


APPENDIX O ROCK COMPILER
INITIAL DISTRIBUTION LIST

57
67
71

76

106
112
1

37

142
145
157

USER'S MANUAL

68

174

I.

A.

BACKGROUND
In

its

INTRODUCTION

GENERAL

attempt to provide students with a well rounded background to the field of

computer science, the computer science department

at the

Naval Postgraduate School offers

One of

courses covering recent developments in programming languages.


deals specifically with the methodology of functional, also

known

the courses

as applicative,

programming. Both the theory and the practice of functional programming are covered,
concentrating more on the practice than the theory. In order to fully appreciate the nuances

of functional programming

it

would be desirable

programming environment. This would provide

when programming

ference in methodologies

programming

Of

in traditional

a first

hand look

in functional

with a functional

fundamental

at the

languages as opposed

the languages currently supported in the department; LISP,

a functional language by some,

its

many

world of imperative prograinming.

this

requirement. Although

of functional programming.

It is

teach. [Ref. l:p.

Modem LISP

Most notably they lack

Dynamic scoping and

LISP

is

to

is

UNIX

considered
it

into

not a pure functional programming language.

dialects

do not support

all

to teach techniques

aspects of functional

the ability to define higher-order functions.

the semantics of the language

make

it

a pedagogical nightmare to

0-1] The goal of teaching functional programming would rapidly be

overtaken by the necessity of explaining the idiosyncrasies of LISP.

UNIX

on the

extensions and modifications actually brings

There are several additional problems associated with using LISP

programming.

dif-

imperative languages.

environment, comes the closest to meeting

the

to provide the students

a trademark of Bell Laboratories.

In an 11

week

quarter, time devoted to

LISP would

significantly detract

from instruction of functional

programming.

Recognizing the shortcomings of LISP, a pure functional language, PHI was


developed by Dr. B.

PHI

MacLennan

little

difficulty in learning

The syntax of

for use in this course of instruction.

means students should

closely follows that of standard mathematical notation. This

have

now

J.

how

to write legitimate

PHI

Instruction can

statements.

concentrate on joining these statements to create functional programs. Hopefully, this

and appreciation of the methodology of functional

will lead to a greater understanding

programming.

B.

BACKGROUND
Creation of

THESIS

PHI solved

the

problem of finding

a suitable language to use to

demonstrate the methodology of functional programming.

programs are programs on paper only. There

PHI language. So
to

remedy

the

environment

it is

exists

no programming environment for the

impossible to machine execute

above problem by providing the


a prototype

PHI

However, currently PHI

first

PHI programs. This


component

in a

PHI programming

compiler.

Conventional compiler construction techniques were chosen for

By choosing

for several reasons.

thesis attempts

this

implementation

conventional techniques, the authors were able to

address the problems associated with utilizing conventional methods for implementing a

compiler for a functional language 2

Additionally, realizing that both the language and

system would change, the authors wanted a well documented and understood
methodology.

The

cost of maintaining a system can be as

development cost [Ref.


that supported a clean

2:p.

478]. Therefore,

it

was imperative

much
to

choose a methodology

and structured design.

Specific problems and solutions are covered later in Chapters

as three times the

Two and Three

Following conventional methodologies, the authors separated the PHI compiler design
into a front-end 3

shown

in

Figure

and a back-end4

The

overall general design of the

The front-end, containing

1.1.

PHI compiler

is

the scanner (lexical analyzer) and parser

(syntactic analyzer) is essentially responsible for analysis of the external file containing the

source program.

The PHI compiler back-end couples semantic analysis with code

generation to produce code suitable for execution on the target machine. [Ref. 3:pp. 5-6]

The authors

felt that a

clear and distinct separation

between parts would aid understanding

of the system, simplify division of labor, and increase ease of development and
maintenance.

It

should also result in greater flexibility for follow-on development in the

PHI programming environment. As an example,


to support a

PHI

the current front-end could be modified

interpreter.

C abstract

user data

svntax tree

parsed

parse f tree

text file

prog

input) data

2.1

1.1

scanner- tokens

ascn

prog

parser-

'lexical

syntactic

v
analyzer

3.0
attrib'd

semantic

analyzer tree

code
generator

asm t

PC

file

analyzer

tokens

output

data

tokens \

results

tables

Figure

C.

BACKGROUND

FUNCTIONAL PROGRAMMING

Functional programming
applicative

functional

is

programming goes

programming

General Design of the PHI Compiler

1.1

traces

methodology

further back,
its

it is

roots to John

^Design and implementation of the front-end


Design and implementation of the back-end

in favor

among academicians. Although

generally agreed that, as a methodology,

Backus

[Ref. 4:p.

404, Ref.

is

discussed in Chapter Two.

is

discussed in Chapter Three.

5:p.

65].

In

ACM

speech for the 1977

his acceptance

Turing Award, Backus criticized traditional

programming languages and programming


methodology of programming

He went on

styles.

to

that involved "the use of a fixed set of

called functional forms." [Ref. 6:p. 619] This

methodology

is

propose a new

combining forms

known today

as functional

programming.

Problems with Conventional Languages

1.

Backus

feels [Ref. 6:pp.

conventional languages

is

613-619]

that the basic underlying

the existence of the assignment statement.

problem with

The assignment

statement plays a central role in conventional languages and breaks programming into two
worlds. Backus calls the right-hand side of assignment statements, expressions, the

of these worlds. The second world

is

the

first

world of statements, with the primary statement,

of course, being the assignment statement.


Several problems are associated with assignment statements.

programs

to be held hostage through access to their variables.

First,

they permit

Since variables are used to

imitate the machine's storage cells; assignment statements allow, even encourage, state

changes to take place. This access, either direct or


effects, unintentional state changes,

and aliasing

indirect, permits

to arise.

It

such problems as side

then becomes difficult to

reason about the correctness of these programs, so proving simple programs correct

arduous task and proving complex programs correct

by permitting the value of variables

to be

temporal order of execution of statements

is

virtually impossible.

is

an

Additionally,

changed, the assignment statement makes

critical.

For example, the following two pieces

of code produce dramatically different results depending on which statement inside the for
loop

is

executed
for
{

(i

first.

= 0;

!= some_value; ++i)

for

if(

2 == 0)

= 0;

i != some_value; ++i)
DoSomething(i);
if( i
2 == 0);

continue;

DoSomething(i);
}

(i

continue;
}

These problems

interact so that

old ones.

6:pp.

[Re'f.

613

it

becomes extremely
1-2

619, Ref. l:pp.

difficult to create

one-word

result.

programmers

In effect, they force

manner. For example, to apply a function

to

what Backus

2.

is this

refers to as the "von

programming languages.

[Ref. 6:pp.

is

that

each produces only

to think in a

word-at-a-time

an entire array of values, the programmer

must access each value individually. Not only


results in

out of

1-20]

Another problem associated with assignment statements


a

new programs

wasteful of computer assets, but

Neumann

it

bottleneck" of conventional

613-619]

Functional Languages

Backus proposes

methodology of functional programming

the

as the solution to

Functional languages have removed variables and the assignment

these problems.

statement from their syntax so that their basic building block becomes the function.

through "the use of a fixed


619] that the programmer

becomes possible

to

is

set

It is

of combining forms... plus simple definitions" [Ref. 6:p.

able to build

new

functions from existing functions.

It

thus

form a new program by combining two or more existing programs or

functions together.

The absence of assignment statements and variables removes


plaguing conventional languages caused by side effects,

etc.

the

program

is

to

practical to prove

view of the program.

It is

perform [Ref. 5:pp. 65

problems

because the program

operates exclusively in the world of expressions. This permits the


a clear conceptual

the

programmer

to

now

maintain

easier to understand and reason about the task


69].

It

programs correct [Ref.6:pp. 624

now becomes

not only possible, but

625].

Another direct benefit stemming from the absence of side

effects

is

order.

The

values of expressions are no longer dependent on the order in which they are evaluated.

Therefore, functional languages provide a natural means of performing parallel

computations [Ref. 7:p.

35].

Functional languages and the associated methodology of

10

functional
parallel

to

programming may very well provide

the

key

to

programming

the massively

computers entering service nowadays. All of the above benefits have applicability

ongoing research

in the

The authors
following thought

SDI program.
programming can

feel that functional

assignment statements

best be

are to functional

summarized by

programming what

the

GOTO

statements are to structured programming.

D.

ASSUMPTIONS
An IBM 5

target

its

personal computer/IBM compatible personal computer was chosen as the

machine for

this

implementation. The authors

felt that

the nature of the language and

intended use were better suited for the PC/personal work station environment as

opposed

to a

mini- or main-frame time shared environment. The

provide greater flexibility and freedom

programming language. Also,

when implementing follow-on

future compiler

improvements

will not

with extraneous interfaces to another system. Working with a


the

need

to take into

the system.

known

PC environment

PC

tools for the

PHI

have to be concerned

environment eliminates

account the effects the PHI environment will have on another user of

The implementor

is

able to

work with

a system that remains constant

quantity.

The assumed

target

machine configuration

is

based on the equipment available

Naval Postgraduate School's computer science microcomputer


configured with

640K

bytes of

1.2M byte 5 inch floppy disk


operates under the
to all

should

MS-DOS 6

IBM

MS-DOS

is

drive,

(most have two)

at the

is

20M byte hard disk drive, one

These machines

are readily available

Naval Postgraduate School, and many students own

a registered trademark of Internal Business Machines Corporation.

is

Each machine

and the 8087 math co-processor; each currently

3.x operating system.

computer science students

RAM, one

lab.

in the

a registered trademark of Microsoft Corporation.

11

personal computers with similar configurations.

when executing

E.

the

It is

not necessary to utilize a hard disk

PHI compiler.

CONSTRAINTS
As

is

the case with

most implementation

This involved making certain trade-offs;

constraint facing the authors.

major

effort be directed

particular

component of

was probably

theses, time

towards a

full

e.g.

the biggest

should the

implementation of PHI while concentrating on a

the compiler, or should the

major

effort

be directed towards a

full

implementation of the compiler while concentrating on a subset of the PHI language? The
benefit could be gained by implementing a complete compiler.

authors

felt that the greatest

Having

to actually face the issues

and interfacing a
about them in a

Since PHI

full

text.

and problems associated with designing, implementing,

compiler implementation would be

As

different than just reading

a result, this thesis implements only a subset 7 of PHI.

an experimental language

is

much

it

is still

undergoing changes and revisions.

Trying to modify and update the compiler design with each version proved to be an
impossibility.

stood on

07

The authors were forced

description of the

grammar

grammar may be found

Any follow-on work

January 1987.

back-end of the compiler

This subset

is

to freeze the design

need

to

as

implemented and a description of the

latest

Appendixes.

discussed in the individual chapters on the front-end and back-end.

12

it

update the front-end and

meet the requirements of these new versions of PHI.

to

in the

will

based on the language as

version of the

FRONT-END OF THE COMPILER

n.

The authors separated

the design of the

PHI compiler

into

and a back-end. These modules were then further subdivided


of Figure

1.1.

The authors

to

two modules, a front-end


produce the general layout

believe this modularization simplifies the design and will aid in

understanding the system, thus decreasing future maintenance problems.

The front-end of the PHI compiler

is

comprised of the scanner

(lexical analyzer), the

parser (syntactic analyzer), and their associated error recovery routines.


interactions

between the

lexical

Two

possible

The

and syntactic analyzers were considered.

first

incorporates the scanner into the parser, and tokens are produced by the scanner only upon

request of the syntactic analyzer.

method

is to

some data

Thus,

this

system acts

like a pipeline.

An

alternate

allow the scanner to tokenize the entire source program, store the tokens in

structure,

and pass

this structure to the parser.

[Ref. 3:p.

10]

For the prototype implementation of a PHI compiler, the authors based the design on
the first interaction.

Although the second method

the authors think the current implementation

enhancements.
this

Any

is

is

conceptually very easy to understand,

clean and will readily lend itself to future

input alphabet peculiarities are restricted to the lexical analyzer, and

independence should provide benefits for the next student(s)

who work on

the

PHI

programming environment.

A.

LEXICAL ANALYSIS
The PHI compiler reads

lexical analysis.

program
is

The

THE SCANNER

a source file of

ASCII

text

principle task of lexical analysis

which

is to

in the

PHI compiler through

13

fed to the scanner for

separate or divide the source

into tokens for use during syntactic analysis [Ref.8:p.

accomplished

is

84, Ref. 9:p.

155].

This

a character-by-character examination of the

These characters are assembled/grouped

user's source file.

which represent terminal symbols of


symbols are operators,
tokens

may

be found

identifiers,

in the

header

The primary advantage

the

PHI grammar. Examples of some of the

keywords, and constants.


file

into the individual tokens

for the scanner in

to tokenizing the source

complete

Appendix

program

is that

for handling white space and

Also, removing white space and


the tokens saves space.

the token [Ref.

comments. The scanner has already removed them.

comments and

Once tokenization

discarded and the compacted tokenized

file

utilizing a fixed-length representation for

is

complete, the source program can be

can be utilized for further analysis.

must be some discrete means

In order to correctly tokenize the source file there

available to accurately represent each token. There are several

One means

available

is to

use a regular grammar.

In this

given for producing the desired tokens" [Ref. 3:p.

method

the design of the

This simplifies the design of the parser because provisions do not have to be

7].

made

of the PHI

E.

syntactic analyzer needs to take into account only one type of data unit
3:p.

listing

terminal

is to

142].

ways of describing

method "generative

An

tokens.

rules are

equivalent, but different,

use finite-state acceptors, FSAs, to recognize tokens.

The authors found

it

easier to visualize this as a recognitive vice generative problem. For this reason the various

An example

tokens were modeled using FSAs.

shown

Figure

in

2.

The

interested reader

is

of an unsigned number recognizer

directed to

Tremblay and Sorenson

3:Chapter 4] for an excellent introduction to the practice of using

The authors found

that utilizing

of the lexical analyzer

The

ideal

identified.

one

FSAs

picture

to

was worth

hundred

the lexical analyzer started

Due

debugging

of code.

be uniquely and unambiguously

on the path of building a token,

able to continue until the end with no backtracking.

14

to

lines

[Ref.

model tokens.

greatiy simplified the design, coding, and

grammar would allow each token

Once

FSAs

is

it

would be

to limitations with the standard

digit

digit

digit

integer

f
\_J

\z^/
Figure

ASCII character

2. 1

PHI used multiple keystrokes,

represent various operators in the language 8

do double duty 9 by taking on

This resulted in

PHI overloads

Also, as in other programming languages,


to

((

compound token

neither of these two,

it

if

it

is

">"

-*) or another "-"

indicates that the token

is

the position this

is

basically a syntax analyzer

reason to complicate the scanner by handling

SUB_, and

SUB_

NEG_.

or

lets the

parser

make

it.

authors, following the

Some examples

^or example, +

and

The scanner just

for

its

to the lexical analyzer

= and <>

it

in the scanner!

true meaning,e.g.

worth noting. The

for *.

can serve as either an unary or binary arithmetic operator.

15

If the

identifies a generic token

example of Pascal, C, and other languages, took

of this are -> for

(--).

problem and there was no

the proper determination of

There are several design decisions relating

"-", the

just the simple token "-".

Distinguishing overloaded operators was solved by essentially ignoring

type, e.g.

them

easily handled through the

For example, upon finding the character

scanner looks ahead to the next character to see

The authors took

types.

different context-dependent meanings.

use of a single lookahead character.

is

or characters, to

certain operators, allowing

The problem of dealing with compound token types was

next character

^ ))

Unsigned Number Recognizer

the designer of

set,

digit

the position that

PHI's keywords 10 are reserved words and


Alternate decisions

would have been

68 do [Ref.

and the authors think

originally

It

certainly

keywords from

to distinguish

PHI has

that this decision

debugging of programs.
PHI's

91].

3:p.

not be redefined and used as identifiers.

them by some special character,

context, as PL/I does, or to precede

ALGOL

may

makes

made

easier for the

life

life

comment with

a special character.

only did

this simplify the

the

to explicitly indicate the

After scanning the special

would ignore

Comments

PHI's designer this implementation was changed.


:

The authors

programmer comments.

for

all

following

was once again found. Following conversations with

characters until the special character

Ada 11

and

easier for the authors.

character at the beginning of the comment, the lexical analyzer

are in

ALGOL 60

programmer by simplifying

implemented comments by requiring the programmer

same way they

as

a very small set of keywords, smaller than Cs,

grammar makes no provisions

beginning and end of each

based on

identifiers

comment

terminator

is

recognizer for comments, but

are

now implemented

the

Not

the end-of-line character.

also completely

it

removed

the

problem of runaway comments.

A name
table

was

table is used to point to the

names of

originally utilized but later discarded

makes analyzing an

all identifiers

when

instance of each

first

words, regardless of

how many

appears only once in the

11

PHI
The

abstract syntax tree easier than analyzing a flattened tree.

This permits just the

A complete

symbol

the authors realized the syntax of

information normally associated with a symbol table

10

and constants.

listing

name

rimes and in
table.

of PHI keywords

Ada is a trademark of the Ada


Government

name

Joint

is

now

to be placed into the

how many

may be found

16

in the

name

table.

scopes the identifier

The token returned

Programming

held in the nodes of the

to the parser

header

file for

would

the scanner in

is

tree.

In other

used,

indicate a

Appendix E.

Office, Department of Defense, United States

token type of identifier and the parser would then


the string containing the actual

know

to dereference the pointer to find

name, X.

Because keywords are reserved, each potential

identifier

against the possible keywords prior to being placed in the

implemented a keyword

shown

table to simplify this process.

that a binary search is the

For

lookup, which

worst 0(log

is at

efficient

way of

reason the keyword table

only comparisons.

this

most

n), is

Knuth

first

be compared

table.

The authors

must

name

[Ref. 10:pp.

406-4101 has

searching an ordered table, using

is

kept in alphabetical order. The

performed using a binary search of the keyword

table.

In an attempt to

a hash table.

improve the efficiency of the name

McKeeman

summing

253-301] experimented with

[Ref. ll:pp.

dependent hash functions. He found

that the function

the internal representation of the first

with

its

The

possibility of collisions

length shifted four places to the

However, since

this

is

implementation, each of the

name of the

it

six different length

producing the best results involved

last

characters of the variable's

reduced by choosing a prime number as the table

make

name

size.

provisions for handling collisions.

method of collision-resolution was chosen.

name

table slots/buckets holds a data structure that

variable and a pointer to another structure of the

hashed value points to a linked

list

of names.

same

In PHI's

can contain

type.

So each

This method offers the advantage of

providing better performance than linear probing [Ref. 12:p. 89],

is

conceptually easy to

visualize/work with, and also solves the problem of possibly overflowing the hash table.

does require slightly more


benefits of this

12:pp.

as

only reduces, not eliminates, the possibility of two or more names

variant of the chaining

both the

and

implemented

This was the function utilized by the authors.

left.

hashing to the same value; the authors had to

table, the authors

method

far

memory

to

It

implement, but the authors determined that the

outweighed the

slight increase in storage requirements.

83-93]

17

[Ref.

B.

SYNTACTIC ANALYSIS
The purpose of

THE PARSER
determine

the parser

is

twofold:

by the output from the scanner,

is

syntactically correct; 2) to

on the token stream,

fitting

it

1) to

into the abstract syntax tree

if

impose a hierarchical

which

[Ref. 8:pp. 7-8, Ref. 9:p. 7], Traditionally, these tasks are

bottom-up methodology

[Ref. 8:p.

41].

the program, as represented

is

structure

the output of the parser

done by either a top-down or

Both methodologies use the tokens generated

through lexical analysis.

The terminology top-down


constructed.

Top-down

symbols
the

at the leaves.

The parse

bottom by applying productions of the grammar

nonterminals.
at the

bottom

from

On

the other hand,

to the top

tree is constructed

bottom-up methodologies

The parse

by applying reductions of the grammar

generally agreed that the popularity of

start

it

BLOCKBODY, and work


because of

its

from

the top to

from

and

the terminal

tree is constructed

from

to generate single nonterminals

top-down parsing techniques

can be constructed more easily by hand". [Ref.

authors can attest to the fact that the concept of top-down parsing

parsing PHI,

downward

and nonterminals. [Ref. 8:pp. 40-41, Ref. 9:pp. 134-136]

fact that efficient parsers

When

tree are

to generate strings of terminals

leaves and proceed upwards to the root.

strings of terminals

It is

which the nodes of the parse

parsing starts from the root of the tree and proceeds

towards the terminal symbols


the

refers to the order in

is

natural to begin with the start

forward from there

to

is

8:p.

its

"due to the
41]

The

very easy to grasp.

symbol of the grammar,

analyze the token stream.

efficiency, but primarily because of

is

So, partially

ease of understanding and use, the

authors chose the top-down methodology of recursive-descent parsing to design and

implement

the syntactic analyzer.

In recursive-descent parsers, separate procedures/functions are written to recognize

each nonterminal of the grammar [Ref. 3:pp. 219-220]. This technique gets

name "because nonterminals can appear

18

in

its

distinctive

the right-hand sides of each other's

productions, the procedures for recognizing nonterminals are recursive."

To

state

it

more

recursively
itself,

if

clearly, the function to recognize nonterminal 'A'

either 1) 'A' appears

on

150]

[Ref.9:p.

could end up calling

itself

the right-hand side of the production describing 'A'

or 2) 'A' appears on the right-hand side of the production describing another

nonterminal

'B'

Regardless of

and

how one

with recursion.

appears on the right-hand side of the production describing

'B'

'A'.

looks at the nature of the technique, one usually identifies a stack

What made

able to use C's underlaying

this

technique so easy to implement was that the authors were

mechanism

for handling recursive functions.

The authors did

not have to explicitly maintain a stack of symbols for each function call; instead, the
information was implicit in the stack of activation records resulting from each function

Top-down

parsing techniques, especially recursive descent, offer straightforward

means of implementing

a syntactic analyzer.

However, these techniques are applicable

only to a subset of the context-free grammars and


eliminated from the

grammar

[Ref. 3:p.

productions describing nonterminal

'A'

211].

with

right-hand side of the production. Obviously,


to present the parser with strings to parse that

production applications" [Ref. 3:p.


production

it is

for

essential that

'A'

appearing as the

would cause

as

PHI

the

is

QUALEXP and would

PHI may be found

19

in

any

element on the

to enter "an infinite loop of

this type

never leave
In order to

PHI grammar

new grammar does

exist

would be possible

an example of

this

The PHI
of

string.

loop until the

employ top-down

to be right-recursive 12

not lend itself to "pure" recursive

descent parsing techniques.

12 The right
recursive syntax of

first

211], never to be heard from again.

the authors rewrote the

shown below, even

it

recursion be

must not

if this situation existed, it

machine ran out of memory stacking activation records.


parsing techniques with

all left

In other words, there

QUALEXP = QUALEXP WHERE AUXDEFS

The parser would hang up looking

However,

call.

Appendix

From

view the

the compiler writer's point of

ideal

grammar would allow

the correct

production rule to be applied in every step of the parsing process. Constructing the parse

would then proceed

tree

there are

two

in a

basic parser design

methods

for dealing with

this is not possible,

nondeterminism

151-152]. In the backtracking method, which

[Ref. 9:pp.

When

completely deterministic manner.

is

in the

grammar

generally not applicable to

recursive-descent techniques, the parser picks an arbitrary production and continues with
the parse [Ref. 9:p.

151].

production was chosen. However,


the last choice, a

parse

If the

new production

an error

if

is

successful

is

is later

is

it

assumed

that the correct

discovered, the parser backtracks to

chosen, and the parser presses forward again.

process continues until either the parse

is

This

successful or the parser runs out of possible

productions to chose from. The second method requires a modification to the grammar

which

results in a deterministic parser: the

factoring to avoid choices

For the most

grammar

among nonterminals

part, the

design of PHI

is

rewritten using a process called

[Ref. 9:p.

is

151].

conducive

to recursive descent parsing

techniques. There are, however, several productions where this


that a

this

not so. The result was

problem through a combination of left factoring and the employment of a simple


all

is

problem

at

When

13

had

to be used.

is

tn the other.

not an LL(1) grammar

These solutions were used because they solved the

hand.

two token look-ahead was used for

parsed.

PHI

not to say that the authors are absolutely certain that

or that backtracking

single

but the two productions described below.

one case a two token look-ahead was employed and backtracking was used

This

].

is

degree of nondeterminism arose in the parser design. The authors attempted to solve

token look-ahead. This solution worked for


In

left

the token

The

first

'['

is

found, a flag

look-ahead token

is

the production 13

is set

utilized

to indicate that

when

A complete description of the PHI grammar may be


20

ARGBINDING =

parsing the

found

in the

an

QUALEXP OP

ARGBINDING

is

being

QUALEXP part. QUALEXP,

Appendices

may

for example,

FACTOR*TERM.

MULOP,

*, to

TERM, which

parse as

FACTOR,

After succeeding on

see

if

in turn

as

QUALEXP was

called

from ARGBINDING, argbinding

in the

ARGBINDING production and

QUALEXP production

the

ARGBINDING production

is

TERM

employed

is

should be

not called from

sentential

and

TERM

not part of the


is

is

allowed

to

is

ACTUAL = DENOTATION = FORMALS

DENOTATION when
first

the

was

']'

If

make

is

this

found

l->

ACTUAL: ACTUAL =

ACTUAL. Legitimate PHI

FORMALS = ( FORMALS" ")


1

are proper subsets

COMPOUND = ( ELEMENTS
identifiers

may

),

excluding

appear between the

not practical during the parse to utilize look-ahead to determine the

presence of the token "|->".

apply

it

proceed to completion.

empty compound statement. Since any number of


it

If

terminated, e.g., term does not recursively call itself again, and

forms produced by the production

parentheses,

This

initiated.

production. In order to

utilized to look for the token

of the sentential forms produced by the production


the

or

to look for the

ARGBINDING.

Backtracking was utilized when parsing productions of

COMPOUND

FACTOR

flag set, the operator * could be the trailing operator

determination, an additional look-ahead


the

parse as either

a look-ahead

a recursive search for another

methodology works as long

may

it

In effect, the parser first realizes

finds "|->".

found, the parser then backtracks 14 to the

FORMALS

this choice.

production.

associated with backtracking were not evident in this isolated case.

space trade-offs had previously been

was simply passed

The root

to the

14
A purist would say
employ a recursive-descent

was parsing

made and

the parser

If "|->" is later

The normal

costs

As described below,

was already working with an

to the subtree containing the previously parsed

FORMALS

This problem was solved by designing the parser to

compound production when presented with

abstract syntax tree.

it

compound

production to insure that the string could have been

that this instance of backtracking

parser.

21

means

that the

PHI compiler does not

in fact

produced by FORMALS. After ascertaining FORMALS, the parser now continues the parse
using the

DENOTATION

production.

The production QUALEXP = QUALEXP

WHERE AUXDEFS

pure recursive descent parsing. The semantics of


(e.g.,

an identifier)

may

be used prior to

major problem for the compiler

its

the identifier since the inner-most scope, in the


the parser then

works

its

way

to the

production are such that a terminal

definition.

However,

writer.

this

required a deviation from

In itself, this does not present a

this construct also

changes the scope of

form of the QUALEXP,

is

parsed

and

first

outer-most scopes, the AUXDEFS. This problem

is

analogous to that of mutual recursion in Pascal, without the benefit of the forward
declaration [Ref. 4:p. 213].

Originally, the parser

was designed

essentially a post-order

walk of the

management

However,

routines.

tree.

to output the parse tree in flattened form,

This design implemented traditional symbol-table

after obtaining a clearer understanding of the semantics

involved with the problems mentioned earlier, notably the production

QUALEXP =

QUALEXP WHERE AUXDEFS,

would be too

Management of the

inefficient.

unwieldy

the authors realized a traditional symbol-table

to

work

with.

table

would take an inordinate amount of assets and be too

The authors solved

this

problem by maintaining the

parse in an abstract syntax tree so the output from the parser

now

status of the

in tree form.

This

permits information originally held in the symbol-table to be maintained in the tree

itself.

The parser

is

able to analyze the source program by walking the tree and decorating the

nodes with required information. Maintaining a binary


space, but this

is

insignificant

when compared with

Interestingly, maintaining the parse in tree

The

is

tree in

memory does

trivial

because

form presented several additional

appropriate subroot and rewalking the

was now simply

it

tree.

more

the benefits.

solution to the aforementioned problem of distinguishing between

DENOTATION became

require

benefits.

COMPOUND

and

a matter of returning to the

Also, working with a binary tree permitted the

22

.
.

modicum of

authors to perform a

optimization in the parser.

straightforward to perform compaction on an actual

The authors think

PHI

becomes

maximum

potential for future

One

possibility

would be

interpreter.

relatively

tree.

that this design offers

of the PHI programming environment.


drive a

It

Modularization of the front-end

enhancements

to use this

in this

front-end to

manner

simplifies

functional understanding of the front-end and should lead to increased ease of maintenance

and

portability.

executed

it

on a

To demonstrate

portability, the authors

68000 based processor.

the source program, just replacement of

recompiled the front-end and

This was accomplished with no modifications

C run-time

header

files for the

new

to

target machine.

ERROR HANDLING

C.

Tremblay and Sorenson


I.

Incorrect responses (error not reported)


a.

b.
c.

2.

Compiler crashes
Compiler loops indefinitely
Compiler continues, producing incorrect object program

Correct (but nearly useless)


a.

Compiler reports

first

error

and then

halts

Acceptable responses
1

Possible responses
a.

b.

2.

Compiler reports error and recovers, continuing to find later errors if they exist
Compiler reports the error and repairs it, continuing the translation and producing a
valid object program

Impossible with current techniques


a.

Compiler corrects error and produces an object program which


what the programmer intended to write

In the prototype

recovery.

PHI compiler,

The primary

11]

the authors have

benefit of error recovery

program as long as possible before


3:p.

183] classify error responses into three categories:

Unacceptable responses
1

II.

[Ref. 3:p.

This allows the

is to

the translation of

implemented a limited form of error


"prolong the compilation

the compiler gives up

maximum number

is

life

of the

on the source program".

[Ref.

errors to be discovered per compilation,

shortening the edit, compile, debug cycle inherent to writing computer programs.

The authors analyzed

the intended environment

and use of the PHI compiler and

decided that lexical analysis and syntactic analysis were the most likely source of errors.

23

Lexical errors basically involve invalid characters or incorrect tokens.

Common examples

of these types of errors are unrecognized words, misspelled identifiers/keywords, or illegal


characters. Syntactic errors relate to incorrect structure of the program.

when
the

the

programmer

program

One

is

failed to follow the rules, productions, of the

wrong. [Ref. 9:p. 226, Ref.

arise

grammar. The form of

185]

3:p.

thing the error handler should not do

These errors

is

exacerbate the situation by reporting

bogus errors or executing an erroneous program. To insure erroneous programs are not
executed, the authors inhibited object

file

production

if

any errors were discovered. The

authors do not believe the compiler should allow code generation to continue, or even
begin,

if

the source

program has

errors being reported

and

attempted to minimize

this is

errors.

extremely annoying to the programmer.

this situation, but

because some errors feed on others.

overwhelmed with
Also, for
codes.

found

To

it

The authors

impossible to eliminate completely

insure the

programmer would not become

error messages, the authors terminate the compilation after

programmer convenience,

The authors saw no

message served much

programming

Often times one error leads to an avalanche of

actual error

errors.

messages are outputted instead of error

justification in using a cryptic

better.

10

code when a plain language

Since the authors anticipate students in functional

classes to be primary users of the

basis in the productions describing the

PHI compiler,

PHI language.

compiler have an understanding of PHI's syntax.

24

It is

error

assumed

messages have

their

that users of the

PHI

III.

A.

BACK-END OF THE COMPILER

OVERVIEW
The back-end of

the compiler consists of the semantic checker

Semantic checking and code generation are completed


sequence of bytes, held

in

memory, which correspond

characters are then written to a text

This output

file,

one pass, and the output


to

ASCII

which the assembler uses

linked to the appropriate run-time routines to

is

the current implementation, a

B.

in

and code generator.

to output

make

RASM86 assembler and LINK86 15

characters.

is

These

an object

file.

a usable program. For

linker are used.

RUN-TIME ORGANIZATION
Since

PHI

is

a structured language with scoping and function calls,

stack-oriented run-time architecture. The stack

is set

up

to

it

lends itself to a

accomplish two

tasks:

1) to

hold pointers to the current operands, and 2) to hold activation records for functions
currentiy in use. Both of these tasks are described below.

There

is

limitation is

and the

64 kilobytes

imposed because

maximum

variables,

offset is

on memory used while a program

limit

the

memory

64K.

and constants (see Figure

3.1).

component. Because PHI

is

operation, and a pointer to this value

The

is

competed

stack

placed

heap allocation method

currently implemented use only one


15

RASM86 and LINK86 are

for

by the stack, current

grows from the top of

a functional language, a value is returned


is

This

this

space

the base of this space up, preventing wastage by

at the top

placed in the lowest available space in the part of


constants.

running.

addressed as an offset from a base address,

This space

down, and the variable space grows from


either

is

is

is

of the stack. The returned value

memory

word of memory, and

trademarks of Digital Research, Inc.

is

assigned to variables and

not currently used because

25

from each

2) there is

1) all

data types

no fragmentation of

memory because

all

types are currently

pointer to the second operand

two topmost

The

pointers.

new operands.

If the

is

If the

next operation

is

a binary operation, a

placed on the stack, and the operation takes place using the

result

placed in memory, and the process begins afresh with

is

next operation

to the stack takes place

static.

is

and the variable

unary (such as the negation operation), no change


in

memory

is altered

as the

program

directs.

Address

64Kb

-4-

^^>

Stack

TOS

Values
(Variables and

Constants)

Kb

Figure 3.1
Organization

Memory
If the

f(x)"),

second operand of an operation

an activation record

is

Then, the activation record

is

function result

saved and placed

is

be the result of a function call

placed on top of the pointer to the

function's value

calculated.

is to

at the

top of the stack.

26

is

first

(e.g.,

"2 *

operand and the

deleted and a pointer to the

Static

Link

Static Nesting

Level

Pointer to Value Space

Figure 3.2
Activation Record

The

activation record itself, Figure 3.2, contains three parts: the static link, the static

nesting level, and a pointer to the address in

The

stored.

static link is

one-word pointer which points

of the previous activation record, and


activation record,
to the

is

The

a static chain. [Ref. 4:p. 77].

i.e.

the function's first variable

is

to the static nesting level space

used to traverse the stack from activation record


static

to

nesting level and the pointer

base of the storage space for a scope's values are used to access variables and

constants. In this design, a two-tuple (B, L)


tuple,

memory where

is

associated with each variable. In this two-

represents the static nesting level and

following the

is

chain for (current nesting level

static

the offset within that level.


-

By

target nesting level) links, the

activation record of the scope of the target value can be accessed. Then, the address of the

variable

is

calculated by adding

method would have been


activation records.

to the

low address of

the scope's variables.

to store the values directly in the stack

However,

this is a

An

alternate

between or within

messy process when dealing with dynamic data

structures such as sequences. Additionally,

it

is

conceptually easier to divide the stack and

the variables.

Functions are implemented as calls to assembly language subroutines, with pointers


the arguments placed

the fact that

PHI cannot have

straightforward.

and pointers to

on the stack before calling the

Whenever

its

side effects,

a function

is

called,

its

routine.

Using

this

scheme, and noting

the implementation of recursion


activation record

is

is

placed on the stack

arguments are placed on top of the activation record.

27

to

If the

function

is

recursive, the assembly language subroutine simply calls itself until the base of

recursion

is

reached or

until stack

series of activation records called

overflow

its

reached. Figure 3.3 shows an example of a

is

by a program with a recursive function. Note

that the

data definition ("answer") has no arguments and simply calls the factorial function. The
factorial function,

on the other hand, has an argument and

operand. So, a pointer to that value

is

placed on the stack.

is

uses that argument as an

put on the stack and the next operand, fac (n

When

put on the stack as an activation record.


return value

it

fac (n

1) is

1), is

evaluated, a pointer to

its

This cycle of evaluation, pop activation record,

evaluation will continue until the data definition "answer"

is

evaluated.

Address

64000

64000

^
?
J

Base of
Value Space

Answer
Activation Record

(no actuals)

61998
1

Fac
1

(5)

^Activation Record

Ptr to Actual

Ptr to 5

63997
2

Fac (4)
3

Activation Record

Ptr to Actual
:

Ptr to 4

63992
Fac

J,

J
Kb
answer where answer
fac(n)

==

if

==

where

fac(5)

then

(3)

Activation Record

else n * fac(n-l)

endif

Figure 3.3
Factorial

As an example of
PHI program fragment

the

is

Program and Activation Records

code generated for function

used

(n)

==

if

n =

28

then

calls

else

(n

and recursion, the following


-

1) *

n endif.

This, of course, simply calculates the factorial of the integer n.


listing

of the assembly language segment which

is

Figure 3.4

is

the

which returns

the

generated from this fragment.

Assembly Language

Address/Machine Code

0150 jmpalOOOO

0103E94A00

alOOOl:
mov cx,0

0106 B90000
0109 E80000

call

Lformal

mov

010C B80000
010FE80000
0112E80000
0115E80000
0118 3D0100

E
E
E
0126

01 IB 7509

011DB80100
E

0120 E80000
0123 E92600

ax,0

call iputvalue

calliequ
call igetvalue
cmp ax,l
jne al0003
mov ax,l
call iputvalue

014C jmp al0002


al0003:
cx,0

mov

0126 B90000
0129 E80000

call

Lformal

mov

012CB90000

012F E80000

call

mov

0132B80100
0135E80OOO
0138E80OOO
013BE80OOO
013E51
013F57
0140BB0100

cx,0

Lformal
ax,l

E
E
E

call iputvalue

0143 E80000
0146 E8BDFF
0149 E80000

call

call imult

014C E80000

call

call isub

ppop
push ex
push di

call

mov
i

bx,

mov

0106 callalOOOl
al0002:
del_scope

014FC3

ret

alOOOO:
Figure 3.4

Assembly Language Output from Factoral Program

The
factorial.

If the

label

"alOOOl"

When

it is

subroutine

label a 10003.

memory,

is

at

address 0103

is

the label of the subroutine

called, pointers to the values of the

arguments are placed on the

called before the base of the recursion

Then, the new actual value (n

a pointer to the value

is

1) is

is

reached, a

jump

is

stack.

made

to

calculated and placed in the low part of

pu^ on the stack, and the values are prepared for calling

29

by the next subroutine

(lines

0126

to 0143).

The

factorial subroutine is then called again.

This process continues until the base of the recursion


integer value

is

put

at the

is

reached; in this case a pointer to the

top of the stack (line 01 ID), and a jump

Here, the subroutine "del_scope" tears

down

the activation record

pointer to the result of the function at the top of the stack.

program can be implemented by

is

made

to label a 10002.

on the stack and puts a

Clearly, recursion in the

PHI

a parallel recursion in the assembly language output of the

compiler.

Another feature of the output code shown

jump around
inline

code

the function (lines

in spite

and time penalties

jump and

in

Figure 3.4

0103 and 014F). This

is

of the fact that functions can be called


to be paid for these

label instruction bracketing

to get to the label at the

is that

there

is

an unconditional

a result of the decision to output


at

random. There are both space

jumps, especially since each function must have a

However,

it.

bottom of the program. The

the ultimate effect of all these


result is that all but

could be eliminated by an optimizer, making the penalty

jumps

is

one jump/label pair

Another solution

trivial.

considered was to generate code for functions and the "main" program separately, then

combine

the

two when printing

the output

from the code generator. This was not done

for

reasons put forth in the section that describes the semantic analyzer.

Variable and constant storage

is

word oriented

advantage of the 8086 processor's 16

rather than byte oriented to take

bit capability.

Integers and naturals are both

represented as single words, and booleans are represented as integers, either


this

boolean representation

is

somewhat wasteful

in

terms of

memory

space,

great deal of overlapping in certain subroutines used in function calling


It is

planned to represent

linked

lists.

real

it

or 0. While

allows for a

and comparisons.

numbers with two words of memory, and sequences using

Neither of these types have been fully implemented; however, there are

provisions in the compiler for adding these features at a later date.

30

There

is

currently no

dynamic allocation of

specific purposes; for instance, the SI register is used to

and of course the

BP and SP registers

are used to

arithmetic processes take place in the

When

auxiliaries as needed.

allocated and,

when

AX

variable space

a function

is

is

Some

registers.

mark

manage

registers are used for

the top of the

program

stack,

the machine's stack. In general,

register, using other general registers as

needed, the highest unused address space

is

finished, only the result is saved in storage; all other value

spaces are returned for use by the program.


Error handling

is

probably the simplest part of the run-time routines.

Any

run time

error such as overflow or division by zero errors will result in an appropriate error
to the user (see
will terminate

C.

Appendix

and control

O for a full listing


is

name of

the node.

and the process

is

and

CODE GENERATION

utilizes the recursive descent technique to

checking and code generation


are filtered through the

of error messages). Then, program execution

returned to the operating system.

SEMANTIC CHECKING
The PHI compiler

message

in

one traversal of the parser

semcheck

function,

These procedures,

which

in turn, call

In

tree.

calls various

semcheck

perform semantic

most cases,

tree

nodes

procedures based on the

for each of their children,

repeated until the leaves of the tree are reached. The function semcheck

then returns a type

(e.g., integer, real,

the semantic correctness of

its

subtree.

function, the parent procedure can

boolean), which the parent node uses to determine

With

do one of

the information returned

from

the

semcheck

three things: return a type, convert one node

to a different type, or declare an error condition.

Concurrent with semantic checking, code

assembly language code written


however, a flag

is set

to a buffer in

is

generated.

memory.

If

As noted above,

an error condition

is

this is

declared,

and code generation ends. Semantic checking will then continue

until

the tree is completely traversed or ten errors are accumulated; then, the semantic checking

31

process terminates.

Unlike the parser, the semantic checker makes no attempt

at error

recovery; top-down checking simply continues normally from where the error was
detected.

Top-down semantic checking


compiler. Unfortunately, there are

For instance, determining

solve.

results in a neat, trim

some problems
if

actuals for a given function involves

there

is

package for the back end of the

that pure

top-down checking

will not

one-toone match between formals and

some detours from top-down checking,

as explained

below.

The scoping
checker.
the

One

number of

item

is

the

rules of

solution
its

is

PHI provided

the largest challenge to writing the semantic

a multiplicity of stacks.

The

constituents visible at any one time.

one found closest

to the top of the stack.

size of these stacks

depends upon

Usually, the proper match for an

However, because of

the "and" construct, checks against the variable-stack

the semantics of

do not always follow

this

convention.

There are four stacks used by the semantic checker: the type- stack, the variable-stack,
the definition-stack,

lists.

and the and-stack. All but the type-stack are implemented as linked

This implementation sheds the disadvantage of

slight increase in

array of

300

memory and

static

length arrays at the cost of a

temporal resources. The type-stack uses a fixed-length

entries because 1) the basic types of real, boolean, integer, natural,

will be accessed

most frequently, because they

and

trivial

are the building blocks of every type

and

sequence, and because they can be more easily accessed from an array than from a linked
list,

and

2) a

list

3) the

type-stack

of

300 type entries should not impose

an extreme burden on the programmer,

planned implementation of sequences will be more straightforward


is

an array.

32

if

the

# of Bytes

Type Name

Link

to

Next Type

Figure 3.5

Type-Stack Entry

The type-stack, Figure

3.5, is

meant

to

hold both the basic type definitions and user

defined type definitions. This stack holds both the

name of

the type

and the number of

bytes needed in

memory

five basic types

and user defined types are added as they are encountered. The begin-end

to

implement the type. At compiler

initialization,

it

contains the

construct of the language (not implemented yet) allows declared types to be visible over a
specified range.
the stack

It is

planned to implement

upon encountering

the begin

this construct

by

setting a pointer to the top of

node and then popping the stack

to that point after

both of the node's subtrees have been checked.

Variable Type

Node

Formal Flag

Link to Next Entry

Pointer

Figure 3.6
Variable-Stack Entry

The

variable-stack, Figure 3.6, holds

currently seen by the semantic checker.

all

of the variables, including function names,

Each entry holds a pointer

containing labels, a type, a pointer to the tree node defining

whether or not

it is

a formal.

Whenever a

variable

a call to a function and not a data definition,

scope

is

it

is

name

and a flag

encountered and the name

dropped from the

of its formals are popped from the stack.

33

to designate

put into the variable stack. Then,

exited, the variables local to that scope are

after a function is defined, all

is

it,

to the hash table

stack.

is

not

when

For example,

Definition

Formals

Type

Tree Node Pointer

Pointer

Link

to

Next Entry

Figure 3.7
Definitions Stack Entry

The

definitions-stack, Figure 3.7, contains

visible in a given scope; e.g., the declaration


into the definition-stack. This entry

a pointer to the tree

node

argument types (Real and


definition. This stack

This

grows and shrinks

The authors considered combining

in this

way.

However,

SR

this

$Z

and a pointer

in the

->

to a linked list

be null

same way

if

which contains

the declaration

is

its

a data

as the type stack.

the definitions-stack
fact,

SB would put the definition C

the type of C's return value (Boolean),

last field will

of the similarity between their fields. In

designed

of the function and variable definitions

would contain

that contains C,

Integer).

all

and the variable-stack because

one of the primitive implementations was

slowed down the search for both definitions and

variables considerably, and the overhead needed to implement these two as separate stacks
is

small: three extra functions

The need

and one extra pointer.

for the and-stack

is

derived from the scoping rules imposed by the

construct. This construct allows a variable to be referenced before

benefit of Pascal's forward declaration or equivalent.

PHI such
a

way

as the

that the

subtree of the

WHERE

construct.

However, the

semantic checker can see

AND

all

AND

This

is

it

is

declared without the

true of other constructs in

construct cannot be parsed in such

variables before they are used, because either

statement can define variables used by the other subtree. So, a program

such as the one depicted in Figure 3.8 needs a vehicle by which


variable

is

AND

defined later in the program. The and-stack

34

is

it

can detect

such a vehicle.

that the

k^^

Where

==

c(l)

Auxand

*Datauxdef

Funauxdef

c(n)

^-t\^
d

c (1)

where c

(n) == =

n * d

andd = =

Figure 3.8
Tree With Forward Variables

When

the semantic checker reaches the

indicate that

and-stack.

AUXAND

"Notfound"

reached, but, since the

Note

that

is later

is

returned from the

AND

semcheck

condition has been

AUXAND

checked against variables

removed from

node, Figure 3.8, a flag

has been traversed, and a pointer

defined in a data definition

and right subtrees of

AUXAND

set,

function

a pointer to

(DATAUXDEF

have been checked,

in the variable-stack.

the and-stack.

is set to

all

If a

set.

The semantic checker would recognize

and-stack would not be equal to the mark placed

node was entered. Nested


top of the and-stack

is

AUXANDS

marked when

is

is

auxand node

35

is

when both

found, d

is

the left

is

when

defined and
the

AUXAND

(UNDEFINED VARIABLE)

this condition

at the

the variable

put in the and-stack.

not found

because the top of the

top of the stack

are possible, but they pose

the

is

entry of the

variables in the and-stack are

node's complete subtree has been checked, an error condition

would be

when

node), and

match

In the event that a variable

the top

is set to

traversed.

when

the

AUXAND

no problem because

the

'

Variables and functions are represented in the run-time by a call to an assembly

language subroutine, and each subroutine must have a discrete name.


several labels found throughout the program, and each of these

names

are generated

by the "name" function found

in the

Also, there are

must have a name. These

sem_u.c module. Each name

begins with the letter "a", followed by 6 digits. Examples can be seen in Figure 3.4.

Funauxdef

Funid

uf^

Formal

Comma

/
y

f (x,y)

==

x * y

Figure 3. 9
Tree for Function

Function definitions presented a problem that was solved with a deviation from pure

top-down semantic checking. When

a function definition

(FUNAUXDEF

in

Figure 3.9)

is

encountered by semantic checker, the following procedure would be followed (see Figure

3.10 for the function definition

entry):

funid node:

check for definition-stack entry for "f


if not found
return

(ERROR)

get a pointer to the

first

formal of

get a pointer to the

first

formal of definitions-stack entry

while both pointers

<>

Nil do

36

'

'

'

put variable in varstack; use type pointed to by the formal

list

advance both pointers


end while loop
if

not (both pointers

==

nil)

(FORMALS MISMATCH)

return
else

put "f

'

end

in the

variable-stack

(Type of

return

= INTEGER)

else

end.

fnnaiixrief node:

left

type

= semcheck (Left Child)


= semcheck (Right Child)

right type

if (left

type

<>

call a

right type)

procedure which will either

convert the right type to the

left

type or set an error flag.

endif
end.

When

a function

called with arguments,

is

a similar process takes place (refer to

Figure 3.11):
actualist

Input

is

a pointer to the actualist node

Output

Check
if

is

error condition

definitions-stack for "f

"f not found


'

set error

(FUNCTION DEFINITION NOT FOUND)


element of element

set elistptr to first

list

elist (elistptr)

check var stack for "f


if

found,

if

not found

generate code to call "f

ifand_flag

TRUE

put "f in the and stack


'

else
set error

(FUNCTION NOT DEFINED)

end.

elist

Input

if

is

a pointer to the element

pointer->rptr

<>

list

node

nil

elist (pointer->rptr)

check type of element against corresponding formal type


if types don't match
set error

(IMPROPER ARGUMENT TYPE)

37

else

generate code to put pointers to argument values on the run-time stack


end.

Integer

$Z

\ Formal
/Types

$z

Figure 3.10
Definitions-Table Entry For Function f

Type conversions
does not yet support

found

in the

are

implemented

this feature.

module semO)

will

in the

semantic checker, albeit the code generator

The function hnumconvert

check

to see if a

(half number-convert,

conversion of the right subtree of a node

to the left subtree type should be accomplished.

This

where the body of the function may be converted

to the type the function returns, but the

converse

module)

is

not acceptable.

In addition, the function

is

useful for function definitions,

numconvert (found

in the

will convert either the left tree type or the right tree type of a node. This

for certain arithmetic operations.

The semantic checker considers

is

semO
useful

integer-to-real and

natural-to-real conversions to be legal. Natural to integer conversions are not implicitly

done, since both of these types are represented in exactly the same way.

On

the other

hand, an attempt to return an integer value for a function which has a declared type of
natural will result in an error.

38

Actualist

Actualist

Elementlist

Comma

f (1,2)

Figure 3.11
Tree for Function Call
Variables of simple type

although such a declaration

(i.e,

may

natural, integer, or real)

be made.

need not be declared before use,

If a variable is

undeclared when defined by a

data definition, the semantic checker will attempt to classify


expects to find a boolean value, the variable

is

AND

it

as an integer; failing this,

it

construct alters this somewhat.

definition,

it

will

As noted

in the section

is

semantic checker

and an entry

is

expected, the semantic checker will try

be classified as a real number. However, the

If a variable is

must have been defined using

If the

easily classified as a boolean

put into the variable table. If a numeric variable


to type

it.

the

used before

LETDEF

it is

defined by a data

construct.

on run-time, some thought was given

to

generating

all

functions and data definitions to one buffer and the "main" program which calls these
functions to another buffer. However, this

would be an

39

inefficient use of

memory

space,

since one buffer might run out of space while the other
a proliferation of

eliminate

D.

jump

but one

all

calls in the output using

call,

is

under-utilized. Although there

is

one buffer, an optimizer could easily

as noted above.

OPTIMIZATION
There

no optimization module implemented

is

attempt will be

made

PHI

in the

compiler. In this section an

to identify three types of optimization

which are suitable for

implementation. Also, a small dissertation on what optimizations should not be considered


is

included.

The
folding

first suitable

type of optimization

to

function.

implement
It

constant folding.

The purpose of constant

eliminate multiple consecutive constants in arithmetic expressions [Ref 3:p.

is to

612], and the function

which

is

numconvert

this optimization.

would be straightforward

of an operand node to see

if

module semO makes an excellent

This

is

structure in

because most arithmetic operations

to put a function that tests the left

and

call this

right children

they are constants, then perform the operation in the compiler

and generate code for a constant

numconvert,

in

call.

However, since

the constant folding function

the division operators

would have

do not

to be inserted in idiv

call

and rdiv

also.

The other two optimizations


considered

is

jump

jump

definitions

is n,

> 0,

there will be n

one

if

the

unnecessary

statements and labels.

These jump statements can be eliminated by replacing the

jump

first

optimization. This should be the most worthwhile to implement:

number of functions and data


unconditional

The

are post-code generation optimizations.

to the last label in the code; then,

because "jmp"

circumnavigate functions and data definitions,

can be eliminated.

40

all

is

first

"jmp" statement with a

not used for anything except to

other unconditional

jumps and

their labels

The

last

type of optimization

will be a "call

is

form of peephole optimization. Occasionally, there

ppush" statement followed by a

"call

ppop" statement. This

is

unnecessary,

and can be eliminated. The 8086 assembly code equivalent of "push" followed by "pop"
should not occur in the present design.

Dead code optimization eliminates code


labels.

It is

inside a

jump when

that

code contains no

not necessary to implement this type of optimization with the current design,

since unconditional

one accepts the

jumps

are only used to bracket functions

and definitions. However,

premise that programmers occasionally make mistakes,

it

if

might be

worthwhile to keep track of which functions are called and eliminate code for those which
are not.

message

to the

programmer concerning

41

this

circumstance would be useful, too.

IV.

A.

RESULTS & CONCLUSIONS

RESULTS
The implementation described

in

study demonstrates the design and

this

implementation of a compiler for the functional programming language PHI. Since

this

implementation

full

implementation.

enough

to allow

a prototype,

is

However,

it

does not possess

of the qualities desirable in a

hooks are present and the design

the necessary

expanding the prototype

all

This implementation

is

mature

to a full implementation.

The PHI compiler front-end implements machine independent


analyzers.

is

lexical

and syntactic

complete and faithfully follows the syntax of PHI

based on the design of the language as of

07

January 1987. In deciding which modules to

include in the front-end and back-end, the authors were originally guided by the traditional

methodology of placing the analysis functions


the

back-end [Ref.

8:p.

in the front-end

and generative functions

in

20]. However, as the design of the PHI compiler progressed, the

authors removed semantic analysis from the front-end and combined

it

with code

generation. This produced a one-pass semantic analysis/code generation phase.

The PHI compiler back-end implements


analyzer and Intel

8086 code

machine dependent one-pass semantic

The semantic analyzer implements

generator.

constructs of PHI: functions and data definitions

number, real number, and boolean types are


generation

is

fully

may

the basic

be defined, and the integer, natural

implemented. Implementation of code

congruent to that of the semantic analyzer, with the exception that the real

number data type has not been implemented.

42

B.

CONCLUSIONS
It is

possible, using traditional technologies to design and

functional

programming language PHI.

It is

implement a compiler

for the

not possible to utilize either pure recursive

descent or pure deterministic techniques for this implementation. The syntax/semantics of


the language forced a degree of non-determinism,

PHI compiler

required in the

The

overall design

is

front-end.

highly modularized facilitating the understanding of concept and

implementation. The authors think that

and provide greater


environment.

It

thesis to drive a

and one instance of back-tracking was

this

approach will greatly reduce maintenance costs

making changes and additions

flexibility in

to the

PHI programming

should be possible, for example, to use the front-end described

PHI

interpreter.

without change should

make

Being able

to abstract out this front-end

the implementation of a

PHI

in this

and use

it

interpreter relatively simple.

Modularizing the design also increases portability of the compiler to other machines. To
demonstrate portability, the authors recompiled the front-end and executed

based processor. This was accomplished with no modifications


replacement of

Removing

C run-time

header

files for the

the semantic analyzer

analysis with code generation.

from

new

target

it

to the source

on a

program, just

machine.

the front-end permitted coupling semantic

The fixed-length buffer design of

the code generator

suitable for this prototype implementation but should be redesigned utilizing

buffer allocation methods in follow on implementations.


single pass through the parse tree
this

methodology

is

is

The authors

suitable for future designs of the

PHI

compiler.

is

dynamic

think that utilizing a

practical for the basic constructs of

43

68000

PHI and

believe

FURTHER RESEARCH

V.

Further research

may

be broken

The former may be

projects.

down

into

further broken

two major

down

short

into

areas:

two main

and long range


areas:

adding

On

the other

unimplemented features and improving the PHI programming environment.


hand,

all

long-range projects involve only the programming environment.

All of these

areas are discussed below.


In the prototype of the

unimplemented.

PHI compiler, both Real and Compound

Compound

variable types remain

variable types consist of sequences, the Trivial type, user

defined types, and tuples. Although

all

of these are recognized by the parser, the semantic

checker will not recognize complex types and no code will be generated. The Real type
recognized by the semantic checker, which can discern
natural type should be accomplished; however,
in the

no code

if

is

is

conversion from an integer or

generated to implement this type

run-time structures. Note also that operators which operate solely on complex types

and reals

One

(e.g., the real

divide and concatenate operators) are not implemented.

other operator not implemented

bindings, functionals, and

FILEs

is

the "l->" operator.

are not recognized

In addition,

argument

by either the semantic checker or the

code generator.
Short-range improvements to the PHI environment

implementation

is

is

just

enough

to

know

that the

be improved by implementing the interactive

mode.

is

system

would be

good

is

running!

mode of PHI,

starting point

44

full

analogous to instrumentation on a

sample interactive session of PHI may be found

interpreter

either after a full

accomplished or may be developed concurrently with the

implementation. Admittedly, the current environment


helicopter: there

may come

as

The environment could

opposed

to the current batch

in [Ref. l:pp

1-17].

Also, an

toward developing a practical, working

environment for PHI. As noted above, the front end of the prototype compiler
adapted for

this

purpose; alternatively, due to the structual similarities between

LISP, an ambitious researcher

One
to

final short-range

allow more than

64K

of the large amount of

may wish

to write

improvement which

of run-time memory.

When
become

the

PHI compiler becomes

viable.

is

be

PHI and

an interpreter in LISP.

is

It

not covered by either category would be

would be worthwhile

memory most modern microcomputers

sequences and recursion, upon which PHI

may

based, gobbles up

a serious user's tool,

to take

advantage

have, especially since

memory

with abandon.

some long-range research

will

Sophisticated input and output would be a vital consideration, and the

minimal I/O methods now


ambitious researchers in

in use

would need

this direction

possibility of a syntax-directed editor.

PHI programming,

a debugger

substantial improvement.

The most

should consider a bit-mapped display with the


Also, based on the authors' limited experience in

would be a necessary

45

tool for the serious

programmer.

LIST OF
1.

REFERENCES

MacLennan, B. J., Functional Programming Methodology: Practice and Theory, to


be published by Addison-Wesley, 1987.

IEEE

2.

Horowitz, E. and Munson, J. B., "An Expansive View of Reusable Software,"


Transactions on Software Engineering, vol. SE-10, No. 5, September 1985.

3.

Tremblay,

4.

MacLennan, B. J., Principles of Programming Languages: Design, Evaluation, and


Implementation, Holt, Rinehart and Winston, 1983.

5.

Bellot, P.,

J. and Sorenson, P. G., The Theory and Practice of Compiler Writing,


McGraw-Hill Book Company, 1985.

"High Order Programming in Extended FP," in Lecture Notes in


vol. 201: "Functional Programming Languages and Computer
Architecture," edited by Jean-Pierre Jouannaud, Springer- Verlag, Berlin Heidelberg,

Computer Science,
1985.
6.

Backus, J., "Can Programming Be Liberated from the von Neumann Style? A
Functional Style and its Algebra of Programs," Communications of the ACM, vol.
21, No. 8, August 1978.

7.

Clark, C. and Peyton Jones, S. L., "Strictness Analysis


a Practical Approach," in
Lecture Notes in Computer Science, vol. 201: "Functional Programming Languages
and Computer Architecture," edited by Jean-Pierre Jouannaud, Springer-Verlag,
Berlin Heidelberg, 1985.

8.

Aho, A. V., Sethi, R., Ullman, J. D., Compilers Principles, Techniques, and Tools,
Addison-Wesley Publishing Company, 1986.

9.

Calingaert, P., Assemblers, Compilers,

and Program Translation, Computer Science

Press, 1979.
E., Sorting and Searching, The Art of Programming, Vol.
Addison-Wesley Publishing Company, 1973.

10.

Knuth, D.

11.

McKeeman, W. M., "Compiler Construction: An Advanced Course," in Lecture


Notes in Computer Science, edited by Goos and Hartmanis, Springer-Verlag, New
York, 1974.

12.

Horowitz, E. and Sahni,


Science Press, 1978.

S.,

3,

Fundamentals of Computer Algorithms, Computer

46

APPENDIX A
THE FUNCTIONAL LANGUAGE PHI
(CONCRETE SYNTAX OF O 10/16/86

Grammatical Notation:

mean

Both '{Ci,C2,...,C n }' and

Similarly, '[Ci

...

Cn

mean

and

]'

exactly one of Ci, C2,...,

at

most one of

Cn

C n The
.

,/-.*.

notation 'C

means zero or more Cs; 'C + means one or more Cs; 'CD ...' means a list of one or more
Cs separated by Ds. Terminal symbols are quoted when they could be confused with
'

metasymbols.

Grammar:
BLOCKBODY

QUALEXP
LET DEFS

BLOCKBODY

FORMALS = QUALEXP
TYPEEXP
TYPE ID [FORMALS] = TYPEEXP
[ID]

ID

DEF

QUALEXP

EXPRESSION

QUALEXP WHERE AUXDEFS

AUXDEFS

AUXDEF AND...

AUXDEF

[ID]

FORMALS

FORMALS

ID

EXPRESSION
1

FORMALS,

...

V] CONJUNCTION

EXPRESSION

[EXPRESSION

CONJUNCTION

[CONJUNCTION A] NEGATION

47

RELATION

NEGATION

RELATION

[SIMPLEXP RELATOR] SIMPLEXP

RELATOR

[=l*l>l<l<l>lele]

SIMPLEXP

[SIMPLEXEP ADDOP]

ADDOP

TERM

[TERM MULOP] FACTOR

MULOP

FACTOR

II

TERM

A
:

primary

APPLICATION

PRIMARY

APPUCATION

PRIMARY

nT TT mn
APPUCATION
,

[APPUCATION] ACTUAL

ID

DENOTATION
CONDITIONAL

COMPOUND

ACTUAL

ARGBINDING

BLOCK
^ FILE

'

CHAR +

'CHAR
DENOTATION

DIGIT+

'

[.

DIGIT +

FORMALS
ARM

'

|->

ACTUAL
[ELSE EXPRESSION] ENDIF

CONDITIONAL

IF

ARM

EXPRESSION THEN EXPRESSION

COMPOUND

'{'ELEMENTS

ELEMENTS

<

ELEMENTS

[QUALEXP,

ARGBINDING

'['<

OP

BLOCK

...

ELEMENTS)

f(
{

ELSIF

]
'}'

>

\
J

...]

OP
OP QUALEXP
QUALEXP OP

RELATOR

>

']'

ADDOP

BEGIN BLOCKBODY END

48

MULOP

DEFS

DEF AND

TYPEEXP

TYPEDOM

TYPEDOM

TYPETERM + TYPEDOM

TYPETERM

TYPEFAC X TYPETERM

...

->

TYPEPRIMARY
TYPEPRIMARY
ID << TYPEEXP,

TYPEFAC

ID

(TYPEEXP

SESSION

COMMAND

is

>>

considered a

DEF
QUALEXP

1
J

TYPE

BLOCKBODY;

COMMAND+

>
)

RIZIN

For batch use, a program


SESSION:

PRIMTYPE

TYPEPRIMARY

PRIMTYPE

TYPEEXP

'

49

for interactive use

it is

considered a

APPENDIX B
THE FUNCTIONAL LANGUAGE PHI
(CONCRETE SYNTAX OF O 03/03/87

Grammatical Notation:
Ci
mean

Both '{Ci,C2,...,C n }' and


I

Cn

exactly one of Ci, C2,..,

Cn

Ci
Similarly, '[Cl

...

C n and

mt2J\ at most one of

]'

LC n

i,...,

C n The
.

i/-.*!
'

notation 'C

means zero or more Cs; 'C + means one or more Cs; 'CD
means a list of one or more
Cs separated by Ds. Terminal symbols are quoted when they could be confused with
.'

'

metasymbols.

Grammar:
BLOCKBODY

QUALEXP
LET DEFS

QUALEXP

[REC]

...

EXPRESSION

I QUALEXP

WHERE AUXDEFS

AUXDEFS

AUXDEF AND...

AUXDEF

[ID]

FORMALS

TYPEEXP (BE
TYPE ID [FORMALS]
[ID,

DEF

BLOCKBODY

FORMALS

EXPRESSION

(ID
I

FOR MALS,

...

V] CONJUNCTION

EXPRESSION

[EXPRESSION

CONJUNCTION

[CONJUNCTION A] NEGATION

50

IS

}]

[ID]

TYPEEXP

FORMALS

QUALEXP

""

RELATION

NEGATION

RELATION

[SIMPLEXP RELATOR] SIMPLEXP

RELATOR

(=|*l>l<l<l>

SIMPLEXP

[SIMPLEXEP ADDOP]

ADDOP

TERM

[TERM MULOP] FACTOR

MULOP

(X

FACTOR

[:] PRIMARY

PRIMARY

J
I

T)

X}

APPLICATION

PRIMARY

APPUCATION

APPLICATION

TERM

[APPUCATION] ACTUAL

TYPEEXP,
DENOTATION
CONDITIONAL

ID [

...

COMPOUND

ACTUAL

ARGBINDING

BLOCK
{

FILE

'CHAR
DIGIT+
DENOTATION

STREAM

CHAR +

}'

'

[.

DIGIT+

NIL

^FORMALS
ARM ELSIF

ACTUAL

|->

[ELSE EXPRESSION] ENDIF

CONDITIONAL

IF

ARM

EXPRESSION THEN EXPRESSION

...

ELEMENTS
(ELEMENTS

']'

'['

COMPOUND

'{'ELEMENTS
<

ELEMENTS

ELEMENTS

[EXPRESSION,

ARGBINDING

'['

'}'

>

...]

rop
<
I

OP

OP ACTUAL
ACTUAL OP

RELATOR

>

']'

ADDOP

51

MULOP

SUB

BLOCK

BEGIN BLOCKBODY END

DEFS

DEF AND

TYPEEXP

TYPEDOM

TYPEDOM

TYPETERM + TYPEDOM

TYPETERM

TYPEFAC X TYPETERM

...

-> TYPEEXP

I TYPEPRIMARY
f

TYPEPRIMARY

<
I

PRIMTYPE

COMMAND

"

TYPEEXP,
PRIMTYPE

ID

ACTUAL
...

R
is

considered a

LET DEF
QUALEXP

>

TYPE

BLOCKBODY;

COMMAND+

(TYPEEXP)

For batch use, a program


SESSION:
SESSION

TYPEPRIMARY*

TYPEFAC

'

52

for interactive use

it is

considered a

APPENDIX C
ASCII REPRESENTATION OF

Reference

ASCII

==

<

LESS

<

<=

>

>=

<>

IN

NOTIN

-s-

->
A

|->

Ai

A!i

T*

T@

R
Z

$R

$N

$B

$1

$Z

53

-O

APPENDIX D
THE FUNCTIONAL LANGUAGE
RIGHT-RECURSIVE GRAMMAR
(

Note:

means zero or more occurrences

(...)

(-)

means one

more occurrences

or

means from zero to n occurrences


(...)
(xly) means either x or y, but not both

BLOCK

::=

BEGIN BLOCKBODY END

BLOCKBODY

::=

LET DEFS; BLOCKBODY


QUALEXP

DEFS

::=

DEF (AND DEFS)*

DEF

::= (ID)

ID

FORMALS a QUALEXP

TYPEEXP

TYPE

ID

(FORMALS) a TYPEEXP
1

QUALEXP

::=

EXPRESSION (WHERE AUXDEFS)*

AUXDEFS

::=

AUXDEF (AND AUXDEF)*

AUXDEF

::= (ID)

FORMALS

::=

FORMALS a EXPRESSION

FORMALS (NORMALS)*

ID

EXPRESSION

::=

CONJUNCTION

CONJUNCTION

::=

NEGATION(

NEGATION

::= (-)

RELATION

::=

CONJUNCTION)

NEGATION)

RELATION

SIMPLEXEP (RELATOR SIMPLEXP)

54

RELATOR

;;=

=
*

LESS

GREATER
<
>
e

SIMPLEXP

::=

TERM(ADE

ADDOP

::=

TERM

:=

FACTOR (MULOP FACTOR)

MULOP

+ PRIMARY

FACTOR

PRIMARY
PRIMARY
-

PRIMARY

APPLICATION

(ACTUAL)

APPLICATION

ACTUAL

(!

APPLICATION)

ID

DENOTATION
CONDITIONAL

COMPOUND
ARGBINDING

BLOCK
FILE '(CHAR)

DENOTATION

:=

'(CHAR)
(DiGrr) +
(DiGrr) +

'

:=

Note

Note

CHAR

can = ASCII 32

...

ASCII 126

CHAR

can = ASCII 32

...

ASCII 126

Note: DIGIT can =


.

FORMALS
ID

(DIGIT) +
|-

ACTUAL

ALF (ALFNUM)*

Note

ALF can =

ALFNUM

ARM

...

a...z,
a...z,

A...Z

A...Z, 0...9, _

ARM) (ELSE EXPRESSION) ENDIF

CONDITIONAL

IF

ARM

EXPRESSION THEN EXPRESSION

(ELSIF

can =

55

COMPOUND

::=

(ELEMENTS)

(ELEMENTS)

)
1

}
1

< (ELEMENTS) >

ELEMENTS

::=

QUALEXP(,QUALEXP)*

ARGBINDING

::=

[
[
[

op

OP QUALEXP
QUALEXP OP

]
]

OP

RELATOR
ADDOP

MULOP
t

TYPEEXP

::=

TYPEDOM

TYPEDOM

::=

TYPETERM

(+

TYPETERM

::=

TYPEFAC

TYPEFAC

::=

TYPEPRIMARY
TYPEPRIMARY
ID

TYPEPRIMARY

::=

TYPEDOM)*

TYPETERM)*

TYPEFAC)*

TYPEEXP

(,TYPEEXP)*

(TYPEEXP)
ID

PRIMTYPE
PRIMTYPE

::=K
7L

N
IB

TYPE

FOR INTERACTIVE IMPLEMENTATION OF


SESSION

::=

(COMMAND)"*"

COMMAND

::=

(DEF

QUALEXP)

56

APPENDIX E

ROCK COMPILER HEADER

FILES

/A****************************************************************
*
THIS FILE CONTAINS HEADER FILES REQUIRED BY THE ROCK COMPILER
***********************************************************************/
*

/***********************************************************************
*
PUBLIC DOMAIN SOFTWARE

scanner definitions
Name
scanner h
File
* Authors
Ma j E.J. COLE / Capt J.E. CONNELL
* Started
10/10/86
* Archived
12/11/86
* Modified
01/10/87 - Update keywords
JC
*********** ************* ************************************************
* This file contains def initions used by the scanner, parser,
*
and
*
* error rec overy routine s
*********** ************* r****************** *****************************
* Modified
01/10/87 Corrections to comply with latest definitions *
*
*
of the 1 anguage and update keywords. JC
*********** ************************************************************ /
*
*

#ifndef

EOF

define EOF_
define FALSE

-2

tdefine TRUE
1
#define BYTENUM
2
define MAX_KEYWORDS 17
define NAMESIZE
18
define MAXLINE
80
107
define TABLESIZE

/*

0-17
'

/*

hash const/size of name array

/* General Token
Types */
Listing of symbols can be found at end of list

define EOLN_
define LEQ_
define NEQ_

3
4

def ine ST_SEQUENCE_

define GEQ_

fdef ine END_SEQUENCE_

define
define
define
define
define
define
define
define

/* system dependent - sizeof(int)


/* really 18, ranges from
\0
/* length of str, 16 chars +

EQ_
ADD_
SUB_
MULT_
IDIV_
RDIV
SEMI_
SUBSCRIPT

10
11
12

13
14
15

16

57

*/

'

*/
*/

*/
'/

define COMMA_

17

define LTPAREN_
define RTPAREN_
EQUIV_
ORLOG_
ANDLOG_
NEGLOG_
COLON_
CAT_
LTBRAKET_
RTBRAKET_
LTSQUIG_
RTSQUIG_
EMPT_LIT_
RTARROW_
LINERTARROW_
LITERAL_
IDENTIFIER_
CONSTANT_
REAL_
INTEGER_
NATURAL_
BOOLEAN_
TRIVIAL_
CHAR_
STRING_
STAR_
POS_
NEG_
KW_

#define
#define
#define
#define

define
define
define
#define
#define
#define

define
define
define
define
define
define
define
define
define
define
define
define
define
define
define
define
define

error,

/* eof,
,,

(,

18

),

==,

19
20
21
22
23
24

25
26
2 7

28
29
30
31
32
33
34

35

36
37

38

39
40
41
42
43
44

45
/* KEYWORD

4 6

unknown token, <=, <>,

\//

A,

~,

:,

A
,

[,

],

{,

<,
\,

>=,

",

>,

=,

->,

+,

identifier, constant, $R, $Z, $N, $B,$1, character,


unary plus, unary minus, keyword
/*

define
define
define
define
define
define
define
define
define
define
define
define
define
define
define
define
define
define

AND_
BEGIN_
ELSE_
ELSIF_
END_
ENDIF_
FILE_
GREATER
IF_
IN

LESS_
LET_
NOTIN_
READ_
THEN_
TYPE_
WHERE_
WRITE

Keywords */

1
2
3
4

6
7

10
11
12
13
14
15
16
17

58

-,

*,

%,

literal,
string, @,

l->,

/,

#define
struct

CALLOC(y,x)
NStruct

((x*)

calloc

(y,

sizeof

(x)

/*

/*

char
struct NStruct

name[NAMESIZE]
*link;

};

NameRec;
typedef struct NStruct
char
*cailoc();
extern
char
*inaloc(| ;
extern
#endif

59

structure to hold names from


user prog

*/
*/

'**********************************************************************
PUBLIC DOMAIN SOFTWARE
parser definitions
Name
parser .h
File
Maj E.J. COLE / Capt J.E. CONNELL
Authors
Started
10/20/86
Archived
12/11/86
01/12/87 - update NodeStruct definition JC
Modified
A******************************************************
*
* This file contains definitions used by the parser
a********************************************************************
* Modified
01/10/87 - update NodeStruct to hold the type of the *
*
*
node
a*********************************************************************/
:

#ifndef

LETDEF

#def ine
#def ine
#def ine
#def ine
#def ine
#def ine
#def ine
#def ine

#def ine
#def ine
#def ine
#def ine
#def ine
#def ine
#def ine
#def ine
#def ine
#def ine
#def ine
#def ine
#def ine
#def ine

LETDEF
DEFAND
KINDEF
FUN ID
FUNDEF
DATADEF
TDEFID
TDEFFUN
DATAAUXDEF
FUNAUXDEF
AUXAND
ACTUALLIST
SEQUENCE
FORMAL
ELLIST
EMPTYCOMPOUND
EMPTYSEQUENCE
ARGBINDOP
ARGLEADOP
ARGTRAILOP
TYPEPLUS
TYPETIMES
TYPEEXPLIST

#def ine
#def ine
#def ine
#def ine

LEFT
RIGHT
ERROR_
BUFSIZE

typedef

int NodeType;

#define

71
72
73
74

75
76
77
78
79
80
81
82
83
84
85
88
89
90
91
92
93
94
95
1
2

-1

512

/*
/*
/*
/*
/*
/*
/*
/*
/*
/*

struct NodeStruct
name;
NodeType
long
index;
type;
int

*/
operator node in tree
*/
int defined as the operator
pointer to constant literal, id */
*/
the type of the node
*/
line no in source text where
*/
token can be found
*/
Label used by functions to
*/
refer to code
*/
Addr of the var or function
value in the run time's virtual*/
*/
/* memory

int

In;

char

label

long

addr;

[8];

60

struct
struct

;;
)

NodeStruct
NodeStruct

/* left ptr
/* right ptr

*lptr;
*rptr;

};

typedef

struct NodeStruct NodeRec,

NodeRec
char

*CreateNode
*NodeName
(

/* global var-list number errors


/* during scan and parse
/* global flag - used to make PHI
/* deterministic

num_errors;
argbind;

extern int
extern int

extern
extern
extern
extern

*nodal;

/* def used from <stdlibs.h>

char *calloc()
char *malloc()

ErrorHandler
WriteErrors ()

/***************** External Utility Functions *****************/


extern
extern
extern
extern
extern
extern
extern

NodeRec *CreateNode
char
*NodeName();
MakeNewRoot

IsFormalO;
IBall ()
EatEm
long ByPass();
(

#include <scanner.h>

include <errors.h>
#endif

61

*/
*/

*/
*/

'

'

**********************************************************************
PUBLIC DOMAIN SOFTWARE
error file definitions
Name
erors h
File
* Authors
COLE / Capt J.E.
J.E
Maj
E
Mai E.J.
* Started
01/20/87
* Archived
04/07/87
* Modified
***********************************************************************
*
* This file contains definitions used by the error recovery routines.
***********************************************************************
*
* Modified
********************************************************************** /

*
*

ifndef

MAXERRORS

#define MAXERRORS

10

/*********************** PARSER ERRORS *******************************/

#def ine
#def ine
#def ine
#def ine
#def ine

ERRO
ERR1
ERR2
ERR3
ERR4
ERR5
ERR6
ERR7
ERR8

define

ERR9

#def ine
#def ine
#def ine

define

|-' w/o '>


/*
*/
or
/* RESERVED FOR FUTURE USE
*/
/* '\' w/o '/'
bad logical OR */
/* '$' w/o proper following char
*/
/* invalid numeric constant
*/
/* literal w/o ending
*/
/* unidentified char in input file*/
/* out of memory
*/
/* error in statement following
*/
/* 'xx'
*/
/* error in type definition
*/
/* following
*/
xx
'

'

'

2
3
4

5
6
7

'

25

/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*

#def ine

ERR_a

10

#define

ERR_b

11

12

define
define
define
define

ERR_c
ERR_d
ERR_e
ERR_f
ERR_g
ERR_h
ERR_i

define
define

ERR_j
ERR_k

19
20

define

ERR_1

21

define

ERR_m

22

define
define
define

ERR_n
ERR_o
ERR_p

23
24

#def ine

define
#def ine

13
14

15

16
17
18

define

ERR q

26

define

ERR

27

/*
r

/*
/*

62

unable to complete eval of


the blockbody
missing or misplaced
after

*/
*/
*/

definition
invalid QualExp
invalid TypeExp
bad or missing formals
missing or misplaced
missing ID after 'TYPE'
bad definition after AND
missing or bad AuxDef after
WHERE
missing or misplaced
error in processing
successive Actuals
missing literal after keyword
FILE"
missing or invalid exp after
keyword ==>
IF statement w/o ENDIF
error in formals preceding ->
missing or invalid QualExp
following comma op
error in ArgBinding - check
QualExp or
off in OZONE-unimplemented
feature

*/
*/

'

*/
*V
*/
*/
*/
*/

*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/

#def ine
#def ine
#def ine
#def ine
#def ine
#def ine
#def ine
#def ine

31

/*
/*
/*
/*

32

/*

32,

/*

ERR_ s
ERR_ _t
ERR_ u
ERR V
ERR_ w
ERR_ X
ERR_ y

28

ERR

35

29
30

/*
/*

34

/* NOTE:

through

reserved for future use

*/

/A********************* SEMANTIC ERRORS ******************************/


define
#def ine

define
#def ine
#def ine

define
define
define
define
define
define
define
define

ERR_ aa
ERR_ hb
ERR_ cc
ERR_ _dd
ERR_ ee
ERR_ "ff
ERR_ .99
ERR_ _hh
ERR_ ii
ERR_ _jj
ERR_ _kk
ERR_ ]ll
ERR_ mm
~-

/*
/*

35
35
35

/*
/*

35
35

/*
/*
/*
/*
/*
/*
/*
/*

35
35
35
35
35
35

35
35

/*

endif

63

Numeric value expected


Natural expected
Integer or natural expected
Error in Tuple Definition
Undefined var in "and" scope
Function w/o function def
Formals mismatch
Undefined function
Real Number expected
Invalid Constant
Boolean value Expected
Boolean Operator Expected
Out of run-time memory space

*/
*/
*/
*/
*/
*/
*/
*/
*/

*/
*/
*/

*/

/************* *********************************************************
*
PUBLIC DOMAIN SOFTWARE

*
*

*
Semantic Definitions Header File
Name
*
Semcheck.h
File
* Authors
*
Maj E.J. COLE / Capt J.E. CONNELL
* Started
01/01/87
*
* Archived
04/10/87
*
* Modified
"FILENAME" eliminated EC
04/13/87
************** *********************************************************
* This file co ntains the header file and definitions for the semantic *
*
* checker and code generator of the PHI compiler
************** *********************************************************
* Modified
*
04/13/87
"FILENAME" eliminated; output path now
*
depends on user's input EC
**********************************************************************
*

/****************************** Externals ****************************/


include
include
include
include

<scanner.h>
<parser.h>
<errors.h>
<stdio.h>

/******************************* Globals ******************************/


define
define
define
define
define
define
define
define
define
define

/* Definition for findvar


/* Type Definitions and sizes

NOTFOUND
UNTYPED
BOOLEAN 1
BOL_BYTES 2
REAL 2
REAL_BYTES 4
INTEGER 3
INT_BYTES 2
NATURAL 4
NAT BYTES 2

define ERROR
define MAXADDR 64000

/* Max

define MAXTYPES 300


define CODE_SIZE 20000
define
START_ADDR
define
TYPE_INIT 5

/* Max
of types in one scope
/* Max size of code buffer
/* Starting address for varspace
/* Pointer to the last initial

define
CNTRL_Z
2 6
define
ENDSTRING
define NUM_BASE 4 8
define STACKSIZE 10000
define SIZEBUFFER 30000

/*
/*
/*
/*
/*
/*

define
define
define
define

define SEM ERR

typetable entry
Control Z ascii
String terminator
Lowest ascii number
Increase in stack size
Size of output buffer

/* Flag to indicate
/* error follows

ifndef NULL
define NULL
endif

64

*/

of bytes in var space

/* Sem check codes

ADD 1
SUB 2
DIVIDE
MULT 4

*/

for arith ops

semantic

*/
*/
*/
*/

*/
*/
*/

*/
*/
*/

Type Definitions

*
*

/* Arithmetic operations
/* Generic flag type
/* Types found in language

typedef int optype,


FLAG,

PHITYPE;

*/

*/
*/

typedef char stg [20];

/*

Assembly language code names

*/

typedef struct and struct *and_ptr;

/* Pointer to and_tabie entries

*/

************************** * Tvpetable Definitions ********************/

typedef struct typenode


char name
10
int bytes;
struct typenode *typeptr;
tnode;

/*

Typetable entries

*/

/a********************** Fonnallist Definitions **********************/


typedef struct formnode

/* Formal stack
/* formname, formtype
/* Link for list

type;
struct formnode "link;
fnode;
int name,

*/
*/
*/

/it********************** Vartable
typedef struct varnode

Definitions **********************/
/*
/*
/*
/*
/*
/*
/*

int type,
form,
def;
nodal nptr;
fnode *fptr;

struct varnode *link;


*varptr;

Entry for variable stack


varname, vartype
Flag set if var is a formal
True if var is a definition
ptr to defining node
ptr to formals
Link for list

*/
*/

*/
*/
*/
*/
*/

/it*********************** Deftable
typedef struct defnode
int type;
nodal nptr;
fnode *fptr;
struct defnode *link;
*defptr;

Definitions **********************/

/* varname, vartype
/* ptr to defining node
/* ptr to formals
/* Link

for list

*/
*/
*/
*/

/A************************** And Definitions **************************/


struct and_struct
{nodal ptr;

/* Structure for and lists


/* Ptr to nodal containing var

*/

name

*/
/* Ptr to buffer where
/* name is called

int buffptr;

struct and_struct *link;

/* Link

};

65

for linked list

*/
*/

/A*****************************************************************
*
PUBLIC DOMAIN SOFTWARE

*
User Header
Name
*
user.h
File
* Authors
*
Maj E.J. COLE / Capt J.E. CONNELL
*
* Started
04/01/87
*
* Archived
04/10/87
* Modified
***********************************************************************
*
* This file is the header file for the user interface module

*
*

(user.c)

a**********************************************************************
*
* Modified
A********************************************************************/
:

/it*************************** Globals ******************************/


#define BUFFLENGTH 30

/* Max size of input


/* directory

#define NOTFOUND
#define BSIZE 1000
#aefine BLOCKSIZE 50
tdefine BACKSPACE
#define EOLN 13
#define ESCAPE 27

#define
#define
#define
#define
#define
fdefine
tdefine

/* ASCII Equivilents

*/

/* Messages to observer
GETPROGRAM "Program to Compile -> "
HEADER1 "ROCK COMPILER"
HEADER2 "Press Escape Key to Exit Compiler"
FILE1_ERR0R "File not Found"
FILE2_ERR0R "Press ESCAPE to exit, any other key to continue"
WAIT "Compiling: Please Wait"
PAUSE "PRESS ANY KEY TO CONTINUE"
/* Textfile of errors

66

*/
*/
*/
*/

/*

#define ERRORFILE "errors. phi"

Input buffer size


Input block size

/*

file name

*/

*/

APPENDIX F

ROCK COMPILER

MAIN MODULE

**********************************************************************
* PUBLIC DOMAIN SOFTWARE
/

Main Rock Module


Name
Rock_main
File
Maj E.J. COLE / Capt J.E. CONNELL
Authors
01/06/87
Started
Archived
04/10/87
04/13/87 Output files put to vdisk
EC
Modified
***********************************************************************
* This file contains the following modules for the PHI compiler:
*
.

R Initial

Semcheck

Main

Algorithm
This contains the main procedure for the phi compiler, in addition to the initialization procedure & the main semantic checking
procedure.
The main module inits the program, sets up the screen
by calling "user ()", & decides whether an error routine needs
It also closes out the input file.
to be called.
The "semcheck procedure is designed to be called by any function
with a ptr to a parse tree node as an argument.
It will then
determine which sub-module is necessary to check the node.
"R_Initial" presently has the function of initializing the type

table.

*
*
*

*
*
*
*
*

***********************************************************************
* Modified
*
04/13/87 Output files written to vdisk, "d:"
EC
a************************************************************/
:

**************************** Externals ******************************

#inciude <semcheck.h>
extern void c_startup
c_ending
user
user_err
p_close
set_page
mov_cursor
(

/* Initializer for code buffer


*/
/* Close out for code generator
*/
/* User interface
*/
/* Error writing interface
*/
/* Close source file
*/
/* Change video display page
*/
/* Move cursor to specified locat */

extern FLAG err_found;


extern nodal parser ()
/

*************************** Globals ******************************/

unsigned _stack =

STACKSIZE;

67

; ;

/A************************* r Initial ****************************/


void
initial ()
{extern tncde types

/*

strcpy
types
strcpy
types
strcpy
types
strcpy
types
strcpy
types

Initialize semantic checking

*/

[];

(types [UNTYPED] .name, "untyped") ;


[UNTYPED] .bytes = NULL;
(types [BOOLEAN] .name, "boolean");
[BOOLEAN] .bytes = BOL_BYTES;
(types [REAL]. name, "real");
[REAL]. bytes = REAL_3YTES;
(types
INTEGER] .name, "integer");
[INTEGER] .bytes = INT_BYTES;
(types [NATURAL] name, "natural");
[NATURAL] .bytes = NAT_BYTES;

/* Set

up type table

*/

/A********************** SemChecker ***************************/


PHITYPE
semcheck (ptr)
nodal ptr;
{extern PHITYPE tkindef (), trtarrow (),
tfunid (), tid (), tconstant (), tactuallist
PHITYPE type;
switch
case
case
case
case
case
case
case

(ptr->name)
(ADD_)
(SUB_)
(MULT_)
(RDIV_)
(IDIV_)
(COLON_)
(CAT_)

/* Breaks Sem Check

(),

type

arithop (ptr)

break;
case (POS_)
case (NEG_)
type = tprimary (ptr)
break;
case (ORLOG_)
type = tor (ptr);
break;
type = tand (ptr)
case (ANDLOG_)
break;
case (NEGLOG_)
type = tnegation (ptr)
break;
case (KINDEF)
tkindef (ptr)
break;
case (RTARROW_)
type = trtarrow (ptr);
break;
case (LETDEF)
tletdef (ptr)
break;
case (KW_ + WHER_)
type = twhere (ptr)
break;
case (AUXAND)
tauxand (ptr)
break;
case (DATAAUXDEF)
tdatauxdef (ptr)
break;
case (FUNAUXDEF)
type = tfunauxdef (ptr)
break;
type = tfunid (ptr);
case (FUNID)
break;
type = tactuals (ptr)
case (ACTUALLIST)
break;
case (COMMA
:

68

tactuals

();

into cases

*/

; ; ;

; ;

telist (ptr);
(ELLIST)
break;
type = ttypetimes (ptr);
case (TYPETIMES)
break;
case (EQ_)
case (LEQ_)
case (NEQ_)
case (GEQJ
case (KW_ + GREATER_)
case (KW_ + LESS_)
IN_)
case (KW_
type = tcomp (ptr)
case (KW_ + NOTIN_)
break;
type = tif (ptr)
case (KW_ + IF_)
break;
type = telse (ptr)
case (KW_ + ELSE_)
break;
type = tthen (ptr);
case (KW_ + THEN_)
break;
type = telseif (ptr)
case (KW_ + ELSIF_)
break;
type = tid (ptr);
case (IDENTIFIER_)
break;
type = tconstant (ptr)
case (CONSTANT_)
break;
case (REAL_)
type = REAL;
break
type == INTEGER;
case (INTEGER_)
break;
case (BOOLEAN_)
type
break;
case (NATURAL_)
type = NATURAL;
break;
case

default

/* Unimplemented feature
/* so sandbag programmer

terror (ERR_r, ptr->ln)

found,

*/
*/

break;
}

return

(type)

/************************** Main A*******************************/


main
{extern char prefix [];
extern void curson (), cursoff
char name_holder [30];
nodal root;
(

c_startup
r initial
user
if

();

Prefix of the souce file


Turn cursor on and off
Holder for prefix name
Root of the Parse tree

/*

Initialize and open files

/* User

parser

(root

/*

()

Parse code; continue if root

display

if
err_f ound)
ending
(

interface

/* not equal to nil


/* Freeze current video

set_page (2
cursoff
semcheck (root);

/*
/*
/*
/*

/*

Semantic check and code gen

/*

Clean up and close out files

69

*/
*/
*/
*/

forkl

forkl

;; ;

;;

"d: rasm86 .exe",

"d: rasm86 .exe"


prefix, NULL)
"d: link86 .exe", "d: link86 .exe"
prefix,",", "d:u", NULL);

strcpy (name_h older prefix)


strcat (name_holder, ".1st");
remove (name_holder
strcpy (name_holder prefix)
".sym");
strcat (name_holder
remove (name_holder)
set_page (0)
curson

/* Assemble the code

*/

/* Link object files together

*/

/* clean up the loose files

*/

error files if req

*/

if

(err_found
set_page
curson
user_err
(

0)

root

/* Print

p_close

/*

();

Close source file

/* Execute rock again; exit comes


/* from inside main Procedure

execl ("rock. exe", "rock. exe", NULL);

70

*/
*/
*/

APPENDIX G

ROCK COMPILER

SCANNER

/***********************************************************************
*
PUBLIC DOMAIN SOFTWARE
*
* Name
Scanner
*
* File
Scan2
* Authors
J.E.
CONNELL
*
COLE
Capt
Maj E.J.
/
* Started
10/10/86
*
* Archived
12/11/86
* Modified
04/23/87 tokens no longer output to intermediate file. *
************************************************************************
*
* This file contains the execution modules for the scanner:
*

IsKeyWordO

GetTokenO,

*
GetToken is called from FillBufferO and returns an
*
integer code to uniquely identify the token.
*
*
IsKeyWordO checks each identifier to insure it's not
*
*
a PHI Keyword.
************************************************************************
* Modified
01/10/87 Corrections to comply with latest definitions *
x
*
of the language. JC
*
*
01/10/87 GetTokenO returns CONSTANT_ vice REAL_ or
*
*
INTEGER_. JC
*
*
01/21/87 Error Recovery added and files combined. JC
*
*
03/10/87 Corrections to partially comply with latest
*
*
definitions of the language. JC
*
04/23/87 tokens no longer output to intermediate file *
*
*
GetToken called directly by the Parser now.
a*****************************************************/

Algorithm

include
include
include
include

<scanner.h>
<stdio.h>
<errors.h>
<ctype.h>

extern

FILE *infile,

*errorfile;

/*

working files

*/

/**********************************************************************/
int

GetToken (token)
char *token;
/* Calls
*
*

*
fgetc (inf ile) for the next char from the input file & builds
*
the token a char at a time.
Returns an internal integer value
*/
representing the type of token found

/*

static int lookahead = FALSE,

line num =

1;

71

lookahead is

/* is current

line

*/
flag, line_num
of user prog */

; ;

;;

; ; ;; ; ;
; ;; ;

;
;

'

static char ch;

/* ch holds last
/* input prog

int

/* i = index into token array;


/* k = temp holder for tokens

k;

i,

extern ErrorHandler

character from

while (TRUE)
{

/*

= 1;

initialize, token name


start at token[l]

/* will

if

(!

lookahead)

ch = fgetc (inf ile)


lookahead = FALSE;

while
{

isspace

if (ch ==
{

+-

(ch)

/*

'\n'

process carrage returns

+ line_num;

return (EOLN_)
/* end if

'

\n

ch = fgetc (inf ile)


/* end while white space

if

(ch == EOF

switch
case
case
case
case
case
case
case
case
case
case
case
case
case
case
case
case
case

return (EOF

/* reached end of the file

);

(ch)

return
return
return
return
return
return
return
return
return
return
return
return
return
return
return
return

(ADD_)

(MULT_

(IDIV_)
(SEMI_)

(SUBSCRIPT^)
(COMMA_)
(LTPAREN_)
(RTPAREN_)
(NEGLOG_)
(COLON_)
(CAT_)
(STAR_)

(LTBRAKET_);
(RTBRAKET_)
(LTSQUIG_)

(RTSQUIGJ

== '>')
(ch = fgetc (inf ile)
return (RTARROW_)
else if (ch == '-'
while((ch = fgetc (inf ile)
if

/*

process comment

!=

'\n'

&S

ch

!=

EOF)
/* do nothing

if (ch ==

'\n')

++line_num;
return (EOLN_)
else return (EOF_)

/* end else if comment

else
lookahead = TRUE;
return (SUB_)
case <
if((ch = fgetc(infile)
return (LEQ_)
else if(ch == >)
return (NEQ_)
else lookahead = TRUE;
'

'

== '=')

72

*/
*/
*/
*/

; ;; ;

;; ;
;
)

; ;

return (ST_SEQUENCE_)

case

'

>

'

(ch = fgetc(infile)
return (GEQ_)
else lookahead = TRUE;
i'f

return (END SEQUENCE

case '='
if((ch = fgetc (inf ile)
return (EQUIV_)
else lookahead = TRUE;
return (EQ
)

'

==

==

W)

.)

case /
if((ch = fgetc (inf ile)
return (ANDLOG_)
else lookahead = TRUE;
return (RDIV
'

case \ \
== '/')
if((ch = fgetc (inf ile)
return (ORLOG_)
else
lookahead = TRUE;
ErrorHandler (line_num, ERR2,NULL)
return (ORLOG

/*

case
== '-')
if((ch = fgetc (inf ile)
== >')
if((ch = fgetc (infile)
return (LINERTARROW_)
lookahead = TRUE;
ErrorHandler line_num, ERRO, ch)
return (LINERTARROW );

/* ch is either
or '-'
/* figured that's what he

'

'

'

'

figured that's what he wanted

case

'

'

'

wanted

*/
*/

$
'

ch = fgetc inf ile)


(ch == 'R'
if
(ch == 'r
||
return (REAL_)
else if
(ch == 'N'
(ch ==
(

'

'n')

return (NATURAL_)
else if
(ch == 'Z'
(ch == 'z'
II
return (INTEGER_)
else if
(ch == 'B') II (ch == b")
return (BOOLEAN_)
else if (ch == 1
return (TRIVIALJ
else lookahead = TRUE;
ErrorHandler (line_num, ERR3, NULL
return (INTEGERJ
(

'

'

if
{

isalpha

/* default return type


/* end switch

/* starts with a letter

(ch)

do

token [i++] = ch;


ch = fgetc inf ile)
while (isalnum(ch)
token[i] = '\0';
lookahead = TRUE;
{

/* end do
/* end the string

ch

/* now check to see


/* KEYWORD

73

*/
-/
if

it's a

-/
*/

);

)
;

;
)

;; ; ;

>=

k = IsKeyWordftoken +1))
return (KW_ + k)

if((

0)

/* Return Adjusted Keyword index


/* to calling routine

*/

/* end if alfa char

*/

*/

return (IDENTIFIER_)
I

if
{

(isdigit (ch)
if (ch == '0'
while (ch=fgetc(inf ile)
{

==

'0')

/* do nothing,

if

isdigit (ch)
token[i++] =

zeros

eat

'

'

/* end if

leading

while (isdigit (ch)


token [i++i = ch;
ch = fgetc (inf ile)
{

/* end

if
{

(ch ==
token [i++]
'

while is

digit

'

= ch;

ch = fgetc (inf ile)


if
(

isdigit (ch)
token[i] = '\0';
Error Handler (line_num, ERR 4,
token+1)
token [i + 1] = token [i];
token [i] = 0;
return (CONSTANT_)
else
do
token [i++] = ch;
ch = fgetc inf ile)
while (isdigit (ch)
(

/* fix for insertion into


/* name table
/*

end if not a digit

/* end do
/* end if ch ==
/* end the string

'

'\0';
token [i
lookahead = TRUE;
return (CONSTANT^)

/* end if isdigit
/* process LITERALS

if
(

(ch ==

token
while
{

'V

'

= ch;
(ch= fgetc (inf ile) !=EOF) SS
(ch!='\n') && (i< MAXLINE)
token [i++] = ch;
if (ch == '\")
[

i++

if
{

(ch =

fgetc (inf ile)

!=

>\")

lookahead = TRUE;
token [i] = '\0';
(strlen (token) >
return (LITERAL_)
return (EMPT LIT
if

3)

/* end if !=
/* end while
/* end the string
'

token[i]='\0';
ErrorHandler line_num, ERR 5, token+1)
return (LITERAL_)
(

/* figured that's what


/* end if literal

char not recognized

ErrorHandler (line num, ERR6, &ch)

/" Default

continue;

/* let's try again


/* end while (true)
/* end GetTokenO

74

he wanted

*/

/a***********************

Scanner Utilities

it*********************/

int

IsKeyWord(token)
char *token;

/* Checks to see if the input token is a keyword in the language.


*
If it is, the function returns the numeric value of the keyword.
*
Performs binary search of
If it isn't, the function returns -1

*
*

keyword array MUST KEEP THIS ARRAY IN ALPHABETICAL ORDER!

*/

int

i;

register int

lo

=0,

hi

mid;
/* list of PHI keywords
/* alphabetical order!!

char

KEEP in */
*/

*keywords[] =
[MAXLINE] ; static
char
"AND", "BEGIN", "ELSE" "ELSIF" "END" "ENDIF", "FILE", "GREATER", "IF",
"IN", "LESS", "LET", "NOTIN", "READ", "THEN", "TYPE", "WHERE", "WRITE"
,

strcpy
for

(i

s,

token)

s[i] != '\0' ;i++)


<= s[i] SS s[i] <=
s[i] += 'A' - 'a';

0;

if('a'

hi =

(sizeof (keywords) /sizeof (char*)

whiledo
{

/*

'z'l

insure letters are upper case

*/

<= hi)

mid = (lo + hi) 12;


if((i = strcmp (s, keywords [mid]

)) <0)

hi =
mid;
else if(i>0)
lo = ++mid;

else
return(mid);

/* found a keyword
/* end while
/* didn't find a keyword
/* end IsKeyWord

return(-i);
}

75

*/
*/
*/
*/

APPENDIX H

ROCK COMPILER

PARSER

/***********************************************************************
PUBLIC DOMAIN SOFTWARE
* Name
parser pt I
* File
parserl
* Authors
Maj E.J. COLE / Capt J.E. CONNELL
* Started
10/20/86
* Archived
12/11/86
* Modified
04/23/87 No longer set up to work, with file of tokens. *
************ ************************************************************
*
* This file contains the following modules for the PHI parser:
*

BlockBo dyC
AuxExp
)

LetDefs
AuxDef s

()
(

Defs ()
AuxAnd

DefAndO
Formals

QualExp ()
Expression

The main module calls BlockBodyO to start the parse


off.
BlockBody in turn calls LetDefs () first and then
QualExp () looking for a valid program.
The remaining
modules in Pt s 1-3 are called by these when trying to
validate a pargram.
The results from the parse are now
kept in an abstract syntax tree for type checking and
Various utility functions are used
code generation.
to build the tree and simplify parsing the grammer.

Algorithm

'

************************************************************************

Modified

12/26/86 Flattened tree output changed to abstract


syntax tree form. JC
01/10/87 Corrections to comply with latest definitions
of the language. JC
01/27/87 Error Recovery added and files combined. JC
03/20/87 Token buffer implemented for parser. JC
03/29/87 Changed manner errors are handled required
for integration with back-end.
04/23/87 No longer set up to work with file of tokens.
JC
GetToken is called directly thru FillBuffO.
***********************************************************************
*

^include <stdio.h>
#include <parser.h>
/*

int

rtbrket = FALSE,

int

line no

argbind

global flags - aid in making


deterministic

/* PHI

= FALSE;

/*
/*
/*
/*
/*

1;

76

*/
*/

*/
global var, current line no
*/
of program
tokenbuff holds tokens provided*/
- ptr is a ptr to*/
by GetToken
*/
next token in tokenbuffer -

; ;

/* must use "long"


/* holds addresses

because buffer

*/

*/

/* use BUFSIZE t 1 in case have to"/


/* place address of 'name at end
*/
/* of buffer
*/

long

tokenbuff [BUFSIZE+1]

FILE

*poutfile,

*ptr

&

tokenbuff BUFSIZE
(

/*

*errorfile;

working files

*/

/********************************************************************/
nodal
Parser ()
{

"root = NULL;
void p_close(), mov_cursor

NodeRec
extern

num_errors

/*

/* init number

= 0;

errorfile = f open ("errors .phi", "w")


fprintf (errorfile, "%40s\n\n", "ROCKY ERRORS")
f close (errorfile)
DEBUG
fifdef
poutfile = fopen "parser out" "w"
#endif
.

if

!ByPass (EOF_)

/* rewrite

jof errors

file for clean start

*/
*/

*/

BlockBody (Sroot

external asm functions

look for a valid program

*/

/* set cursor on screen to


/* found extra junk, tell user

*/
*/

/* end if not end of user's prog

*/

/*

mov_cursor (20, 0) ;
print f "WARNING ...additional text found
at completion of your program (

line %d\n", line_no)


}

#ifdef
if

DEBUG
/* write parser's output
*/
*/
/* to data file
/* case it's needed for debugging */
/* need that carrage return
*/

!= NULL)

(root

PostOrder root
fprintf (poutfile, "\n")
f close (pout file)
#endif
(

fclose(infile)

p_close

(num_errors
return (NULL)
else
return (root)
if

>

0)

/*

end main

*/

/A*******************************************************************/
void
PostOrder root)
NodeRec
*root;
(

/*
/*

Does a post order walk of the tree with (root) as its head.
Just prints out the node name to the screen now

77

*/
*/

static
if

ir.t

;)

/* used in pretty printing parser */


/* output file
*/

Oj

(root

!= NULL)

PostOrder (root->lptr) ;
PostOrder (root ->rptr)

switch (root->name)
case IDENTIFIER
case CONSTANT_
case LITERAL_
fprintf (pout file, "%d ",root ->name)
fprintf (poutfiie, "%ld
", root->index)
break;
default
fprintf (poutfiie, "%d
",root ->name)
:

/* end ID, CONSTANT,

LITERAL

/* end switch

if

++i

7)==0))

fprintf (poutfiie, "\n")

/* end root != NULL


/* end PostOrder

/A***********************************************************/

BlockBody (root)
NodeRec
**root;

/* root is a ptr to tree/subtree


/* currently working with

<BLOCKBODY>

<QUALEXP>

*/

*/

<LETDEFS>

flag;
iff ((flag = LetDefs (root)
return (TRUE)

== TRUE))
/* looking for LETDEFS; BL0CK30DY
/* look for plain ol' QUALIX?

else if (flag != ERROR_)


flag = QualExp (root

*/
*/

return flag)
(

/A*************************************************************/

mt
/* root is a ptr to tree/subtree
/* currently working with

LetDefs (root)
NodeRec
**root;

<LETDEFS>

/*

let <DEFS>

<BLOCKBODY>

tifdef DEBUG
printf(" ietdefs entered\n");
#endif

scanf("%*c"

if (ByPass (KW_ + LET_)


"root = CreateNode (LETDEF)
!= TRUE)
if (Defs (4 ('root) ->lptr)
i

ErrorHandler (line_no, ERR_a,

/*
/*
/*
/*

starts off with LET


start off the tree
look for the definitions
report it, try & fix

/*

report it

(long)SEMI_)
if (!ByPass (SEMI_)

ErrorHandler (line_no, ERR_b,

&

try to continue

(long) SEMI_)

ByPass (SEMI_)
== TRUE)
if (BlockBody (& (*root) ->rptr)
return (TRUE)
ErrorHandler (line no, ERR a, NULL);
(

78

/* found everything
/* report it, no fix

*/
*/

return (ERROR

; ;

, ;;

started LETDEFS but couldn't


finish
/* end ByPass LET
/*

/*

#ifdef DEBUG
printf!" letdefs exited\n")
#endif

/
*/
*/

scanf("%*c")

/* default - no LET at
/* end LetDefs

return (FALSE)

beginning

/A*********************************************************************/
int
Def s (root)
NodeRec

/* root is a ptr to tree/subtree


/* currently working with

'root;

(<DATADEF> <FUNDEF> <KINDEF> <TDEFID>


<DEFAND>
<TDEFFUN>)
Where "<DEFAND> " need not be present

/* <DEFS>
/*
/*

*/
*/

NodeRec
long

"temp;
flag;
id ptr;

extern

long *ptr;

int

/* address of data struct


/* holding identifier name

if(id_ptr = ByPass (IDENTIFIERJ


temp = CreateNode (IDENTIFIER^
temp ->index = id_ptr;
)

if (ByPass (EQUIV_)

*root = CreateNode (DATADEF)


*root) ->lptr = temp;
if (QualExpU (*root) ->rptr)

TRUE)

!=

/*

set up itsside of subtree

/*
/*
/*
/
/*

looking for ID ==
found '==' It's a DATADEr
attach temp ptr to root
now need QualExp
note, try & fix

ErrorHandler line_no, ERR_c,


(long) KW_+AND_)
(

/* end ByPass EQUIV_


/* looking for ID
TYPEEXP
/* found
so it's a KINDEF
/* attach temp ptr to root

else
if (ByPass (COLON_)
*root = CreateNode (KINDEF)
(root) ->lptr = temp;
if (TypeExp(& (*root) ->rptr)

!=

TRUE)

/* now need TypeExp


/* note, try to fix

ErrorHandler (line_no, ERR_d,


(long) KW_+AND_)
/* end else if ByPass
/* not == or :, so must be
/* ID FORMALS
:

else
f

'root = CreateNode (FUNDED


(root) ->lptr = CreateNode (FUNID)
(*root) ->lptr->lptr = temp;
if
Formal s (& (Toot) ->lptr->rptr
(

/*
/*

will look for ID FORMALS


attach ID to FUNID

/*

!=TRUE)

ErrorHandler (line_no, ERR_e,

need the FORMALS


it, try S fix

/* note

(long)EQUIV_)
if

/* Look for '==', already created


/* FUNAUXDEF - Need QualExp on rt
/* note, try s fix

ByPass (EQUIV_)

ErrorHandler (line_no, ERR_f


(long) KW_+AND_)

else if

(QualExpU (*root) ->rptr)


(

!=TRUE)

79

*/
*/

))

;;

)
;
;; ; ;
, ;

ErrorHandler (line_no, ERR_c,


(long) KW +AND

/* note it, try

fix

&

/* end else not

goto CHECK;

/*

'== or

found something so need to

*/

/* check for more


/* end if ID

/******

*/
*/

didn't find ID, so look for FORMALS == QUALEXP

!= FALSE))
else if (((flag = Formals root
if (flag==ERROR_)
ErrorHandler line_no, ERR_e,
(long) EQUIV_)
if (ByPass(EQUIV_)
MakeNewRoot root DATADEF, LEFT)
if (QualExp(S (*root) ->rptr) !=TRUE)
(

/*

****** */

found something

/* note,

try

fix

/* looking for ==
/* found ==, so fix tree
/* need QualExp on rt
/* note, try S fix

ErrorHandler line_no, ERR_c,


(long) KW_+AND_)
(

/* end if ByPass (EQUIV)


/* note, try to fix

}else

ErrorHandler (line_no, ERR_f


(long)KW_+AND_)
goto CHECK;

/*****

nothing so far

/* found somenthig so check for


/* more defs

look for some sort of TYPEDEF

else if (ByPass (KW_ + TYPE_)


if(id_ptr = ByPass IDENTIFIERJ
temp = CreateNode IDENTIFIER_)
temp ->index = id_ptr;
{

/*
/*

if (ByPass (EQUIV_)

"root = CreateNode (TDEFID)


*root ->lptr = temp;
)else
if (Formals (root) != TRUE))
ErrorHandler line_no, ERR_e,

*/
*/

*****/

found TYPE, looking for ID


set up It side of subtree

*/
*/

/* found ID, looking for ==


/* found == so it's a TDEFID

==
/* not
yet
/* note it, try to
'

'

fix

(long)

EQUIVJ

MakeNewRoot (root, FUNID, RIGHT)


(root) ->lptr = temp;
if
ByPass (EQUIV_)
ErrorHandler (line_no, ERR_f
(long)KW_+AND_)
MakeNewRoot (root, TDEFFUN, LEFT)
(

if

(TypeExptS

(*root) ->rptr)

!=

TRUE)

found/fixed Formals, fix tree


attach ID to FUNID node
/* note it, try to fix
/*

*/

/*

*/
*/

/* found/fixed '==',fix tree


/* end else not '==' yet
/* need TypeExp on rt
/* note, try & fix

ErrorHandler (line_no, ERR_d,


(long) KW_+AND_)
/* end if ByPass ID
/* no ID, note it, try to

>

else
ErrorHandler (line_no, ERR_g,
(long)KW_+AND_)
goto CHECK;

fix

/* found sometthing so check


/* more defs
/* end ByPass TYPE
/* default

return flag)
(

80

for

none of the above

*/
*/
*/

)
;

/*

CHECK:

found something so need to


for more clef's

/* check

Def And (root

*/
*/

/* any errors have been


/* so press on
/* end Defs

return (TRUE)
}

notea,

*/
*/
*/

/*******************************************************************/
void
DefAnd(root)
NodeRec

/*
/*
/*

/* root is a ptr to tree/subtree


/* currently working with

**root;

:= and <DEFS>
<DEFAND>
Where " and <DEFS> " need not be present.
This function assumes root is not NULL upon entry
:

Note:

*/
*/

*/
*/
*/

if (ByPass (KW_
{

AND_)

MakeNewRoot (root, DEFAND, LEFT)


if (Defs (S (*root) ->rptr)

/*

found "and" so fix tree

*/

!= TRUE)

ErrorHandler (line_no, ERR_h,


(long) SEMI_)

/* note it, try to fix


/* end ByPass AND
/* end DefAnd

*/
-/

*/

/a**********************************************************/
int
/* root is a ptr to tree/subtree
/* currently working with

QualExp root
NodeRec
**root;
(

<QUALEXP> ::= <EXPRESSION> where <AUXEXP>


Where "where <AUXEXP>" need not be present.

/*
/*

*/
*/

*/
*/

flag;

int

#ifdef DEBUG
print f(" qualexp entered\n")
#endif

scanf "%*c")
(

if (((flag = Expression (root)

== ERROR_)

EatEm(KW_+END_)
if (ByPass (KW_+ WHERE_)
MakeNewRoot (root, (KW_+WHERE_)
AuxExp(& (*root) ->lptr)
(

RIGHT)

#ifdef DEBUG
printfC qualexp exited
scanf ("%*c")
fendif

%d\n",

f lag)

/* errors already reported,


/* attempt to press on
/* looking for where expression
/* found one, fix tree
/* need AuxExp following WHERE

*/

/*

end byPass WHERE

*/

/*

default - just return flag


Qualexp ()

*/
*/

*/
*/
*/

*/

return flag)
(

/* end

/************************************************************/
int

AuxExp(root)
NodeRec

/*

/* root is a ptr to tree/subtree


/* currently working with

"root;

<AUXEXP> ::= <AUXDEFS> (where <AUXEXP>)

81

*/
*/

*/

; ;
, ;

);

);

'

flag;

int
if

(flag = AuxDefs (root) != TRUE)


Error Handler (line_no, ERR_i,
(long) KW_+WHERE_)
)

if (ByPass (KW_+ WHERE_)


MakeNewRoot (root, (KW_

AuxExp

(S

WHERE_)

(*root) ->lptr)

RIGHT)

return flag)
(

/* need at least one AUXDEF


/* note, try & fix

*/
*/

/*
/*

looking for multiple WHERE'S


found one, fix tree
/* need AuxExp following WHERE
/* end ByPass (WHERE)

*/
*/

/* default - return
/* first AuxDefs
/* end AuxExp

*/
*/

result of

*/
*/

*/

/*****************************************************************/
int

AuxDefs root
NodeRec

/*
/*

'root

root is a ptr to tree/subtree


currently working with

<AUXDEFS> ::= (<DATAAUAXDEF>


<FUNAUXDEF>) <AUXAND>
Where "<AUXAND> " need not be present.

/*
/*

*/
*/

*/
*/

NodeRec
int

long

*temp;
flag;
ptr;

/* address of data struct


/* identifier name

if ((ptr = ByPass (IDENTIFIER^


{

holding */

temp = CreateNode(IDENTIFIER_)
temp ->index = ptr;

/*

set up its side of subtree

if (ByPass (EQUIV_)

/*

looking for ID ==

"root = CreateNode(DATAAUXDEF)
(root) ->lptr = temp;
if (Expression (& (*root) ->rptr)
Error Handler (line_no, ERR_c,
(long) KW_+WHERE_)
)

TRUE)

*/

/* found '==' It's a DATAAUXDEF


/* attach temp ptr to root
/* now need Exp
/* noteit, try & fix
/* end ByPass EQUIV_
'==' so must be

/* not

else
'root = CreateNode(FUNAUXDEF)
(root) ->lptr = CreateNode (FUNID)
(root) ->lptr->lptr = temp;
if (Formals (& (*root) ->lptr->rptr)

/* will look for ID FORMALS


/* attach ID to FUNID
/* need the FORMALS

!= TRUE)

Error Handler (line_no, ERR_e,


(long) EQUIV_)

/* note,

try to fix

/* Looking for '==', already


/ created FUNAUXDEF /* need QualExp on rt
/* note the errors, try & fix

ByPass (EQUIV_)
ErrorHandler (line_no, ERR_f
(long)KW_+WHERE_)
else
if (Expression (S
*root ->rptr)
(

!= TRUE)

ErrorHandler line_no, ERR_c,


(long)KW +WHERE
(

/ end else

not

'

==

found something so need to


/* check for more
/*
end if ID

goto CHECK;

82

*/
*/

*/

*/

*/
ID FORMALS */

if

*/

******

;)

; ;;

; ;

***********

didn't find ID, so look for FORMALS == EXP


/*

!= FALSE))
if(((flag =' Formals (root)
if (flag==ERROR_)
ErrorHandler (line_no, ERR_e,
(long)EQUIVJ
if (3yPass(EQUIV_)
MakeNewRoot (root DATAAUXDEF, LEFT)
if (Expression (& ('root) ->rptr)
)

found something

/* note,

fix

looking for ==
found ==, so fix tree
/* need Exp on rt
/*
/*

try

!= TRUE)

/* note, try fix

ErrorHandler (line_no, ERR_c,


(long) KW_+WHERE_)
)else

ErrorHandler line_no, ERR_f


(long)KW_+WHERE_)
(

/* found somenthig so check


/* more auxdefs

goto CHECK;

for

return flag)
(

/* default

none of the above

/* found something so need to


/* check for more def's

CHECK:

AuxAnd (root)
/* any errors have been noted,
/* so press on
/* end AuxDefs

return (TRUE)

*/
*/
*/

a*******************************************************************/

void
AuxAnd (root!
NodeRec

/* root is a ptr to tree/subtree


/* currently working with

root;

<AUXAND> ::= and <AUXDEFS>


Where "and <AUXDEFS>" need not be present.
This function assumes root is not NULL upon entry
Note:

/*
/*
/*
{

if (ByPass (KW_+AND_)

MakeNewRoot root AUXAND, LEFT)

if

(AuxDefs

/*

(*root) ->rptr) != TRUE))


ErrorHandler (line_no, ERR_h,

found "and" so fix tree

(&

/* note it,

try

&

fix

(long)KW_+WHERE_)
/* end ByPass AND
/*
end AuxAnd

/a*********************************************************************/
int
/* root is a ptr to tree/subtree
/* currently working with

Formals (root)
NodeRec
**root;

<FORMALS>

/*

= <ID>

'

<FORMALS>

NodeRec

*temp,

long

ptr;

if
{

((ptr
*rcot

=
=

(*root)

*workingroot

/* temp ptrs to nodes in tree


/* workingptr marches down the
/* rt side of the subtree

ByPass (IDENTIFIER^)
CreateNode( IDENTIFIER^
->index = ptr;

/*

return (TRUE)

83

checking for just an ID

);

; ;

; ;

/* end if ByPass

if (ByPass (LTPARENJ
{

'root = CreateNode (FORMAL)


=TRUE)
Formal s (S (*root) ->lptr)
if
ErrorHandler (line_no, ERR_e,
(long)RTPAREN_)
(

workingroot

/*

recursive search

ErrorHandler (line_no, ERR_e,


(long) RTPAREN_)
workingroot = workingroot->rptr;

if (ByPass

')'

*/

fix

*/

FORMALS now looking

'('

*/

*/
*/
*/

for

/*
/*
/*
/*

found ',
attach it to rt side */
*/
recursive search
*/
need FORMALS following ','
*/
note it, try & fix

/*

(RTPARENJ

&

FORMALS

/*

',

*/

'

'

/* end

'('

set the working ptr for later

/* use
/* have

workingroot ->rptr=CreateNode (COMMA_)


temp = workingroot->rptr;
if
Formal s (& (temp->lptr)
!=TRUE)
(

checking for

/*

(*root);

while (ByPass (COMNA_)


(

/*

/* note it, try

*/

ID

while ByPass COMMA

looking for

')
'

already found

</

*/

/*
*/
FORMALS
/* compact the tree - only one ID */
(

'

if(*root == workingroot)
"root = (*root) ->lptr;
free (workingroot

'

/* end of compaction
/* end of compaction

*/

*/

return (TRUE)
/* end if RTPAREN
/* missing ')' after

ErrorHandler line_no, ERR_ j, NULL)


return (ERROR_)
(

'('

/* end if ByPass LTPAREN


/* default - none of the above
/* end Formals ()

return (FALSE)
}

*/
*/
*/
/
*/

/a********************************************************************/
int

Expression (root)
NodeRec
**root;

/* root is a ptr to tree/subtree


/* currently working with

<EXPRESSION> ::= <CONJUNCTION>

\/

*/
*/

<EXPRESSION>)

flag;

int

== TRUE))
if (((flag = Con junction (root)
if (ByPass (ORLOG_)
MakeNewRoot (root, ORLOG_, LEFT)
if (Expression (& (*root) ->rptr) !=TRUE)
ErrorHandler (line_no, ERR8,
)

(long)ORLOGJ

/*

look for Conjunction

/* will recursively check for \/


/* found, so fix root for return
/*
w/o following Exp.
/* Just note it, no fix

return (ERROR_)
}

/* end recursive search

return flag)
(

/* end Expression!)

/A*******************************************************************/

84

*
.

/A*******************************************************************
PUBLIC DOMAIN SOFTWARE
* Name
parser pt 2
* File
parser2
* Authors
Maj E.J. COLE / Capt J.E. CONNELL
* Started
10/20/86
* Archived
12/11/86
* Modified
JC
01/27/87 - Error Recovery added.
************************************************************************
*
* This file contains the following modules for the PHI parser:
*
Relation ()
Relator ()
Negation ()
Con junction ()
*
MullOPO
Term()
AddOpO
SimplExpO
*
Application
Primary ()
Actual ()
Factor ()
.

Algorithm

See parser part

************************************************************************
*
* Modified
12/26/86 Flattened tree output changed to abstract
*
*
syntax tree form. JC
*
*
comply
Corrections
to
with
latest
definitions
01/10/87
:

of the language. JC

*
01/27/87 Error Recovery added and files combined. JC
a*************************************************************/

include <stdio.h>
include <parser.h>
extern int

line_no;

extern int

rtbrket;

global var, holds current line


no of source prog
/* global flag - aids in making
/* PHI deterministic
/*
/*

*/
*/
*/
*/

/A**************************************************************/
int

Conjunction (root)
NodeRec
**root;

/* root is a ptr to tree/subtree


/* currently working with

<CONJUNCTION>

/*

<NEGATION>

/\

<CONJUNCTION>)

int

flag;
if ((flag = Negation (root)
if (ByPass (ANDLOGJ
{

== TRUE)

MakeNewRoot root ANDLOG_, LEFT)


if (Con junction (S (*root) ->rptr)
ErrorHandler (line_no, ERR8,

/*

!=

TRUE)

return (ERROR

*/

/* Just

(long)

look for Negation part

/* will recursively check for


/* found, fix root for return
/*
w/o following Neg

note it,

no fix

/* end recursive

search

*/
*/

*/
*/

ANDLOGJ ;/*

>

return flag)
(

/*

end Con junction

/a*********************************************************************/
int

Negation (root)
NodeRec
"root;

/*

/*

85

root is a ptr to tree/subtree


currently working with

*/
*/

;) ;

<NEGATION>

I-

if (ByPass

(NEGLOGJ

<RELATION>
/* look for /* found a /* ~ w/o Relation. Just
/* note it, no fix

'root = CreateNode (NEGLOG_)


if (Relation (S (*root) ->rptr)
ErrorHandler (line_no, ERR8,
(long) NEGLOG_)
return (ERROR

TRUE)

*/
*/

note it

*/
*/

else

return (TRUE)
/* end if NEGLOG
/* just check for

return (Relation (root)

/*

*/

single relation */

end NEGATION

*/

********************************************************************** /
int
/* root is a ptr to tree/subtree
/* currently working with

Relation root
NodeRec
**root;
(

<RELATION> ::=
<SIMPLEXP>
<RELATORXSIMPLEXP>)
Where <RELATOR><SIMPLEXP> need not be present

/*
/*

*/

*/

*/
*/

int

flag,

/* type is

type;

if ((flag = SimplExp(root)

== TRUE)

if(argbind &S IBall (RTBRAKET_,


return flag)
else if (type = Relator

/*
/*
/*
/*
/*
/*

kind of relator found

looking for a Term.


Need to
look ahead for
due to poss
of having been called from
ArgBindO & ArgBindO looking
"
for " <QualExp><Op>
following first <Op>

*/

recursively check for more


RELATION'S
/* found one, fix root for return
/* RELATOR w/o SimpExp. Just note
/* note it, no fix

*/
*/
/
*/
*/

'

'

'

'

*/

*/
*/

*/
*/

/*
/*

MakeNewRoot (root type, LEFT)


if (SimplExp (& (*root) ->rptr)
ErrorHandler (line_no, ERR8,
,

!= TRUE)

(long) type)

return (ERROR_)
}

/* end recursive search

return flag)
(

/*

end RELATION

*/

1**********************************************************************1
int

Relator

()

>=
<=
=
<>
<
>
in
notin
<RELATOR> ::=
returns the Relator value vice TRUE if found
I

Note:
flag;

if (flag=ByPass (EQ_)
else
if (flag=ByPass
else
if (flag=ByPass
else
if (flag=ByPass
else
if (flag=ByPass
else
if
f lag=ByPass
else
if (flag=ByPass
else
if (flag=ByPass
(

/* do nothing

(NEQ_)
(LEQ_)
(GEQ_)

(KW_+IN_)
(KW_+NOTIN_)
(KW_+LESS_)
(KW_+GREATER_)
)

86

*/
*/

;;

))

/* return result
/* end Relator

return flag)
(

of search

*/
*/

/a*********************************************************************/
int
/* root is a ptr to tree/subtree
/* currently working with

SimplExp(root)
**root;
NodeRec

<TERM>

<SIMPLEXP>

<ADDOPXSIMPLEXP>)

*/

*/

flag,

int

/* type is

type;

(flag=Term(root) == TRUE)
if(argbind && IBall (RTBRAKET_,
return (flag)
if

*/
looking for a Term
Need to look ahead for
due */
to possibility of having been
called from ArgBindO and
/*ArgBind looking for <QualExp>
/* <0p> ']' following <0p>
/* recursively check for more
/* SIMPLEXP's
/* found AddOp, so fix root for
/* return
/* AddOp w/o SimpExp. Note it
/* note it, no fix

2)

else if (type=AddOp()

MakeNewRoot (root, type, LEFT)


if
{

(SimplExpU (*root) ->rptr) != TRUE)


ErrorHandler (line_no, ERR8,
)

*/

/*
/*
/*
/*

kind of relator found

(long) type)

return (ERROR_)
}

/* end recursive search

return flag)
(

/* end

SimplExp

/A****************************************************************/
int

AddOp

:=
"
<ADDOP>
+
Returns the AddOp value vice TRUE if found

/*
/*

*/
*/

flag;

int
if

else
else
else

lag=ByPass (ADD_)
if (flag=ByPass (SUB_)
if (flag=ByPass (COLONJ
if (flag=ByPass (CAT_)

/* do nothing

return flag)

/* return result of search


/* end AddOo

/a**************************************************
int

MulOp

()

:=
*
<MULOP>
%
(idiv)
/
Returns the MulOp value vice TRUE if found

/*
/*

flag;

int
if

(flag = ByPass (MULT_)

else
else

if
if

/* do nothing

(flag=ByPass (RDIV_)
(flag=ByPass (IDIV
)

87

*/
*/

;;

;;

; ;)

'

/* return result of
/* end Relator

return flag)
(

search

/
/

/it*********************************************************************/
int
Term (root)
NodeRec

/* root is a ptr to tree/subtree


/* currently working with

**root;

<FACTOR>

<TERM>

I-

int

flag,

<MULOPXTERM>
/* type

type;

if ((flag = Factor (root)

*/

*/

kind of relator found

is

*/

*/

/* looking for Factor


*/
/* Need to look ahead for ']
due */
/* to possibility of having been
*/

TRUE)

'

if(argbind &S IBall (RTBRAKET_,


return flag)
else if (type = MulOpO)

/* called from ArgBindO & ArgBind*/


/* looking for <QualExp> <0p>
*/
/* '] 'following <Op> ?
*/

MakeNewRoot (root, type, LEFT)


if (TermtS

/* will recursively look for


/* more TERM'
/* fnd MulOp, so fix root for

rtn */

/* MulOp w/o following Term.


/* note it, no fix

!= TRUE)
(*root) ->rptr)
ErrorHandler (line_no, ERR8,
(long) type)
return (ERROR_)
)

*/
*/
*/
*/

/* end recursive search

return flag)
(

/*

end Term

*/

/a***************************************************************/
int

Factor (root)
NodeRec

/* root is a ptr to tree/subtree


/* currently working with

**root;

<FACTOR>

*/
*/

-]<PRIMARY>

[+|

/* check for

'

or

if (status = ByPass (ADD_)


"root = CreateNode (POS_) ;
else if (status = ByPass (SUB_)

'root = CreateNode (NEG_)


if

/*

(status)
if (Primary

(*root) ->rptr) !=TRUE)


ErrorHandler (line_no, ERR8,
long) status)
return (ERROR_)

(S

found

'

+'

or

'

/* MulOp w/o following Term.


/* note it, no fix

else
return (TRUE)
else
return (Primary (root)

/* default, check
/* end FACTOR

for Primnary

/*****************************************************************/
int
/* root is a ptr to tree/subtree
/* currently working with

Primary root)
NodeRec
**root;
(

/*

<PRIMARY>

<APPLICATION> (!<PRIMARY>)

88

*/
*/

flag;

int

Application (root

if (flag =

looking for an Application


]'
Need to look ahead for
due to possibility of having
been called from Arg3ind()
and *ArgBind() looking for

/*

/*
/*
/*
/*

if(argbind &S IBall (RTBRAKET_,


return flag)
else if (ByPass (SUBSCRIPT^)

*/

'

'

'

'

*/

/* <QualExp><0p>
following
/* recursively look for next
/* Application
/* found one so fix tree
/*
w/o following Primary.
/* note it, no fix

MakeNewRoot root SUBSCRIPT_, LEFT)


Primary (S (*root) ->rptr)
if
ErrorHandler (line_no, ERR8,
(long)SUBSCRIPT_)
return (ERROR_)
(

*/

'

end recursive search

/*

return flag)
(

/* end Primary

()

a*********************************************************************
int
/* root is a ptr to tree/subtree
/* currently working with

Application (root
**root;
NodeRec

<APPLICATION>

/*

*/

*/

(<ACTUAL>)

flag;
*tnode;

int

NodeRec

/* temp pointer to

== TRUE)
if ((flag = Actual (root)
== TRUE)
if ((flag = Application (Stnode)

/* look
/* look

MakeNewRoot root ACTUALLIST, LEFT)


(root) ->rptr = tnode;
if ("root) ->rptr->name != ACTUALLIST)
MakeNewRoot (& (*root) ->rptr)
ACTUALLIST, LEFT)
(

node

for an actual
for an actual list

/*

fix tree so all Actual's


/* hang to LEFT */

/* end if (Application it node)


/* invalid ActualList
/* note it, no fix

-/

/* either valid ActualList or


/* just a single actual
/* return ERROR_ or FALSE,

*/

else if (flag == ERROR_)


ErrorHandler (line no, ERR k,NULL);

else return (TRUE)


return flag)
(

/*

based on first look


Application

/* end

*/
*/

*/
*/
*/
*/

A****************************************************************/
int

Actual root)
NodeRec

/* root is a ptr to tree/subtree


/* currently working with

**root;

<ACTUAL>

/*
/*

<ID> f ile<LITERAL> <CONDITIONAL> <BLOCK>


<DENOTATION> <COMPOUND> <ARGBINDING>
|

int
if

*/
*/

/* ptr to data struct holding the */


*/
/* actual value of ID, REAL, etc
*/
/* ptr to temp node in the tree

long
NodeRec

*/
*/

ptr;
'temp;
flag;

((ptr = ByPass (IDENTIFIER )))

/*

89

checking for ID

; ;

; ;
)

; ;

; ;

"root = CreateNode (IDENTIFIERJ


(root) ->index = ptr;
if (ByPass (LINERTARROW_)
{

MakeNewRoot (root, LINERTARROW_, LEFT)


== TRUE)
if (Actual (&( (root) ->rptr)
return (TRUE)
else
ErrorHandler line_no, ERR8,
(long) LINERTARROWJ
return (ERRORJ
)

/
/*
/
/
/
/

now look for ID -> ACTUAL


Note: "ID
-> ACTUAL" is a
I

<DENOTATION>
found one so fix tree
look for trail ACTUAL
note it,

no fix

/
/

end else not Actual


end if LINERTARROW

/*

end if ID

found keyword FILE

attach following LITERAL

/*

()

return (TRUE)

ByPass (KW_ + FILEJ


= CreateNode (KW_ + FILE_)
if ((ptr - ByPass (LITERAL_)
temp = CreateNode (LITERAL_)
temp ->index = ptr;
(root) ->rptr = temp;
return (TRUE)

if

root

else
ErrorHandler line_no, ERR_1, NULL)
return (ERROR_)
{

end if LITERAL_
note it, no fix

end if FILE

/
/
/
/
/
/

Phi is nondeterministic must


first check for compounds then
-> follows must see if the
if
compound was actually a fcrmaisV
list
Order may NOT be
NOTE:

/
/
/
/
/

had "l->" now need to see if


had Formals
set var to be passed by value
to IsFormals
just report it and press on

!= FALSE)
((flag = Conditional (root)
return flag)
if ((flag = Block (root)) != FALSE)
return flag)

if

if
if

((flag = Compound root


(

ByPass (LINERTARROWJ

temp

return (TRUE)

root;

IsFormal (temp)
ErrorHandler (line_no, ERR_o, NULL)
root) ->name = FORMAL;
MakeNewRoot (root, LINERTARROW_, LEFT)
== TRUE)
if (Actual (&( (root) ->rptr)
return (TRUE)
else
ErrorHandler (line_no, ERR8,
long) LINERTARROWJ
return (ERROR
if

changed

/
/

== TRUE)

else
{

/
/
/

/
/
/

found one so fix tree


look for trail ACTUAL
note it, no fix

/
else if (flag == ERROR
return (ERROR
)

90

end else ByPass LINERTARROW

/
/
/
/
/

if

((flag = Denotation (root)


return flag)

!=

FALSE)

!=

FALSE)

if

((flag '= ArgBinding(root)


return flag)
(

/* Default, tried everything else */


/* end Actual ()
*/

return (FALSE)
}

/a**************************************************************/

91

;)

*
PUBLIC DOMAIN SOFTWARE
*
parser pt 3
Name
*
* File
parser3 .c
*
* Authors
Maj E.J. COLE / Capt J.E. CONNELL
* Started
10/20/86
*
* Archived
12/11/86
*
* Modified
01/27/87 - Error Recovery added.
JC
************************************************************************
*
* This file contains the following modules for the PHI parser:
*
*
Conditional
Arm()
Compound
BlockO
*
*
Elements ()
Denotation
ArgBindO
opo
*
*
TypeFac ()
TypeExpO
TypeDomO
TypeTermO
*
*
TypePrimary
PrimType

*
*

Algorithm

See parser part

************************************************************************
*
* Modified
12/26/86 Flattened tree output changed to abstract
*
*
syntax tree form. JC
*
01/10/87 Corrections to comply with latest definitions *
:

*
JC
*
01/27/87 Error Recovery added and files combined. JC
***********************************************************************/

of the language.

*
*

include <stdio.h>
include <parser.h>
extern int

rtbrket;

extern int

line_no;

/* global flag - aids in


/* making PHI deterministic
/* global var, current line
/* number of program

*/
*/
*/
*/

/**********************************************************************/
int

Conditional root
NodeRec
**root;
(

/*

/*

<CONDITIONAL> ::= if <ARM> (elsif <ARM>)

/*

root is a ptr to tree/subtree


currently working with

(else<EXPRESSION)

/* ptrs to

NodeRec

*temp

NULL,

*subroot,

*/
*/

endif */

temp nodes in the tree

*/

'workingptr;

if (ByPass (KW_ + IF_)


if (Arm(Stemp) != TRUE)
(

IrrorHandler (line_no, ERR_m, (long) IF_)


'root = CreateNode (KW_ + IF_) ;
("root) ->lptr = temp;
workingptr = "root;
while (ByPass (KW_ + ELSIF_))
subroot = CreateNode (KW_ + ELSIF_)
workingptr ->rptr = subroot;
if (Arm(Stemp) != TRUE)
ErrorHandler (line_no, ERR_m,
(long)

/*
/*
/*
/*

note it, try to fix


set up root for return
attach THEN exp to root
move working ptr

*/
*/

*/
*/

/* attach ELSIF to tree

*/

/* note it, try

*/

&

fix

ELSIFJ

subroot ->lptr = temp;


workingptr = workingptr ->rptr;
}

if (ByPass KW_ + ELSE_)


(

92

/* attach THEN exp to ELSIF


/* move wrking ptr down subtree

*/

/* end while ELSIF

*/

*/

if (Expression (Stemp)

!=

; ;

TRUE)
/* note it,

ErrorHandler (line_no, ERR_m,

try

&

*/

fix

(long) ELSE_)

subroot = CreateNode (KW_ + ELSE_)


workingptr ->rptr = subroot;
subroot ->lptr = temp;
workingptr = workingptr ->rptr;

/* attach ELSE to tree


/* attach EXPRESSION to ELSE
/* move wrking ptr down subtree
/* end ELSE

if (ByPass(KW_

*/
*/

*/
*/

ENDIFJ

temp = CreateNode (KW_ + ENDIFJ


workingptr ->rptr = temp;

}else
{

ErrorHandler (line_no, ERR_n, NULL) ;


if (IBall(ENDIF_, 1) II IBall(ENDIF_,2)
Eatm(ENDIF_)

return (TRUE)
)

return (FALSE)

/* note it and try to fix /* will return TRUE regardless


/* look 2 ahead for the END

*/

/* end else not ByPass ENDIF_


/* saw an IF, any errors they
/* were already reported

*/
*/

/* end if IF
/* didn't see an IF
/* end Conditional

*/

*/
*/

*/
*/
*/

/**************************************************************/
int

Arm(root)
NodeRec

/* root is a ptr to tree/subtree


/* currently working with

**root;

<EXPRESSION>then<EXPRESSION>

<ARM> ::=

/*

*/
*/

*/

int

flag;

NodeRec *temp = NULL;

/* temp ptr to a node in tree

if ((flag = Expression (Stemp)

!= TRUE)

EatEm(KW_+THEN_)
if
{

(ByPass (KW_ + THEN_)


*root = CreateNode (KW_ + THEN_)
(root) -> lptr = temp;
if (Expression (Stemp) == TRUE)
(root) -> rptr = temp;
else
ErrorHandler line_no, ERR_m,
(long) THEN_)

*/

/* if an error try to recover by


*/
/* look for THEN, ELSE, ELSIF, ENDIF */

/*

report it and try to press on

*/

/* end begin if THEN


/* report it and try to press

else
ErrorHandler (line_no, ERR_f
(long)KW_+THEN_)
return (flag)

*/

on

/* end Arm()

*/

*/

/a********************************************************************/
int

Block (root)
NodeRec

/* root is a ptr to tree/subtree


/* currently working with

"root;

<BLOCK>

/*

begin <BLOCKBODY> end

::=

*/

*/

*/

if
{

(Bypass (KW_ + BEGIN_)


*root = CreateNode (KW_
if

(BlockBody

(S

BEGIN_)

(*root) ->lptr)

!=

TRUE)

93

/* sets root for return errors


/* have already been reported

*/
*/

for BLOCKBODY

*/

/* look

;;

;; ;

)
)

,
,

>

Error Handler (line_no, ERR_m,

/* note it,

(long) BEGIN_)
if (ByPass (KW_ + END_)
(*root) ->rptr = CreateNode (KW_
return (TRUE)

&

fix

END_

try

/* end bypass END


/* note it, no fix

ErrorHandler (line_no, ERR_f


(long) KW_+END_)
return (ERROR_)

/* end ByPass

BEGIN

return (FALSE)

;e

/* end BLOCK

/it*********************************************************************/
int

Compound (root
NodeRec
**root;

/*
/*

<COMPOUND>

/*

'< <ELEMENTS>
<ELEMENTS>
<ELEMENTS> }
where <ELEMENTS> may be empty */
)

(
'

'

root is a ptr to tree/subtree


currently working with

'

'

'

(LTPARENJ
Elements (root

*/
*/

'

'

'

'

'

if (ByPass
{

/* only look for elemt s because


/* errors reported via QualExp
/* note it, no fix

'

(! ByPass (RTPAREN_)
ErrorHandler (line_no, ERR_f

if

*/
*/
*/

(long)RTPAREN_)
root == NULL)
root = CreateNode (EMPTYCOMPOUND)
else if (*root) ->name == COMMA_)
(root) ->name = ELLIST;
return (TRUE)
if

(*

/* now check for empty compounds/ */


/* compounds w/ multiple elements */

/* end if

(LTSQUIGJ
Elements (root
!ByPass (RTSQUIGJ
if
ErrorHandler (line_no, ERR_f
(long)RTSQUIG

/*
/*

if (ByPass
(

LTPAREN)

only look for 'em,


errors reported via QualExp

if

/* note it,

(Toot == NULL)

root

no fix

CreateNode (EMPTYCOMPOUND)
else if ("root) ->name == COMMA_)
(root) ->name = ELLIST;
return (TRUE)
=

/* check for empty compounds and


*/
/* compounds w/ multiple elements */

/* end if LTSQUIG)

(ST_SEQUENCE_)
Elements (root
if
ByPass (END_SEQUENCE_)
ErrorHandler (line_no, ERR_f
(long) END SEQUENCE

if (3yPass
i

(Toot

*/

/* note it

*7

*/

&

no fix

NULL)
*root = CreateNode (EMPTYSEQUENCE)
else
MakeNewRoot (root SEQUENCE, RIGHT)
return (TRUE)
if

/* only look for 'em,


/* errors reported via QualExp

/* now check for empty sequences/ */


/* sequences w/ multiple elements */

/*

end ByPass ST_SEQUENCE_

/* none of the above


/* end CompoundO

return (FALSE)

/************************************yf*********************************/

94

; ;

;; ;;

int
/* root is a ptr to tree/subtree
/* currently working with

Elements (root)
**root;
NodeRec

<ELEMENTS> ::= <QUALEXP>

/*

<QUALEXP>)

flag;

int

if ((flag = QualExp(root)

== ERROR_)
/* errors already reported
/* recursively look for next
/* qualexp
/* found a COMMA so fix tree

EatEm(COMMA_)
while (ByPass (COMMA_)

MakeNewRoot (root, COMMA_, LEFT)


if (Elements (& ('root) ->rptr)
ErrorHandler (line_no, ERR_p,

!=

TRUE)
/* note it, try & fix
/* fix tree so all QualExp's

(long)COMMA_)
if

(*root) ->rptr->name != COMMA_)


MakeNewRoot (s
*root) ->rptr)
COMMA_, LEFT)
(

/* hang to the LEFT

/* end

while ByPass (COMMA_)

return flag)
(

/*

end Elements

**********************************************************************
int
/* root is a ptr to tree/subtree
/* currently working with

Denotation (root)
NodeRec
**root;

<LITERAL>
<CONSTANT>
<DENOTATION> ::=
<FORMALS> -> <ACTUAL>
where LITERAL is quoted ('
string of zero or more chars and
where CONSTANT is an integer or decimal number
NOTE:
<FORMALS> -> <ACTUAL>
was already checked by Actual ()

/*

*/
*/
*

*
*

*/

long

ptr;
if (ptr = ByPass (LITERAL_)
*root = CreateNode(LITERAL_)
(*root) ->index = ptr;
return (TRUE)
{

/* end a LITERAL

if
{

(ByPass (EMPT_LIT_)
*root = CreateNode(LITERAL_)
(root) ->index = NULL;
return (TRUE)
/* end a LITERAL

if (ptr =ByPass
(

(CONSTANTJ
"root = CreateNode(CONSTANT_)
(*root) ->index = ptr;

return (TRUE)
/*

return (FALSE)

end

CONSTANT

/* default,

none of the above

/* end Denotation

()

**********************************************************************
int

ArgBinding (root)
NodeRec
**root;

/*
/*

95

root is a ptr to tree/subtree


currently working with

*/
/

)
;

;;

,_

<ARGBINDING>

;;

(<OPXQUALEXP>

i
r
['

<QUALEXPXOP>

<0P>)

']'

int

NodeRec
extern

specialcase;
'temp = NULL;
argbind;
int

/*
/*

temp ptr to node in tree


global flag needed to make
/* PHI deterministic
/* set global flag, needed to
/* PHI deterministic.

if (ByPass (LTBRAKET_)
argbind = TRUE;
{

specialcase

IBall (ADD_,

1)

II

IBall (SUB_,

/
*/
*/
*/
*/

1 ))

DE3UG
tfifdef
print f "special case = %d argbind = %d\n", specialcase, argbind)
#endif
(

if
{

/*

(Op(root)
(ByPass (RTBRAKET_)
argbind = FALSE;
MakeNewRoot root ARGBINDOP, LEFT)

/*
/*

if
{

/*
/*
/*
/*
/*

return (TRUE)
1

MakeNewRoot root ARGLEADOP, LEFT)


,

if (IBall (ADD_,

specialcase
if

begin Op comes first


looking for [Op]
reset global flag

1)

II

IBall (SUB_,

= FALSE;

/*
/*
/*

(QualExpU (*root) ->rptr) ==TRUE)


)

if (ByPass (RTBRAKET_)

/*

had
<0p>
end if ByPass RTBRAKET_
don't have just an Op
might be +/- +/- QualExp
and don't want to accept
+/+/- QualExp Op later on
two cases where QualExp could
be TRUE
<Op><QualExp>
or + -<QualExp><Op>
reset global flag
could be +/- PRIMARY
(

/*
argbind = FALSE;
return (TRUE)
/*
else
if (specialcase && Op(Stemp)
SS ByPass (RTBRAKET_)
(*root) ->lptr) ->rptr= (*root) ->rpt r ;
/* now fix the tree
(root) ->rptr = temp;
(*root) ->lptr) ->name == ADD_) ?
(*root) ->lptr) ->name=POS_)
(*root) ->lptr) ->name = NEG_)
/* <0p> came last as a ","
(*root)-> name = ARGTRAILOP;
/* reset giobalflag
argbind = FALSE;
return (TRUE)
/* end else specialcase a Op
/* S& RTBRAKET_
/* end 2 cases where QualExp TRUE
/* reset giobalflag
argbind = FALSE;
/* report it, no fix
ErrorHandler (line_no, ERR_q, NULL)
return (ERROR_)
/* end Op comes first
/* found something
!= FALSE)
(QualExp(root)
MakeNewRoot (root ARGTRAILOP, LEFT)
/* reset global flag &
argbind = FALSE;
;

if (Op(& ('root) ->rptr)

ByPass (RTBRAKET_)
return (TRUE)
ErrorHandler (line_no, ERR_q,NULL)
return (ERROR
&&

/*

see if can continue

/* report

it,

no fix

/* end if QualExp comes first


/* end if ByPass LTBRAKET
/* default, none of the above
/* end ArgBindingO

return (FALSE)

it*************************************** it****************************int

96

Op(root)
NodeRec

);
;

/*
/*

"root;

<OP> ::=

/*

<RELATOR>

root is a ptr to tree/subtree


currently working with

<ADDOP>

<MULOP>

*/
*/

*/

flag;

int

if (flag = ByPass (COMMA_)

"root = CreateNode (COMMA_)

else if (flag = ByPass (SUBSCRIPT^)


'root = CreateNode (SUBSCRIPTJ
else if (flag = Relator ())
'root = CreateNode flag)
(

else if (flag = AddOp


*root = CreateNode flag)
(

else if (flag = MulOpO)


root = CreateNode (flag)

return flag)
(

/* end Op

*/

/A********************************************************************/
int
/* root is a ptr to tree/subtree
/* currently working with

TypeExp root
NodeRec
"root;
(

<TYPEDOM>

<TYPEEXP> ::=

/*

-> <TYPEEXP>

*/
*/

*/

)*

NodeRec

*newroot;

int

flag;

/*

== TRUE)
if ((flag = TypeDom(root)
if (ByPass (RTARROW_)
newroot = CreateNode (RTARROW_)
newroot ->lptr = 'root;

temp ptr to nodes in the tree

*/

/* will recursively search for


/* more TYPEEXP's
/* fix root for return

*/

/* end recursive search

*/

*/
*/

'root = newroot;
if (TypeExp (&( ('root) ->rptr)
{

!=

TRUE)

ErrorHandler (line_no, ERR9, (long) RTARROW_)


return (ERROR_)

return (flag)

/* end

TypeExp

*/

/a*******************************************************************/
int
/* root is a ptr to tree/subtree
/* currently working with

TypeDom (root
NodeRec
"root;

<TYPEDOM> ::=

/*

<TYPETERM>(+ <TYPEDOM>)

*/
*/

*/

NodeRec

'newroot;

int

flag;

/* temp ptr to nodes

== TRUE)
if ((flag = TypeTerm(root)
if (ByPass (ADD_)
newroot = CreateNode (TYPEPLUS)
newroot ->lptr = 'root;

in the tree

*/

/* will recursively search for


/* more TYPEDOM'
/* fix root for return

97

*/
*/
*/

;
;

;;

*root = newroot;
if
{

!= TRUE)
(TypeDomU (*root) ->rptr)
ErrorHandler (line no, ERR9, (long)ADDJ
)

return (ERROR_)
I

end recursive search

/*

*/

return (flag)
/* end

TypeDomO

*/

/it*******************************************************************/

mt
/* root is a ptr to tree/subtree
/* currently working with

TypeTerm (root)
NodeRec
**root;

<TYPEFAC>('*' <TYPETERM>)

<TYPETERM>

/'

NodeRec

*newroot;

int

flag;
if ((flag = TypeFac(root)
if (ByPass (MULT_)

*/

*/

/* temp ptr to nodes in the tree

*/

/* will recursively search for


/* more TiPETERMS's
/* fix root for return

*/
*/
*/

== TRUE)

newroot = CreateNode (TYPETIMES)


newroot ->lptr = *root;
*root = newroot;
!= TRUE)
if (TypeTerm(& (*root) ->rptr)
ErrorHandler (lineno, ERR9,
(long)MULT_)
return (ERROR

*/

/* end recursive search

return flag)
(

/* end TypeTerm

()

/************************************************************/

mt
TypeFac (root)
NodeRec
**root;

/* root is a ptr to tree/subtree


/* currently working with

:=
<TYPEFAC>
<TYPEPRIMARY>@
<TYPEPRIMARY>
<ID> '' <TYPEEXP> (,<TYPEEXP>) * '' <ACTUAL>
Where TYPEEXP TYPEEXP,
and/or <ACTUAL>
need not be present

/*
/*
/*
/*

NodeRec

newroot

int

flag;
ptr;

long

if (ptr = ByPass
(

/*

temp ptr to nodes in the tree

IDENTIFIER^

*root = CreateNode IDENTIFIERJ


(root) ->index = ptr;
(

4S ByPass (ST_SEQUENCE_)
ErrorHandler (lineno, ERR_r, NULL)
return (ERROR_)

if (ByPass (ST_SEQUENCE_)
{

/* end bypass

<<

goto CHECK;
/* end if

TypePrimary (root)
goto CHECK;
return flag)

if ((flag =

ID

== TRUE)
/* return either ERROR or FALSE

98

*/
*/

*/
*/
*/
*/

; ;

;;

)
)
)

;
)

;;

CHECK: if (ByPass (STARJ


newroot = CreateNode (STAR_
newroot ->lptr = (*root);
root = newroot;
{

/*
}

end if STAR

'/

/* made it this far,


/* end TypeFacO

return (TRUE)
}

ail OK

*/
*/

/a***********************************************************/
int
/*

TypePrimary (root)
"root;
NodeRec

/*

root is a ptr to tree/subtree


currently working with

'(' <TYPEEXP>
<TYPEPRIMARY> ::= <PRIMTYPE>
ID already checked in TYPEFACO

/*
/*

')'

*/

*/

*/
*/

NOTE:

if (ByPass (LTPARENJ
if (TypeExp(root)

!=

TRUE)
/* note

ErrorHandler (linejio, ERR9,

it,

no

f:

(long) LTPAREN_)
if (ByPass

(RTPARENJ

return (TRUE)
else
ErrorHandler (line_no, ERR_f,
(long)RTPAREN_)
return (ERROR_)
(

/* end ByPass

'

if (PrimType (root)
return (TRUE)
/* default
/* end TypePrimary

return (FALSE)

/a****************************************************************
int

PrimType (root)
NodeRec
**root;

<PRIMTYPE>

/*

:=

/* root is a ptr to tree/subtree


/* currently working with

real

integer

natural

boolean

trivial

if (ByPass (REAL_)
{

*root = CreateNode (REALJ


return (TRUE)
/* end if REAL

if (ByPass
{

(INTEGERJ

"root = CreateNode (INTEGERJ


return (TRUE)
/* end if INTEGER

if (ByPass (NATURALJ
Toot = CreateNode (NATURALJ
return (TRUE)
{

/*

if (ByPass
{

(BOOLEANJ

*root = CreateNode (BOOLEANJ

99

end if NATURAL

*/
*/

type */

;;

return (TRUE)
)

if (ByPass
{

(TRIVIALJ

/*

end if BOOLEAN

*/

/*

end if TRIVIAL

*/

*root = CreateNode (TRIVIALJ


return (TRUE)

if (ByPass (KW_ + TYPE_)


(

'root = CreateNode (KW_


return (TRUE)

TYPE_)
/* end if TYPE

return (FALSE)

/*
/*

default - none of the above


end PrimTypeO

*/
*/

*/

it********************************************************************/

100

/********** *************************************************************
PUBLIC DOMAIN SOFTWARE
* Name
Parser Ut ilities
* File
parsr_uti l.c
* Authors
Ma j E.J. COLE / Capt J.E. CONNELL
* Started
01/26/87
* Archived
03/03/87
*
* Modified
04/23/87 FillBufferO now calls GetTokenO direct.
*********** ************** ***********************************************
*
* This file contains the utility modules for the parser:
*
*
MakeNewRoot ()
ByPassO
CreateNode
*
*
IsFormaK)
IBallO
FillBuff ()
*
*
EnterNameO
FindNameO
NodeName

*********** *************************************************************
*
03/20/87 - Buffer Handling routines added - JC
Modified
*
*
FillBuferO calls GetTokenO direct vice
04/23/87
*
*
working with intermediate file of tokens
*
*
EnterNameO and FindNameO added to place
*
*
IDs, LITERALS, and CONSTANTS into the name
*
*
table.
JC

***********************************************************************
tinclude <stdio.h>
#include <parser.h>

extern

int

line_no;

/* global var, holds line no


/* of source prog

extern

FILE

*pinfile;

/*

char
NameRec

token [MAXLINE] ="x";


*nametable [TABLESIZE+
*EnterName ()

global working file

/*

*/

/*

*/

Init token [0] to value other


than NULL.
Token [0] holds the
/* length of the string.
/* add 1 because [0] is unusable

1]

*/
*/

/**********************************************************************/
/*
*/
UTILITIES
NodeRec *
CreateNode (op)
NodeType op;

/* operator type of node

/* Creates a tree node and returns the pointer (temp) to this node.
/* Accepts node type (op), an integer, and inserts it into the node.

*/
*/

NodeRec

*temp;

temp = C ALLOC (1, NodeRec)


temp -> name = op;
temp -> In = line_no;
temp -> lptr = (temp -> rptr)
return (temp)

/*

create

node

NULL;
/*

end CreateNode

()

*/

/A***************************************************************/
void
MakeNewRoot root type, side)
(

101

NodeRec

"root;

/* old root of subtree /* will turn into new root

int

type,

/*
/*

side;

(type)
(side)

is type of new root


is side to att old root

Creates a new working root for subtree.


Old root is attached to lt/rt based on value of (side)

/*
/*

*/
*/
*/
*/

*/
*/

*newroot;

NodeRec

newroot = CreateNode (type)


(side == LEFT) ?
(newroot ->lptr = *root)
"root = newroot;

(newroot ->rptr = "root);


/*

end MakeNewRoot

*/

/it*********************************************************************/
void
FillBuf (start)
long
*start;

/* which slot in the buffer


/* array to start the filling

/* Requires the buffer array and buffer ptr to be previously defined.


/* Fills the buffer with tokens by calling GetTokenO.
Buffer filled
/* until 1) end of user prog reached or 2) end of the array reached
/* If the token is a literal, id, or constant then EnterName
is
/* called to enter it into the nametable.
/* Lastly, resets the buffer ptr to tokenbuf f [0
(

*/
/

*/
*/
*/
*/
*/
*/

long tokenbuff[],
token_num;
*nptr;

extern
int
N'ameRec

*ptr;
/*

identifies a token type


structure of NameRec

*/
*/

intit ptr to travel thru buff

*/

/* ptr to
/*

ptr = start;
do

token_num = GetToken (token)


*ptr = token_num;

++ptr

switch (token_num)
case LITERAL_
case CONSTANT_
case IDENTIFIER_
token[0] = strlen (token)
if (nptr=EnterName (token)
*ptr = (long)nptr;
++ptr;
(

/* insert length of sting

*/

/* address of token

*/

else Error-Handler (NULL, ERR7, NULL)


break;
}

default:
)

while

ptr

(token_num != EOF)
&&
(ptr < Stokenbuff [BUFSIZE]

Stokenbuff

/*

HANDLE MEMORY OVERFLOW!

*/

/* end case
/* do nothing
/* end switch

*/

/* reset the buffer ptr


/* end FillBuffO

*/

*/
*/

))

[Oj

/a*********************************************************************/

102

)
;

long
ByPass (tgt)
tgt;

int

Checks to see if the next token in the buffer matches the target.
If so, then returns the token no. and increments the buffer
pointer

/*
/*
/*

*/
*/
*/

long

extern

tokenbuff[],

*ptr;

if(ptr >= Stokenbuf f [BUFSIZE]


FillBuff (itokenbuff [0]
)

/* see if at end of buffer


/* refill buffer

*/
*/

/*

*/

while (*ptr == EOLN_)


++ptr;
++line_no;
if(ptr == Stokenbuf f [BUFSIZE]
FillBuff (itokenbuff [0]

increment counter

/* end

(*ptr

skip

/* see if at end of buff


/* refill buffer

if

while

*/
*/
*/

!= tgt)

return (FALSE)
/* otherwise,

++ptr;
if (ptr == Stokenbuf f [BUFSIZE]

FillBuff (itokenbuff
switch (tgt)
case LITERAL_
case IDENTIFIER
case CONSTANT_
return (* (ptr++)

[0])

it

was found

*/

/* if at end of buffer
/* refill buffer

*/

/* return ptr to struct


/* holding the token

*/
*/

/*

*/

*/

default:
return (tgt)

just return true

/* end swithch
/* end ByPass

*/
*/

/a********************************************************************/
int

IsFormal (root
NodeRec
*root;

/*
/*

root is ptr to subtree


currently working with

/* Required to make the language deterministic. Compound


returned
/* TRUE and " ->" was subsquently found. Formal is a proper subset of
/* the compounds so need to insure no errors in the f ormals
/* Performs a preorder search of the subtree. NOTE: assumes that root
/* initially points to a non-null compound list.
(

#ifdef
DEBUG
printf "isf ormal entered, root->name = %d\n", root->name)
if (root == NULL) printf ("root is null\n");
#endif
(

if (root == NULL)
return (TRUE)
if (root->name==COMMA_

II
I

root->name==IDENTIFIER_
root->name==ELLIST)

103

*/
*

*/
*/
*/
*/
*/

if

; ;

);

))

Is Formal (root->iptr)
ii
IsFormal (root->rptr
(

return (TRUE)

return (FALSE)
/* end

Isformal

*/

/*******************************************************************/
ir.t

Ball (tgt, index)


tgt, index;
int
/* Checks to see if the (index) th token in the
/* target.
If it does returns TRUE else FALSE.

buffer matches the


Does not increment
the buffer pointer.
Checks for full buffer implemented in this
manner to allow for future flexibility. Could have used simple
heuristic of:
if(ptr + (3*index) > Stokenbuf f [BUFSIZE]
Ref ilBuf fer
at the expense of generality

/*
/*
/*
/*
/*

tokenbuff[],
long
*tptr;

extern
long

*/
*/
*/
*/
*/
*/
*/

*ptr;

if(ptr >= Stokenbuff [BUFSIZE]


FillBuf f (Stokenbuf f [0]
)

DO_AGAIN:
tptr = ptr;

/* see if at end of buff if


/* so, refill buffer

*/
*/

/* start over if had to refill


/* buffer during check for tgt
/* set working pointer

*/
*/
*/

while (*tptr == EOLN_)


{

increment tptr

++tptr;

/*

if (tptr == Stokenbuf f [BUFSIZE]

/* see if at end of buff


/* nedd to refill buffer and
/* then start over

goto REFIL;

/* end while
/* only enter

for (/index >1; --index)


switch (*tptr)

/*

case IDENTIFIER_:
case CONSTANT_:
case LITERAL_:
tptr +=

/*
/*
2;

*/

for loop if need to */

look more than one char ahead


double skip because next
entry is addr of element

/* increment counter

/*
/*

*/
*/
*/

refill buffer
end while

skip

start over

*/
*/
*/

++tptr;
/* end switch
/* check if will overflow buff

if (tptr

*/
*/
*/
*/

break;

case EOLN_:
while (*tptr == EOLN_)
++tptr;
if (ptr == Stokenbuf f [BUFSIZE]
goto REFIL;
default:

skip EOLNs

&

>= Stokenbuf f [BUFSIZE]

*/
*/

goto REFIL;
/*

*/

end for

(*tptr != tgt) return (FALSE)


else
return (TRUE)
if

/* take what's left in buffer,


/* put at beginning, now refil
/* rest of buffer

REFIL:

for (tptr = Stokenbuf f [0]


ptr < Stokenbuf f [BUFSIZE]
*tptr = *ptr;
FillBuf f (tptr)

pt r *+ tpt r + +
,

*/

/* refill buffer
/* posit to end

104

*/
*/

from current

*/
*/

/* refilled buffer,
/* over

goto DO_AGAIN;

/* end

IBall

so start

*/
*/
*/

()

/******************************************************************/
char *
NodeName (ptr)
NodeRec
*ptr;
/* Accepts a ptr to a structure of NodeRec.
Dereferences this node
/* to get a ptr to structure of NameRec which hold the string
/* containing the name of the value in NodeRec. Returns the name to
/* calling routine

*/
*/
*/
*/

NameRec

/* temp ptr to data struct


/* holding name of "*ptr"

*temp;

*/
*/

temp = (NameRec *) (pt r->index)


return (temp->name + 1)
/* end

NodeName

()

*/

/****************************************************************/

105

APPENDIX

ROCK COMPILER

ERROR HANDLER

/*********** ************************************************************
*
PUBLIC DOMAIN SOFTWARE
*
* Name
Error Handler
*
* File
errors
*
* Authors
Maj E.J. COLE / Capt J.E. CONNELL
*
* Started
01/20/87
*
* Archived
04/07/87
*

Modified
************ ************************************************************
* This file contains the execution modules for error recovery.
*
ErrorHandler ()
EatEmO
*

<

ErrorHandler
is called by other modules in the
compiler.
It insures the error count is updated and
*
the* error is written to the error file.
If required,
*
ErrorHandler
calls EatEmO to gobble tokens to get to
the parse.
a known point in
Used during error
*
After MAXERRORS number of errors simply
recovery.
*
returns to calling routine.
* NOTE
'errorfile' must have been initially created before
*
ErrorHandler
is first called - don't want to append
*
to last times errors!
************ ***********************************************************
* Modified
*

Algorithm

( )

***********************************************************************
^include
#include
#include
extern

<stdio.h>
<scanner.h>
<errors.h>
FILE
*errorfile;

int

nil

m errors =

errors

/*

working file

/*
/*
/*

running talley of # eroi


found - global var
array of error messages

incomplete '!->'",
RESERVED FOR FUTURE USE"
without following '/
logical OR is \\/
"$' without following 'R' 'N' 'Z' 'B',or 1'"/
> ",
'invalid numeric constant
- ",
'literal without ending
'unidentified char in input program ==> ",
'MEMORY OVERFLOW DURING COMPILATION",
'error in statement following ==> ",
'error in type definition following ==> ",
'unable to complete definition of blockbody after keyword
'missing or misplaced ';' after definition",
'valid qualexp/exp not found in the def/auxdef",
'

"W

106

"valid typeexp not found in the def",


"formals list missing or error in formals list",
"misplaced or missing ",
"at least one identifier must follow keyword TYPE",
"unable to complete def/auxdef following keyword AND",
"missing or invalid auxdef after keyword WHERE",
"missing or misplaced closing paren in formals list",
"error in processing multiple Actuals",
"missing literal after keyword FILE",
"missing or invalid exp following KEYWORD ",
"IF statement w/o ENDIF",
"error in formals preceding | >",
"missing or invalid QualExp following COMMA operator",
"error in ArgBinding - check QualExp or closing bracket",
"OZONE LEVEL I - for 19.99 the feature can be implemented in 1999'

/* d */
/* e */
/* f */
/* g */
/* h */
/*

*/

"

/* J
/* k */
/* 1 */
/* m */
/* n */
/* o */
/* p */
/* q */
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*

*/

*/
*/
u */
v */
w */
s

x*/
y

*/

NUMERIC VALUE EXPECTED ",


NATURAL EXPECTED ",
INTEGER OR NATURAL EXPECTED ",
ERROR IN TUPLE DEFINITION ",
UNDEFINED VARIABLE IN AND SCOPE ",
FUNCTION WITHOUT FUNCTION DEFINITION ",
FORMALS MISMATCHED ",
FUNCTION CALLED WITHOUT FUNCTION DEFINITION
REAL NUMBER EXPECTED ",
INVALID CONSTANT EXPRESSION ",
BOOLEAN VALUE EXPECTED ",
BOOLEAN OPERATOR EXPECTED ",
OUT OF RUN-TIME MEMORY SPACE ",

aa */
bb */
cc */

dd */
ee */
ff

*/

gg */
hh */
*/
*/
kk */
11 */
mm */

ii
jj

******** **************************************************************/

void
ErrorHandler (line_no,err_no, str_num)
int
line_no, err_no;
long
str_num;

use long because str_num is either pointer to a string "long"


or an actual number (int or long)

/*
/*
{

DEBUG
fifdef
printf("eh entered, err#
#endif
if

(++num_errors

errorfiie
if
{

f open

>

= %d,

str_num = %ld\n", err_no, str_num)

MAXERRORS)

return;

("errors .phi", "a")

(err_no == ERR7)
fprintf (errorfiie, "%s\n", errors [err_no]
user err
(

107

/*

append to what's there

/*

no more memory get out and start over

/*

*/
*/

;
; ;

; ; ; ;

execl "rock .exe", "rock .exe", NULL)


(

/*

%s
fprintf (errorf ile, "line %3d
line_no, errors [err_no]

end if no more memory

",

switch (err_no)

case ERR4:
case ERR5:

fprintf (errorf ile, "%s\n", (char

case ERR6:

fprintf (error file, "%. ls\n", (char *)str_num); break;

case ERR8:
switch (str
case LEQ_
case NEQ_
case GEQ_
case EQ_
case ADD_
case SUB_
case MULT
case IDIV
case RDIV_
case SUBSCRIPT
case ORLOG_
case ANDLOG
case NEGLOG
case COLON_
case CAT_
case LINERTARROW_:
case (KW_+GREATER_)
case (KW_+IN_)
case (KW_+LESS_)
case (KW_+NOTIN_
default
fprintf (errorfile,
(

*)

str_num)

break;

num)

fprintf
fprintf
fprintf
fprintf
fprintf
fprintf
fprintf
fprintf
fprintf
fprintf
fprintf
fprintf
fprintf
fprintf
fprintf
fprintf
fprintf
fprintf
fprintf
fprintf

(error file,
(error file,
(error file,
(error file,
(error file,
(error file,
(error file,
(error file,
(error file,
(error file,
(error file,
(error file,
(error file,
(error file,
(error file,
(error file,
(error file,
(error file,
(error file,
(error file.

<=\n'
*<>\n'
>=\n'
=\n")
+\n")
-\n")

*\n'
'%\n'

An'
!\n'

'\\/\:

AWn'
'~\n'

:\n")
"\n"]
'

->\n")

GREATER\n"
*IN\n")

LESS\n")
'NOTINXn")

break
break
break
break
break
break
break
break
break
break
break
break
break
break
break
break
break
break
break
break

UNDEFINED error\n")
/* end

switch case ERR8

break;

switch (str_num)
:RR9:
case ADD_
fprintf (errorf ile, "+\n")
case MULT_
fprintf (errorf ile, "*\n")
case RTARROW
fprintf (errorfile, "->\n")
case LTPAREN
fprintf (errorf ile, " (\n")
default:
fprintf (errorfile, "UNDEFINED error\n"

break;
break;
break;
break;

/* end

switch case ERR9

break;

switch str_num)
case KW_+AND_:
case KW_+WHERE_:
fprintf (errorfile, "==\n
break;
case RTPAREN_:
fprintf (errorfile, ") \n"
str_num=NULL; break;
case RTSQUIG_:
fprintf (errorfile, " }\n"
str_num=NULL; break;
case END_SEQUENCE_:
fprintf (errorfile, ">\n"
str num=NULL; break;

:ase ERR_f

/*

don't want to go to EatEm

/*

don't want to go to EatEm

/* don't want to go to

108

EatEm

case KW_+END_:
fprintf (errorfile, "KEYWORD END\n")
str_num += KW_; break;
case KW_+THEN_:
fprintf (errorfile, "KEYWORD THEN\n")
break;

/*

set up for call toEatEm

*/

/*

end switch case ERR_f

*/

/*

end switch case ERR_m

*/

/*
/*

set str_num up to be passed


to EatEmO

*/
*/

/*

end switch

*/

/*

end ErrorHandler

*/

default
fprintf (errorfile, "UNDEFINED error\n")

break;

case ERR_m: switch str_num)


case IF_
break;
fprintf (errorfile, "IF\n")
case ELSIF_
break;
fprintf (errorfile, "ELSIFXn")
case ELSE_
break;
fprintf (errorfile, "ELSEXn")
case THEN_
break;
fprintf (errorfile, "THENXn")
case BEGIN_
break;
fprintf (errorfile, "BEGINXn") ;
default
fprintf (errorfile, "UNDEFINED errorXn")
(

str_num += KW_;
break;
default:
fprintf (errorfile,

"

\n")

f close

if

(errorfile)

(err_no >= ERR_a) 4S


(err_no < ERR_aa) &S
(str_num != NULL)
Eat Em (int str_num)
(

/*******************************************************
void
EatEm (tgt)
int tgt;

/* Increments token buffer pointer until tgt token is found.


/* Use in error recovery to reach a known point in the program.
{

extern
extern

tokenbuf f
line_no;

long
int

#ifdef
DEBUG
print f "eatem entered, tgt
#endif
(

*ptr;

%d\n",tgt);

while Cptr != EOF_)


switch (tgt)
case E0LN_
++ptr;
++line_no;
{

case SEMI_
if (*ptr==SEMI

break;

||

(*ptr==KW +LET

109

))

*/
*/

return;
break;

-Dtr;

switch

case EQUIV
case EQUIV_
case SEMI_
case KW_+AND_
case KW_+LET_
default
break;

(int) *ptr)

return;
++ptr;

case KW_+WHERE_
case KW_+WKERE_
case KW_+AND_
case KW_+LET_
case SEMI_
default
break;

switch

case KW +AND
case KW_+AND_
case KW_+LET
case SEMI_
default
break;

switch

case RTPAREN_
case RTPAREN_
case LTPAREN_
case COMMA_
case EQUIV_
case LINERTARROW
case KW_+LET_
case KW_+AND_
case SEMI_
default
break;

switch ((int)*ptr)

/*

end switch case EQUIV

/*

end switch case WHERE

((int)*ptr)

return;
++ptr;

((int)*ptr)

return;
++ptr;
/* end switch case AND

return;
++ptr;
/* end

case KW
case KW
case KW
case KW
case
case
case
case
{

_+

switch case RTPAREN

IF_

ELSIF_
_+ ELSE_
_+ THEN_
KW_+ ELSIF
KW_+ ELSE_
KW_+ ENDIF
KW + THEN
_+

switch (int) *ptr


(

return;
/* end switch case THEN,

++ptr

break;

case COMMA_
case COMMA_
case LTPAREN_
case RTPAREN_
case LTSQUIG_
case RTSQUIG_
case ST_SEQUENCE_
case END_SEQUENCE_
case SEMI_
case KW_+LET_
case KW_+WHERE_
case KW_+ AND_
default

switch

(int) *ptr)

return;
++ptr;

110

*/

break;

case KW_+END_
case KW_+BEGIN_
case KW_+END_
case KW_+LET_
case KW_+WHERE_
case KW_^AND_
case COMMA_
case RTPAREN_
case RTSQUIG_
case END_SEQUENCE_
case SEMI_
default
break;

switch

/*

end switch case COMMA

/*

end switch case BEGIN/END

(int) *ptr)

return;
++ptr;

default
return;
:

end swithch
end while
/* end EatEmO
/*
/*

'

* * *

*/
*/
*/

******************************** a*******************************/

111

APPENDIX

SEMANTIC CHECKER

ROCK COMPILER

/A*******************************************************************
*
PUBLIC DOMAIN SOFTWARE

Semantic Checker Module


SemO.c
Maj E.J. COLE / Capt J.E. CONNELL
02/01/87
04/03/87

Name
File
Authors
Started
Archived
Modified

This file contains the following modules for the PHI parser:

*
*

*
*

*
*
*
*

*
*

Hnumconvert

Numconvert

*
*

*
Algorithm
*
*
This module contains procedures for type conversion.
If the
* rt child of a node may be converted to the It type but the con*
* verse is not true,
*
"Hnumconvert" is called.
If either side may be
*
* converted,
"numberconvert" is called
A************************************************************
*
* Modified
a****************************************************************/
*

/it**************************** Externals ****************************/


#include <semcheck.h>

extern void terror

();

/********************** hnumconvert *****************************/


PHITYPE
hnumconvert

rtype,

(ltype,

ptr)

PHITYPE ltype, rtype;


nodal ptr;
{extern void c_ztor ();

if

((ltype == BOOLEAN)
return (BOOLEAN);

switch (ltype)
case (REAL)

S&

switch (rtype)

case (REAL)
return
case (INTEGER)
case (NATURAL)
c_ztor
return (REAL)
default
:

*/

/* No type conversion needed

*/

*/
*/
*/
*/
*7

(rtype == BOOLEAN))

/* Predicate actions on type of


/* side of node

/* Type conversions for the


/* right side of the tree only
/* Left and Right types
/* Ptr to the root working with
/* Generates code to convert
/* integer/natural to real

(REAL);

It*/
*/

/*

Matching types; no conv req

*/

/*

Generate code for conversion

*/

112

terror
return

; ; ;

(ERR_aa,
(REAL)

;;

; ;;

/* No appropriate match; error


*/
/* Rtn real so semantic check con:*/

ptr->ln)

switch (rtype)
case (INTEGER)
case (INTEGER)
return (rtype);
case (NATURAL)
default
terror (ERR_cc, ptr->in)
return (INTEGER);
:

/*

Matching types, no

cor.v

req

*/

case

(NATURAL)
(rtype == NATURAL)
return (rtype)

/* Can't

convert from real to int */


*/
programmer

/* so sandbag the

if

else
terror
return

/* Only one match poss w/o error

(ERR_bb, ptr->ln)
(NATURAL)

default
terror (ERR_aa, ptr->ln)
return (NATURAL)
:

/************************ Numconvert ****************************/


PHITYPE
numconvert (ptr)

/* Do number conversions for


/* both left and right side

nodal ptr;
{PHITYPE ltype, rtype;
extern PHITYPE semcheck
extern void c_ztor ();
ltype = semcheck

/*

(ptr->lptr);

/* Get

(ptr->rptr->name == KW_ + ENDIF_)


return (ltype)
rtype = semcheck (ptr->rptr);
if

if

Left and right child types

();

((ltype == BOOLEAN)
return (BOOLEAN)

ii

(rtype == BOOLEAN))

switch (ltype)
case (REAL)
switch (rtype)
case (REAL)
return (REAL)
case (INTEGER)
case (NATURAL)
c_ztor
return (REAL)
default
terror (ERR_aa, ptr->rptr->ln)
return (REAL)
{

left type

/* Special case of
/* Get
/* No

/*

"if" sequence

right type

conversion necessary

Predicate actions on It type

/* Types are same;

no action req

/*

Generate code for int/nat


conversion

/* to real
/* No

converison possible

case (NATURAL)
switch (rtype)
case (REAL)
c_ztor
return (REAL)
case (INTEGER)
return (INTEGER)
case (NATURAL)
return (NATURAL)
default
terror (ERR_aa, ptr->rptr->ln)
return (NATURAL)
:

/*

Convert left side

/* No

conversion necessary

/* No

conversion necessary

113

*/

case (INTEGER)
switch (rtype)
case (REAL)
c_ztor
return (REAL)
case (INTEGER)
case (NATURAL)
return (INTEGER);
default
terror (ERR_aa, ptr->rptr->ln)
return (NATURAL)
:

/* Convert

left side

/* No conversion necessary

default
terror
return
:

(ERR_aa, pt r->lptr->in)
(NATURAL) ;

114

/* Types are not

numeric

;;

/**********************************************************************
*
PUBLIC DOMAIN SOFTWARE

Semcheck Module 1
Name
* File
Semi
* Authors
Maj
E.J. COLE / Capt J.E. CONNELL
* Started
01/02/87
* Archived
01/10/87
* Modified
***********************************************************************
* This file contains the following modules for the PHI parser:
*
*

Tletdef
Twhere
Tandcheck

Trtarrow
Tdataauxdef
Tauxand

Tkindef
Tauxand
Ttypetimes

*
*
*

*
*

Algorithm

This module contains scoping procedures (Twhere and Tauxand)


definition procedures (trtarrow, tkindef, ttypetimes) and the data
definition procedure.

*
*

*
:

*
*
*

***********************************************************************
*
* Modified
a*********************************************************************/
:

/****************************** Externals ****************************/


finclude <semcheck.h>
include <string.h>
extern int typeptr;
extern tnode types
extern void terror

/* For "strcpy"

/* Typetable and pointer


[];
();

fnode *fhead = NULL;

/************************* Tletdef ******************************/


void
tletdef (ptr)
nodal ptr;

/* checks types of both branches

semcheck
semcheck

(ptr->lptr);
(ptr->rptr);

/*********************** Trtarrow *****************************/


PHITYPE
trtarrow (ptr)
nodai ptr;
(PHITYPE ltype, rtype;
extern void putform ();

/*

ltype = semcheck (ptr->lptr)


rtype = semcheck (ptr->rptr)

(ptr->lptr->name == TYPETIMES)
(ptr->lptr->name == TYPEPLUS)
putform (ltype);
if

return

Returns type

/* Check left side type


/* Check right side type
II

/*

(rtype)

115

Only if leftnode not

'*'

or

;;

;;

/a************************ Tkindef ******************************/


void
tkindef (ptr)
nodal ptr;
(extern defptr defhead;
extern void putdef
PHITYPE rtype;
(

/* Adds

variable name to defstac< */

rtype = semcheck (ptr->rptr)


putdef (rtype, ptr->lptr)
def head->fptr = fhead;
fhead = NULL;

/* Put definition in defstack


/* Append formal types to entry
/* Kill

fhead

*/
*/
*/

/it***********************

it******************************/

t where

PHITYPE
twhere (ptr)
nodal ptr;
(PHITYPE type;

semchecker (ptr->lptr)
type = semchecker (ptr->rptr);
return (type)

/* Semcheck where node

*/

/* Check leftside
/* Check right side

*/
*/

/************************ TDatauxdef ****************************/


void
tdatauxdef (ptr)
nodal ptr;
(extern void c_store_code (),
extern PHITYPE getdtype ();
extern defptr finddef ();
extern char 'name ();
defptr d_ptr;
char
'holder = malloc (8),
*nme = malloc (8) ;
PHITYPE rtype,

c_jmp

/* WORKS FOR ONE FORMALS ONLY

*/

/* Temp holder

*/

();

type,
count = 0;

for function name

/* Type of left and right nodes


/* Type of datadef

*/
*/

/* Calculate function name


/* Gen code for starting proc
/* Get type of right ptr

*/
*/
*/

/* Open can of worms to


/* if left is ident.
/* No prev decl of this

*/
*/

nme = strcpy (nme, name ());


c_jmp (nme)

holder = strcpy (holder, named


c_start_proc (holder);
rtype = semcheck (ptr->rpt r)
if

(ptr->lptr->name == IDENTIFIER_)
if

(d_ptr=f inddef (ptr->lptr->index)


ptr->lptr->type = rtype;
putvar (rtype, ptr->lptr)

typecheck */
variable

else if (d_ptr->fptr == NULL)


ptr->lptr->type = getdtype (d_ptr)
type = hnumconvert (ptr->lptr->type,
(

rtype,

putvar

ptr)
(type,

/* Prev decl of var

/* Convert

rt type

is

if

data def

feasible

*/

*/

ptr->lptr)

else
terror

/*

(ERR_dd,

ptr->lpt r->ln

116

Prev decl of var is another var*/

;;

while ('(holder

count)

(ptr->lptr->label
++count;
c

store code

; ;

!= NULL)
=

[count!)

/* Push piano through the door


/* to copy strings

(*

(holder

count));

/* Generate code to end procedure */


/* CANNOT USE C_END_?ROC () HERE; */
/* NO SCOPE CHANGE!
*/

("ret\n");

c~store~code (nme)
c

store code

*/
*/

(":\n");

/it************************* And Check *****************************/


void
and_check (mark, ptr, mark_and)
varptr mark;
and_ptr *mark_and, ptr;
{extern varptr varhead;
extern int buff_ptr;
extern char *code_buf fer;
int buf f_holder
varptr v_ptr = varhead;
if

(ptr

!=

NULL)
(mark,
{

and_check
do

ptr->link, mark_and)

/* Check and_list for var defs


/* Scope delimiter

*/
*/

/* Ptr = NULL is base for recurs


/* of and_check
/* Loop to evaluate all proper
/* varptr entries
/* Check if equal names in

*/
*/
*/

/* and_list & var_list


/* Not a function definition

*/
*/

/* Save code buffer pointer


/* Get location of variable code
/* Generate code
/* Restore buffer pointer

*/
*/

*/
*/

if (v_ptr->nptr->index==ptr->ptr->index)

buff_holder = buff_ptr;
buff_ptr = ptr->buf f ptr
c_call_proc (v_ptr->nptr->label)
buff_ptr = buf f_holder
(*mark_and == ptr)
*mark_and = ptr->link;

/*

if

Traverse list

*/
*/
*/

del_and (ptr)
break;

(v_ptr == mark)

if

/* End of var list

break;

v_ptr = v_ptr->link;
while (TRUE)

reached

/* Exit is accomplished using a


/* break in the loop

*/

*/
*/

/it**************************** Tauxand ******************************/


void
tauxand (ptr)
nodal ptr;
'extern FLAG and_flag;
extern and_ptr and_head;
int save_and;
varptr mark;
and_ptr tptr, mark_and = and_head;

save_and

/*

Semantic check for and node

*/

*/
/* Holder for and flag
*/
/* Mark top entry in the varlist
/* Mark current head of and_stack */

and_flag;

/* Save current
/* Set and flag

ar.d_fiag = TRUE;

117

and_flag

*/
*/

; ;

/* Semantic Check

semcheck (ptr->lptr)
mark = varhead;
semcheck (ptr->rptr)
and check

and_flag

(mark,
=

and_head,

&mark_and)

/*

*/

Check all new fctn

data defs */

/* Restore and flag

save_and;

*/

tptr = and_head;

while (tptr != NULL)


tptr = tptr->link;

/*

Traverse list until end

*/

if (mark_and != and_head)
terror (ERR_ee, ptr->ln)

/*

Undefine variables found

*/

/it***************************** TTvpe Times ***************************/


PHITYPE
ttypetimes (ptr)
nodal ptr;
{extern void putform
PHITYPE type;

/* Semantic check
/* for types

when used

*/
*/

() ;

putform (semcheck (ptr->lptr


if

'*'

(type = semcheck

(ptr->rptr)

/* Attach formal type to


/* formal list

/* Look for right type;


/* end of insertions

*/

if 0,

*/
*/

putform (type)
return

/*

(NULL)

Always return NULL;


value is used by parent

/* This

118

*/
*/

PUBLIC DOMAIN SOFTWARE

*
*

*
Semcheck Module 2
Name
*
* File
Sem2.c
* Authors
*
Maj E.J. COLE / Capt J.E. CONNELL
*
* Started
01/02/87
*
* Archived
04/10/87
*
* Modified
a****************************************************************
* This file contains the following modules for the PHI parser:
*
*

Tfunauxdef
Tid

Matchfor
Tactualist
Telist

*
*
*

Tfunid
Act_Walk

*
*
*

*
Algorithm
*
This module contains the procedures needed to define and call
functions. Tfunauxdef will set up the run-time structure of the fun-*
ction, tfunid will check the semantics of the function, & matchfor, *
called by tfunid, checks for the proper type & number of formal pa- *
*
rameters
Tactualist coordinates the checking of a function call.
It uses *
*
both telist and act_walk. Actwalk determines whether the number &
type of actuals is correct, and telist checks each element list and *
*
returns its type.
*
Tid performs semantic checking for program variables.

*
*
*
*

*
*
*
*
*

*
Modified
**********************************************************************/

/a************************* Externals it*******************************/


#include < semcheck h>
#include <string.h>
.

/* For

extern tnode types


;
extern varptr varhead;
extern void terror (), c_store_code
[

"strcpy"

*/

();

/a*************************** Globals ********************************/


int actual_count = 0;

/* count of all actuals

*/

/it************************** Matchfor *******************************/


FLAG
matchfor

(nptr,

def)

nodal nptr;
defptr def;
{extern long curr_addr;
extern fnode *getfptr
extern FLAG form;
fnode *tptr = getfptr

/* Match formals
/* Called by tfunid () only
/* Ptr to rt side of funid node
/* Ptr to var table for fur.c name

*/

/* Flag set when formals


/* are generated

*/
*/

*/
*/
*/

();

(def)

form = TRUE;
tptr = def->fptr;
curr addr =0;

119

;;

;;

(nptr->name == IDENTIFIER_)
(nptr->type) = tptr->type;
nptr->addr = curr_addr;
putvar (tptr->type, nptr)
nptr = nptr->rptr;
tptr = tptr->link;

else

/* Only one formal

/*

do

Multiple formals

nptr->lptr->type = tptr->type;
nptr->lptr->addr = curr_addr;
curr_addr = curr_addr +
types [tptr->type] .bytes;
putvar (tptr->type, nptr->lptr)
nptr = nptr->rptr;
tptr = tptr->link;
while (nptr !=NULL) &S (tptr !=NULL)
(

/* Halt when end


/* by either ptr

reacned

form = FALSE;
if

(nptr

!=

return

NULL

tptr

/* One ptr isn't at end of run


/* Error handled in calling fctn

!= NULL)

(FALSE)

else return

*/
*/

(TRUE)

/******************* Tf unauxdef *******************************/


void
tfunauxdef (ptr)
nodal ptr;
(extern long curr_addr;
extern void c_end_proc (), c_jmp
extern char "name ();
extern nodal hnumconvert {);
char *nme = malloc (8);
PHITYPE ltype, rtype;
varptr varl, mark = varhead;
long pres_addr = curr_addr;

nme = strcpy (nme, name


c_ jmp (nme)

ltype = semcheck
rtype = semcheck

/* Type check

funauxdef

();

/* Name for jump around function


/* Gen code to jump around fctn

());

*/

/* Eliminate formals from Ink 1st /

ptr->rptr =
hnumconvert (ltype,
c end proc (nme)
=

*/

(ptr->lptr)
(ptr->rptr)

while (varhead->link != mark)


varl = varhead;
varhead = varhead->link;
varl->link = NULL;
free (varl) ;

curr_addr

*/

Convert if needed

rtype,

ptr->rptr)

/* Reset addresses

pres_addr;

120

;;

/a***************************

********************************/

T fun id

PHITYPE
tfunid (ptr)
nodal ptr;
{extern defptr finddef ();
extern long curr_addr;
extern char 'name ();
int count = 0;
defptr def;
char 'holder = malloc (8);
if

/*

(def = finddef (ptr->lptr->index)


(ERR_ff, ptr->ln)

terror
return
else

/* Semantic Check

(NOTFOUND)

Generic loop varient

/* Func name not

for tfunid

found

*/

*/

*/

ptr->lptr->type = def->type;
ptr->type = def->type;
putvar (ptr->lptr->type, ptr->lptr, FALSE)

*/

Match formals

*/

/*

(Imatchfor (ptr->rptr, def))


terror (ERR_gg, ptr->ln)

if

else
holder

/* Set node type

strcpy

('(holder

while

(holder,
+

count)

(ptr->lptr->label
(

(holder + count)
++count;

ptr->iptr->addr

name
!=

());

0)

/* Push piano -> door to copy


/* string to array

*/
*/

/* Gen code

*/

[count])
)

0;

c_start_proc (ptr->lptr->label)

for begin function

return

(pt

r->type)

/it************************** Tellist *********************************/


void
telist (ptr)
nodal ptr;

/* Semantic Check

for element 1st */

if

(ptr->rptr

semcheck
semcheck

/* Only semcheck if there is


/* something there

!= NULL)

*/
*/

(ptr->rptr)

(ptr->lptr)

c_store_code ("call ppop\n");


c_store_code ("push cx\n");
c_store_code ("push di\n");
++actual count;

/*

Generate code

*/

/A************************* Act Walk *******************************/


void
act_walk

/* Recursive procedure to
/* sem check actual list

(ptr, fptr)

121

*/
*/

; ;

nodal ptr;
fnode *fptr;
{

if

(pt->rptr != NULL)
act_waik (ptr->rptr,

/*

Recurse until NULL ptr is hit

*/

fptr->link)

semcheck (ptr->lptr)
if (ptr->iptr->name != ELLIST)
++actual_count;

/* Incr count only if left


/* sibling is an ID

c_store_code ("call ppop\n");

/ *

Generate code to put addresses

/* on the stack

*/
*/
*/
*/

c_store_code ("push cx\n");


c_store_code ("push di\n");
}

/it************************** Tactuals *******************************/


PHITYPE
tactuals (ptr)
nodal ptr;
(extern void c_call_proc ();
extern FLAG and_flag;
extern varptr findvar
extern defptr finddef ();
extern char 'name ();
defptr def = finddef (ptr->lptr->index)
varptr var = findvar (ptr->lpt r->index)
int count_hold = actual_count;
char *long_buff = malioc (10);
long convert;
fnode *fptr;
(

actual_count
if

(def)

if

/*

Evaluate actualists

*/

/* Defstack pointer
/* Varstack pointer
/* Buffer for
/* Conversion

*/
*/

long to string conv */

variable

*/

0;

Definition found

*/

/* Legitimate cases

*/

/*

((!var &S and_flag)

II

var)

fptr = def->fptr;
act_walk (ptr->rptr, fptr);
convert = actual_count
c_store_code ("mov bx, ");

/* Get

stcl_d (long_buff, convert);


c_store_code (long_buff);
c_store_code ("\n");
c_call_proc ("i_mov")
if

(and_flag)

&&

!var)

ptr to the formal nodes

*/

/* Generate code to put # of


/* actuals on the stack
/* Long to string conversion

*/
*/

Cover "and" scoping rules

*/

/*

add_and (ptr->lptr)
c_call_proc (name ());

/* Holder

for real name

*/

*/

else
c_call_proc var->nptr->label)
actual_count = count_hold;
return (def->type)
(

/* Gen code to call function


/* Restore actual count

*/
*/

terror (ERR_hh, ptr->ln)


return (NOTFOUND)

/* Function name not

122

found

*/

;;

/a************************** Tid ********************************


PHITYPE
tid (ptr)
nodal ptr;
(extern void c_i_form ();
extern long curr_addr;
extern char *name ()
extern int formal ()
extern FLAG and_flag;
extern varptr findvar
extern defptr finddef ();
char *long_buff = malloc (10);
varptr var = findvar (ptr->index)
defptr def;
(

Cvar)

if

if

/* Typecheck

Id node

*/

/*
/*

Buffer for long to string conv */


*/
Look for definition of var

/* Rtn type if var


/* in def table

(def = finddef (ptr->index)


if (and_flag)
add_and (ptr)

found

c_call_proc (name ());


return (getdtype (def)
}

else return

/* Get

and return type definition */

(NOTFOUND)

else if (formal (var))


stcl_d (long_buff, var->npt r->addr
c_i_form (long_buff);
(

/*

Long to string conversion

/* If no formal list, assume var


*/
/* is an assignment
*/
/* Generate code to call procedure

else
c

return

call proc

(getvtype

var->npt r->label

(var)

/* to assign value
/* Return variable type

123

/A******************************************************************
*
PUBLIC DOMAIN SOFTWARE

*
*

*
Semcheck Module #3
Name
*
* File
Sem3.c
* Authors
*
Maj E.J. COLE / Capt J.E. CONNELL
*
* Started
01/02/87
*
* Archived
04/02/87
*
* Modified
A********************************************************
* This file contains the following modules for the PHI parser:
*
*
Tidivide
*
Trdivide
Tarithop
*
*
Tconvert
Tprimary
Tconstant
*
*
Tand
Tor
Tnegation

Algorithm

This module contains the procedures necessary for implementing *


arithmetic & boolean operators.
Tarithop coordinates the semantic *
*
checking of arithmetic ops by calling the proper function based
Trdivide & Tidivide handle semantic checking *
on the operator type.
*
For all other arithmetic
for real & int division, respectively.
*
ops, the numconvert procedure (semO)is called to perform seman*
tic checking, then code is generated.
For each boolean operator, the appropriate child (ren) is checked*
*
and code is generated for the operation.
*
In addition, tconstant checks the type of a simple constant by
calling convert, & then returns either the constant type or an error*

*
*
*
*

*
*
*
*

it*********************************************
*
* Modified
* it******************************************************
/it*************************** Externals ******************************/
*

include <semcheck.h>
include <string.h>
extern void terror ();
extern void c_store_code

();

/* For "strcmpi"

*/

/* Store asm language output

*/
*/

/* to a buffer

/a-********************** Trdivide *****************************/


void
trdivide (ptr)
nodal ptr;
(PHITYPE ltype, rtype;
extern FLAG err_found;
extern void c_ztor 0;
ltype

switch
case
case
case

semcheck

/*

(ptr->lptr

Division of real operands

/* Check left

side for type

/* Make convs or locate errors

(ltype)
break;
(REAL)
(INTEGER)
(NATURAL)
{

*/

*/
*/

c_ztor
break;
default
terror
return;
(

(ERR_aa,

ptr->lptr->ln)

124

Lt child must rtn numeric type */


/* Error, no need to go thru acode*/
/*

;;

rtype

semcheck

(ptr->rptr)

/*

switch (rtype)
case (REAL)
break;
case (INTEGER)
case (NATURAL)
c_ztor
break;
default
terror (ERR_aa, ptr->rptr->ln)
return;

Check right side for type

/* Error,

no need to go thru acode*/

acode

/*

REAL)

(ptr,

Generate code

*/

/************************* Tldivide ******************************/


PHITYPE
tidivide (ptr)
nodal ptr;
(PHITYPE Itype, rtype, type
ltype = semcheck
rtype = semcheck

/* Semcheck
=

for integer division

*/

NATURAL;

(ptr->lptr)
(ptr->rptr)

/*

TypeCheck both sides

*/

/*

Check It for Int/Natural Type

*/

/*

If not

switch (ltype)
type = INTEGER;
case (INTEGER)
case (NATURAL) :break;
default
terror (ERR_cc, ptr->lptr->ln)
return (INTEGER);
(

Int or Nat,

error

*/

switch (rtype)
case (INTEGER)
type = INTEGER;
case (NATURAL)
break;
default
terror (ERR_cc, ptr->rptr->ln)
return (INTEGER)

/* Check rt

for Int/ Natural type */

/* If not

Int or Nat,

error

*/

>

acode (ptr, type);


return

/*

Generate code

*/

(type)

/a************************ TArithoD *****************************/


PHITYPE
arithop (ptr)
nodal ptr;
(extern PHITYPE numconvert
int type;

switch
case
case
case

(ptr->name)
(ADD_)
(SUB_)
(MULT_)

/* Type Check Addition,


/* Multiplication, Sequence Ops

Addition falls through


Subtraction falls through

*/
*/

();

/*
/*

*/

if (type = numconvert (ptr


acode (ptr, type)
return (type) ;

else
terror
return

<

(ERR_aa, ptr->ln)
(NATURAL)

>

125

trdivide
case (RDIV_)
ptr->type = type;
return (REAL)
tidivide
case (IDIV_)
ptr->type = type;
return (INTEGER);
case

(COLON_)

case

(CAT_)

(ptr)

(ptr);

/* Dummies for new,


/* but watch our smoke!

break;

break;

/it************************ Tprirnarv *****************************/


PHITYPE
tprimary (ptr)
nodal ptr;
(PHITYPE type;
type
if

/* Handle unary "+"

semcheck

or "-"

(ptr->rptr)

(type != INTEGER) &&


(type != REAL) S&
(type != NATURAL)
terror (ERR_aa, ptr->rptr->ln)
(

/* Check type of right node


/* Type must be a number

else if
(ptr->name) == NEG_)
c_store_code ("call igetvalue\n")
c_store_code ("neg ax\n");
c_store_code ("call iputvalue\n")

/* Negate operation
/* Spew code

return (type)

/* Note that no action


/* for unary "+"

is

req

/************************ Convert ******************************/


PHITYPE
convert (string)

/* Convert const to real, boolean,*/


*/
/* or integer value
/* String to convert
*/
/* True if "e" or "E" read
*/
/* True if a period has been read */
*/
/* Garden variety loop counter

stg string;
(FLAG e = FALSE,
period = FALSE;
int count = 0;
if

((strempi (string, "FALSE")


strempi (string, "TRUE")))

Si

/* If not boolean

while (string [count] != 0)


if
isdigit (string [count]))

/* Loop until end of string


/* If character is not a digit

if

((string [count] == 'e')


(string [count] == 'E'))
if

(e)

else

return

(ERROR);

found

/*

"e" or "E"

/*

Cannot have two "e"s

e = TRUE;

if

((string [count
(string [count
++count;
>

1]

1]

==
==

'+')

'-'))

126

II

/* "+" or "-" character

*/
*/

else if

;; ;
;

[count] =='.'){
(period) return (ERROR)
else period = TRUE;

(string

if

/*
/*

Decimal point found


Cannot have two periods

*/
*/

else return (ERROR)


++count;
(e

if

(string

[0]

return

period)

if

== '-')

return

(NATURAL)

return

(BOOLEAN);

/* If gauntlet has been run,


/* period or "e" makes real

(REAL)

return

(INTEGER);

*/
*/

/* Negative sign makes an

integer */

/*

If no other num types,

natural */

/*

If

not a number,

boolean

*/

/a-********************* TConstant *****************************/


PHITYPE
tconstant (ptr)
nodal ptr;
{extern put_addr
PHITYPE type;
NameRec *tptr;

/*

Handle constant nodes

*/

();

/* Constant type
/* Constant name

*/
*/

tptr = ptr->index;
if

(type = convert (tptr->name


ptr->type = type;
put_addr (ptr, type);
c_i_const (tptr->name + 1);
return (type) ;

1))

/*

Calculate type

/* Fill node

&

*/

increment address

*/

terror (ERR_jj, ptr->ln);

/* No legitimate constant

found

*/

/*******************************

Tand.

********************************/

PHITYPE
tand (ptr)
nodal ptr;
{PHITYPE ltype, rtype;
ltype = semcheck
rtype = semcheck
if

(!

(ptr->lptr)
(ptr->rptr)

/* Sem Check

for bool and node

*/

(ltype == BOOLEAN && rtype == BOOLEAN))


(ERR_kk, ptr->ln)

/*

Both children must be boolean

*/

/*

Generate code

*/

terror

c_store_code ("call land\n")


return (BOOLEAN)
;

/it****************************** Tor *******************************/


PHITYPE
tor

/* Sema Check

(ptr)

for bool or node

*/

nodal ptr;
{PHITYPE ltype, rtype;
ltype = semcheck
rtype = semcheck
if

(!

(ptr->lptr);
(ptr->rptr)

(ltype == BOOLEAN && rtype == BOOLEAN))


(ERR_kk, ptr->ln)

terror

127

/* Both children must be boolean

*/

c_store_code ("call lor\n");


return

/*

Generate code

*/

(BOOLEAN);

/it**************************** Tneoation *****************************/


PHITYPE
tnegation (ptr)
nodal ptr;

/* Sema check

for neg operation

if

(!(semcheck

(ptr->rptr)

== BOOLEAN))

/* Rt
/* It

child must be
child is null

boolean;

*/

*/

terror (ERR_kk, ptr->ln)


else c_store_code

return

("call negat ion\n"

/* Gen

(BOOLEAN)

128

code for boolean negation

*/

/a**********************************************************************
*
PUBLIC DOMAIN SOFTWARE

Semcheck Module #4
Name
*
Sem4.c
File
*
* Authors
J.E.
CONNELL
COLE
Capt
/
E.J.
Maj
*
* Started
01/29/87
*
* Archived
04/03/87
* Modified
a***********************************************************
* This file contains the following modules for the PHI compiler:
*

*
*

Telseif

Tthen
Tcomp

Tif
Telse

*
*

*
Algorithm
*
the
procedures
necessary
implement
This module contains
to
the
"if-then-elseif-else" series of commands. Tif coordinates the seman-*
tic checking by calling Tthen to check its left nodes, then calling *
Telse will be called until the right*
telse to check its right nodes.
*
subtree runs out of "elses" and "elseif s"

*
*
*
*
*

************************************************************************
*
* Modified
a**********************************************************************/
:

/************************** Externals *******************************/


#include <semcheck.h>
include <string.h>

/*

extern FLAG err_found;


extern PHITYPE semcheck

extern char 'name


extern void terror

For "strcpy"

();

();
(),

c_store_char

();

/a************************** Globals ****************************/


char *if label = NULL;

/it************************** Tif *******************************/


PHITYPE
tif

/* Semantic checker for


/* Ptr to the node
/* Int, Natural to real

(ptr)

nodal ptr;
{extern PHITYPE numconvert
PHITYPE type;
if

(if label == NULL)

();

/*

if label = malloc

if_label = strcpy (if_label,


type = numconvert (ptr)

name

0);

c_store_code (if_label);

(type)

129

Return value type

/* Generate
label
/* Check 4 conv It and rt types

/*

return

*/

converter */

(8);

/*

c_store_code (":\n");

"if" node */

Output code if an error


hasn't been found

*/
*/

;;

/it********************** Tthen ********************************/


PHITYPE
tthen (ptr)
nodal ptr;
(PHITYPE ltype, rtype;
char 'label = calloc (7,1);
char "holder = calloc (7,1);
(holder, if_label)

strcpy
if

(ptr->lptr)

terror

pt r->ipt r->ln)

c_store_code
c_store_code
c_store_code
c_store_code
c_store_code
return

BOOLEAN)

!=

if_label = strcpy if _label, holder


label = strcat (label, name ());
c_store_code ("call igetvalue\n")
c_store_code ("cmp ax,l\n");
c_store_code ("jne ");
c_store_code (label);
c_store_code ("\n");
rtype = semcheck

*/

/* Jump for

*/

asmlanguage code

*/
*/

(ltype=semcheck
(ERR_il,

/* Sem checker for then node


/* Pointer to the node
/* Type returned from left

/* Left node contains condition;


/* must be a boolean

*/
*/

/* Get a label for assembly code


/* Print proper code

*/
*/

/* Check right side

*/

/* Generate code

*/

(ptr->rptr)

("jmp ") ;
(if_label);
("\n");
(label);
(":\n");

/* Right type

(rtype);

is

returned

*/

/it*********************** Telseif a;*****************************/


PHITYPE
telseif (ptr)
nodal ptr;
{extern PHITYPE numconvert
return

(numconvert

/*
/*
/*
/*

();

Sem check for "elseif" node


Ptr to the node
Function converts and returns
left and right types

*/
*/
*/
*/

(ptr));

/it************************ xelse ********************************/


PHITYPE
telse (ptr)
nodal ptr;

/* Sema checker

for "else" node

*/

return

(semcheck

(ptr->lptr)

/* Return left side;


/* right side is always endif

*/
*/

/A*************************

^ c omp

******************************/

PHITYPE
tcomp (ptr)

nodal ptr;
{extern PHITYPE numconvert
PHITYPE type;

/* Handle comparisons and


*/
/* set membership operations
*/
/* FOR INTEGERS AND BOOLEANS ONLY */
();

130

; ;

;;

type = numconvert

switch (ptr->name)

case

(EQ_)

Check and convert if necessary


THIS IS FOR FUTURE USE WHEN
REALS ARE IMPLEMENTED
Check cases
WORKS ONLY FOR INTEGERS AND
/* BOOLEANS
NEEDS REAL

(ptr)

c_store_code ("call iequ\n");

break;

case

(NEQ_)

case

(KW_

c_store_code ("call ineq\n");


break
:

LESS_)

c_store_code ("call ilt\n");


break;
case (KW_ + GREATER_)
c_store_code ("call igt\n")
break;
case (LEQ_)
c_store_code ("call ilteq\n")
break;
case (GEQ_)
c_store_code ("call igteq\n"),
:

break;

case

(KW_

IN_)

c_store_code ("call in\n")


case

break;
(KW_ + NOTIN_)

c_store_code ("call notin\n");


default

break;
terror
break
:

(ERR_11,

ptr->ln)

return

(BOOLEAN)

131

/*

*/

/*
/*
/*
/*

'/
-/

/
*/
*/

/A****************************************************************
*
PUBLIC DOMAIN SOFTWARE

Name
Semcheck Utilities.
File
Sem_U. c
* Authors
Maj E.J. COLE / Capt J.E. CONNELL
* Started
01/02/87
* Archived
04/03/87
* Modified
jt********************************************************************
* This file contains the following modules for the PHI parser:
*
*
*

Putvar
Getfptr
Name
Putdef

*
*

*
*

Makef orm
Finddef
Form
Add And

Putf orm
Getvtype
Getdtype
And Alloc

Findvar
Put_addr
Makevar
Del And

A***************************************************************
*
* Modified
A******************************************************************/
:

/it*************************** Externals ******************************/


#include <semcheck.h>

include <stri.ng.h>

/*

/**************************** Globals
FLAG err_found = FALSE;
long curr_addr = START_ADDR;

long curr_scope
form = FALSE;

*/

/* True if an error found


/* Next address to be used to
/* place a variable
/* Current scope

START_ADDR;

for "stpcpy"

it*****************************/
*/
*/

*/
*/

formals being processed*/

/* True if

/***************:******. Typetable Definitions ************************/


int typeptr = TYPE_INIT;
tnode types [MAXTYPES];

/* Ptr to last
/* Typetable

typetable insert

*/
*/

/******************* Vartable Definitions ************************/


varptr varhead = NULL;

/*

Head of varlist linked list

*/

/********************** Deftable Definitions ************************/


defptr defhead

deftable linked list

/* Head of

NULL;

*/

/********************** And List Definitions it************************/


and_ptr and_head
and_flag = FALSE;

/* Head for and list

NULL;

*/

/it*************************** Makef orm ******************************/


f node
makeform

/*

()

Create

formal node

*/

return

((fnode*)

calloc

(1,

sizeof

(fnode)))

/************************ Put form *********************************/


void
putform (type)
PHITYPE type;
(extern fnode *fhead;
fnode *ptr = makeform

/* Put type

into formal list

/* Make a formal node


/* Tracer for the formal

(),

tracer;

132

*/

*/

list

*/

ptr->type
if

= type;

list already exists

/*

If

while (tracer->link != NULL)


tracer = t racer->link;

/*

Find end of list

tracer->link = ptr;
ptr->link = NULL;

/*

Insert Node

/*

If no list,

(fhead
tracer

!=
=

NULL)
fhead;

else
fhead = ptr;
ptr->link = NULL;
{

insert

/it************************* Makevar a******************************/


varptr
makevar ()

/*

Make node for vars linked 1st

*/

return (struct varnode*)


calloc (1, sizeof (struct varnode));
}

/a*************************** Putvar ********************************/


void
putvar (type, treenode)
PHITYPE type;
nodal treenode;
{extern int form;
varptr ptr = makevar

/* Put variable in

vartable

*/

();

ptr->nptr = treenode;
ptr->type = type;
ptr->form = form;

/* Fill entry

formal flag

*/

ptr->link = varhead;
varhead = ptr;

/* Set top of linked list

*/

ptr = NULL;
free (ptr)

/* Free

/* Set

*/

pointer space

*/

/it************************** Findvar *********************************/


varptr
findvar (varname)
long varname;

/*

Find var in vartable

/*

Travel list,

/*
/*

Break if variable found


Return ptr to proper varnode

*/
*/

/*

Increment link

*/

*/

{varptr ptr = varhead;

while (ptr
if

!=

NULL)

(ptr->nptr->index == varname)
return (ptr);

ptr = ptr->link;

return

/* No tally on

(NULL)

133

look for varname

variable

*/

*/

;
;

/a*************************** Getvt VP it*******************************/


PHITYPE
getvtype (per)
varptr ptr;

/* Get type of var

in var stack

*/

return

(ptr->type)

/it**************************** Putdef ********************************/


void
putdef (type, treeptr)
PHITYPE type;
nodal treeptr;
(extern int form;

defptr ptr

ptr->nptr
ptr->type

=
=

/* Put var

(struct def node* calloc


)

1,

sizeof

in

definitions table

(struct defnode)

/* Fill entry

treeptr;

*/

*/

= type;

= defhead;
def he ad = ptr;
ptr = NULL;
free (ptr)

ptr->link

/* Set top of
/* Free

linked list

pointer space

*/

*/

/********************** Finddef *********************************/


defptr
finddef (varname)
long varname;
{defptr ptr = defhead;

while (ptr
if

!= NULL)

Find var in deftable

*/

(ptr->nptr->index == varname)
return (ptr)

ptr = ptr->link;

return

/*

/* Break if variable found


/* Return ptr to proper varnode

*/

/* No tally on variable

*/

*/

(NULL);

/it*************************** get f pt r ********************************/


f node
'getfptr (ptr)
defptr ptr;

/*

Return fptr from def table

*/

return

(ptr->fptr)

/it*************************** Getdt vpe ********************************/


PHITYPE
getdtype (ptr)
defptr ptr;

/* Get type of var

in def table

*/

return

(ptr->type)

/a************************ Add and *********************************/


void
add_and (ptr)
nodal ptr;

/* Add and_node to and list


/* Ptr to node containing var

134

*/

*/

{extern and_ptr and_head, and_alloc


extern int buff_ptr;
and ptr a_ptr = and_alloc ();;

();

/*

Holder for and ptr

*/

ptr to current buffer ptr

/* Set

/* Get ptr to node with var def


/* Link node to list

a_ptr = NULL;
free (a_ptr)

/*

ptr >buffptr = buff_ptr;


ptr->ptr = ptr;
a_ptr->link = and_head;
and_head = a_ptr;

Dispose of a_ptr

*/
*/
*/

*/

/******************************

Alloc *****************************/

And.

and_ptr
and_alloc {)

/*

Create

node for and list

*/

return ((struct and_struct *) calloc

(1,

sizeof

(struct and_struct

/it**************************** Del

and.

void
del_and (ptr)
and_ptr ptr;
{extern and_ptr and_head;
and_ptr search = and_head;
if

(ptr

and_head)

!=

while (search->link

!=

ptr)

******************************/
/* Delete entry into the and list

*/

/* Case if pointer not equal to


/* first entry in list

*/
*/

/* Place ptr on entry above


/* tgt entry

*/
*/

/* Set pointer

*/

search = search->link;

search->link

ptr->link;

else and_head = ptr->link;

/*

Case ptr = to 1st entry in 1st

*/

ptr->link = NULL;

/*

Dispose of uneeded node

'/

free

(ptr)

/it**-*************************** Terror *******************************/


void
terror (err_num,

line_num)

/* Sem check error handling


/* routine

*/

/* Set err_found to true


/* stop code gen

*/
*/

*/

int err_num,

iine_num;
{extern ErrorHandler ();

err_found

TRUE;

ErrorHandler (line_num, err_num, SEM_ERR)

/*

&

generic error handling proc

*/

/it**************************** Putaddr *******************************/


void
put_addr (ptr, type)

Inserts virtual address of


variable/function return
/* And increments curr_addr
/* Assumes global curr_addr
/* Pointer to target node
/*
/*

nodal ptr;

135

*/

*/
*/
*/
*/

;;

PHITYPE type;

/* Node type

*/

ptr->addr = curr_addr;
ptr->scope = curr_scope;
curr_addr = curr_addr + (types [type] .bytes

/* Set

*/

if

(curr_addr

terror

>

/* Increment curr_addr by num of


/* bytes type needs
/* Error if address
/* address space

MAXADDR)

(ERR_mm,

node address

exceeds

*/

*/

*/
*/

ptr->ln)

/********************************* Name ****************************/


char
name ()

/* Generate an appropriate name


/* for a label/ procedure

*/

/* Holder for output

*/

*/

char 'string = malloc

(7),

*stringl = malloc (7);


static long seed = 10000;

Number to append to string

*/

String prefix
Insert string terminator
/* Convert long seed to string
/* Concatenate strings
/* Incr int to avoid duplication

*/
*/

/*
/*
/*

"string = 'a';
"(string + 1) = ENDSTRING;
stcl_d (stringl, seed);
string = strcat (string, stringl);
++seed;
return (string);

*/
*/
*/

/it***************************** pq rma 1 *******************************/


FLAG
formal (ptr)

/* Returns true if the varnode


/* describes a formal

varptr ptr;
{

if (ptr->form) return
else return (FALSE)

(TRUE)

136

*/
*/

APPENDIX K

ROCK COMPILER

CODE GENERATION MODULE

/A******************************************************************
*
PUBLIC DOMAIN SOFTWARE

Name
Code Generation Module
* File
Code_Gen
* Authors
Maj E.J. COLE / Capt J.E. CONNELL
* Started
02/06/87
* Archived
04/10/87
* Modified
EC
04/13/87 Code output to vdisk
A***************************************************************
* This file contains the following modules for the PHI compiler
*

C_Store_Code
C Ending

Ac ode

C_I_Const
C_I_Op

C_Startup
C_Printcode
C_Jmp
C_I_Form
C Call Proc

C_Of f_Insert
C_Ztor
C_Start_Proc
C End Proc

*
Algorithm
*
This module contains the procedures necessary for code generation.
C_startup initializes the run_time file, & the semantic checker will*
*
call the procedures as necessary. Note that "c_store_code" is a
genaric generator which will spew any string given as an arg to the *
*
output file.

*
*
*
*
*

**********************************************************
* Modified
04/13/87 Code output to vdisk., drive "d:"
***************************************************
:

EC

/it************************* Externals ****************************/


#include <semcheck.h>
include <string.h>
include <fcntl.h>

/* For

extern FLAG err_found;


extern long curr_addr;

/* Error flag
/* Current virtual address

level

I/O

*/

/it**************************** Globals ******************************/


char *code_buf fer
int buffjptr = NULL;

/*

Buffer for output code


in output buffer

/* Ptr to chars

*/
*/

/*************************** q store Code *************************/


void
c_store_code (string)
char *string;
(int ptr = NULL;

/* Put str into the output buffer


/* String to be printed
/* Ptr to the chars in input str

137

*/
*/

*/

if (!err_found)
while ('(string + ptr) != NULL)
=
* (code_buf fer
+ buff_ptr)

/'
/*

-f

(string

Compute only if no error found


Copy string char by char

*/
*/

ptr);

+ ptr;

+^buff_ptr;

/it***************************** q Jmp ********************************/


void
c_jmp (name)
char 'name;

/* Gen code to insert

jump command*/

c_store_code ("jmp ");


c_store_code (name);
c_store_code ("\n");
}

/it************************** q Start Proc ***************************/


void
c_start_proc (name)

/* Output name for start


/* language procedure

of asm

'/
*/

char *name;
(

c_store_code (name);
c_store_code (":\n");
)

/it********************* q End Proc *****************************/


void
c_end_proc (name)

/*
/*

Output name for ending an


assembly language procedure

*/
/

char 'name;
{

c_store_code
c_store_code
c_store_code
c_store_code

("call del_scope\n")
("ret\n");
(name);
(":\n");

/A*************************** q Call Proc ****************************/


void
c_cali_proc (name)

/* Output call for an assembly


/* language procedure

*/

'/

char 'name;

c_store_code ("call
c_store_code (name);
c_store_code ("\n");

")

/A************************* q

Form ** ***************************** /

void
c_i_form (num)

/* Generate call to put integer


/* formal addr onto stack

char *num;
{

c_store_code
c_store_code
c_store_code
c store code

("mov ex,");
(num);
("\n");
("call i formal\n");

138

'/

'/

;;

/a************************** q
c

void
const

; ;;

Const ******************************/

/* Output code for assigning an


/* integer constant

(name)

*/
*/

char *name;
{

store_code
c_store_code
c_store_code
c_store_code

("mov ax,");

(name)
("\n")

("call iputvalue\n"

/a*************************** q
void
c_i_op (op)
optype op;
{extern void terror

op *********************************/

/* Output code for int


/* Type of operation
(

arith ops

switch (op)
case (ADD)
c_call_proc ("iadd");
break;
case (SUB)
c_call_proc ("isub");
break;
case (DIVIDE)
c_call_proc ("idivn");
break;
c_call_proc ("imult")
case (MULT)
break;
return;
default
{

/********************* startup ****


it****************************/
void
c_startup ()
code_buffer = getmem (SIZEBUFFER)
'extrn
initial
near\n")
c store code
'extrn
iadd
near\n")
c store_code
isub
near\n")
c store code
e xt r n
near\n")
c store code
'extrn
imult
'extrn
idivn
near\n")
c store code
'extrn
iequ
near\n")
c store code
'extrn
ineq
near\n"
c store code
near\n")
c store code
'extrn
igt
c store code
'extrn
ilt
near\n")
c store code
'extrn
land
near\n")
lor
near\n"
c store code
'extrn
c store code
'extrn
igteq
near\n"
iputvalue
c store code
'extrn
near\n'
c store code
near\n")
'extrn
ilteq
c store code
'extrn
igetvalue
near\n'
c store code
'extrn
initial
near\n");
c store code
'extrn
finis
near \n"
c store code
'extrn
print top
near\n'
c store code
'extrn
negation
near\n")
c store code
'extrn
i_formal
near\n")
c store code
'extrn
near\n"
i mov
c store code
'extrn
ppush
near\n")
c store code
'extrn
ppop
near\n")
c store code
'extrn
add scope
near\n'
c store code
'extrn
del scope
near\n'
c store code
org 0100h\n\n") ;
c store code
'cseg\n ') ;
c store code
"call initial\n"
{

'

139

/* Open and initialize files


/* Initialize buffer
/* Write utilities needed

*/
*/

; ;

/*********************** q Print Code ****************************/


void
c_print_code

()

(extern char prefix


int code;
char holder [30]

*/
*/

/* Output

*/

[];

/* set

strcpy (holder, "d:");


strcat (holder, prefix)
strcpy (prefix, holder);
strcat (holder, "a. 86");
code

/* Output code buffer to


/* secondary storage

open (FILENAME, 0_TRUNC

/*

0_WRONLY, NULL)

write (code, code_buffer, buff_ptr);


close (code);

file

up file name

save prefix

&

drive for fut use*/

/* Open file for writing and


/* overwriting only

*/
*/

/* Write the buffer


/* Close the output

*/
/

file

Endincr ********************************

/A*********************** q
void
c_ending

/*

()

Ending for output code

*/

err_f ound)
c_store_code ("call print_top\n")
*/
/* Print address pointed to by

if

c_store_code ("call finis\n")


* (code_buf fer +
(buff_ptr ++)
c_print_code

/* top of program stack


/* Routine to make clean
=

CNTRL_Z;

();

ending
/* If no error, put asm language
/* delimiter to file
/* Output code to a file

*/
*/
*/
*/

*/

>

/it**************************

ztor ********************************/

void
c_ztor ()

/* Gen code for conv int to real


*/
/* Empty now, but watch our smoke */

{}

/A***************************

p^Q ode

void
acode (ptr, type)

*****************************/
/* NOTE
USES EMPTY STATEMENTS
/* FOR REAL OPERATIONS

*/
*/

/* Generate code for arith ops

*/

nodal ptr;
FLAG type;
(extern void terror
int name;

();

name = ptr->name;

switch (name)
case (ADD_)
if (type == REAL)
else c_i_op (ADD)
break;
case (SUB_)
if (type == REAL)
else c_i_op (SUB)
break;
case (MULT_)
if (type == REAL);
else c_i_op (MULT)
break;
case (RDIV_)
break;
{

/*

Addition

*/

/*

Subtraction

*/

/*

Multiplication

*/

/* Real Division

140

*/

case

(IDIV_)

c_i_op (DIVIDE);
break;
:

/*

141

Integer Dilvision

APPENDIX L

ROCK COMPILER

USER INTERFACE

**********************************************************************
User Interface
Name
* File
User .C
* Authors
Maj E.J. COLE / Capt J.E. CONNELL
* Started
04/01/87
* Archived
04/10/87
* Modified
***********************************************************************
* This file contains the following modules for the PHI compiler
*
/

User_err
Print header

Prog_name
User

Get name
P

Close

Algorithm

This module contains the procedures necessary for the user in- *
*
terface.
Prog_Name gets the user's choice of program by calling Get_Name *
*
Print header is called to print the initial screen display on console, & the User procedure is the overall coordinator of the inter- *
*
face.
User_Err and P_Close are both independent procedures. User_Err *
handles output in the event that an error or errors have been found.*
P_close is called by "Rock._Main" to ensure the input file has been *
*
closed.

*
*
*
*
*

*
*

*
:

********************************************************************
* Modified
*********************************************************************

/****************************** Externals ****************************/


#include <user.h>
^include <dos.h>
^include <stdio.h>

extern void clrscr

/*

(),

mov_cursor

(),

c!r_window

for "getch

*/

()"

();

/******************************* Globals ******************************/


char u_name [BUFFLENGTH]
prefix [BUFFLENGTH];

/* Name of Source file


/* Prefix of source file

FILE "infile;

/* File handle of

source file

*/
*/
*/

/****************************** User Err ******************************/


void
user_err ()
{extern void clrscr

/* Screen interface
();

142

for error rnsg */

; ;;

;; ;

/* Number of errors found


/* Error File
/* Number of blocks to read
/* Generic loop
variable

extern int num_errors;


FILE *errors;
int numblocks,
count = 0;
char *buffer = malloc (BSIZE),
input;

c1rscr

*/

*/

Keypressed after pause

*/

/* Put EOF marker to file

*/

/*

errors = fopen (ERRORFILE, "a")


fprintf (errors,
"number of errors = %d\n", num_errors)
putc ('$', errors);
fclose (errors)

*/
*/

errors = fopen

numblocks

(ERRORFILE,

"r")

read (buffer, BLOCKSIZE, 20, errors)

while ('(buffer + count) != $')


putchar (* (buffer + count)
++count;

/* Read error mgs from error files*/


/* BLOCKSIZE
*/
will allow whole
/* file to be read at once
*/

/*
/*
/*
/*
/*

printf ("\n \n \n")


printf

PAUSE);

("%s",

input = getch

();

fclose

(errors)

c1rscr

*/
*/
*/
*/
*/

(input == ESCAPE)

if

Skip lines to give appearance


of user friendliness
Pause to give user a chance to
comtemplate his errors
Eat keyboard input after pause

exit

/* If user pressed escape,


/* exit the program

(I);

*/
*/

/******************************** Getname it****************************/


void
getname

/*
/*
/*
/*

()

{int ch,

count =
do

0;

/* Loop, get file name


/* <- key is hit

if

(ch = getch
if (count)

putchar
putchar
putchar

== BACKSPACE)
--count;

())
{

/*
/*

(ch)
('

Returns the user's choice


file to compile
Single input character
Buffer pointer
of

');

*/
*/

ltr by Itr */

Backspace
Insert blank

/* Eat

(ch)

*/
*/

*/
*/
*/

last char if there is one

*/

else if (ch == ESCAPE)


cirscr
exit (1) ;
else if (ch < 127)
(

/* Escape pressed;

exit

*/

/*

putchar (ch)
u_name [count] = ch;
+ x count;
while ((count <= BUFFLENGTH)

Legitimate char read; use it

*/

ch

!=

&&

/* Loop until buffer full or


/* return pressed

EOLN)

143

*/
*/

;; ;;

u_name (count

; ;

;;

/*

= 0;

1]

Insert end of string char

*/

/it***************************** Proo name *****************************/


void
prog_name

/* Get

()

legitimate program name

*/

do

/* Loop until foper. finds


/* legit name
/* Clear out lower window of

clr_window (9,1,21,79);
mov_cursor (10,2);
printf (GETPROGRAM)
getname
infile = fopen (u_name, "r")
(

if

(!

infile)

(getch

*/

/* Name not in current directory


*/
/* Print user friendly error msgs */

== ESCAPE)

()

c1rscr

exit

sen

mov_cursor (20,33);
printf (FILE1_ERRCR)
mov_cursor (21, 16);
printf (FILE2_ERROR)
if

*/
*/

/* Exit

if ESCAPE

pressed

*/

(1)
}

while

(!

/* Repeat until correct file found*/


/* NOTE - escape exits loop & prgm*/

infile);

mov_cursor (13,28);
printf (WAIT)
}

/it************************** Print header ****************************/


void
print_header

/* Print out header

()

for user

*/

c1rscr

mov_cursor (1,33);
printf (HEADER1);
mov_cursor (2,24);
printf (HEADER2)
}

/it**************************** p close
void
p_close

*^*** *************************
/*

()

Close out target file

*/

f close

infile)

/****************************** user ********************************/


void
user ()
(int count = 0;

print_header
prog_name
(

while
I

/* Invoke user interface


/* Duty integer
(

*/
*/

(u_name

==

[count]

'

*/
/* Copy root of input file name
*/
/* Loop until end of input name
/* reached OR until end of str is */
*/
/* reached, if no
extension

'

u_name [count] == NULL))

prefix [count] = u_name [count];


++count;
prefix [count] = 0;
}

/* Insert end of

144

string value

*/

APPENDIX

ROCK COMPILER

RUNTIME UTILITIES

***********************************************************************
*
* Name
Phi Runtime Utilities
*
* File
U.a86
*
* Authors
Maj E.J. COLE / Capt J.E. CONNELL
*
* Started
01/26/87
*
* Archived
16 Feb 87
* Modified
*
16 Apr 87 Stack/Varspace Crash error check
EC
***********************************************************************
:

***********************************************************************
ALGORITHMS
1.

Input/Output:

The first section of the program contains input and output

Virtual Space: A virtual


stack.
The middle j of this
offset ( 32700) from vars.
vars grow from the bottom.
two bytes), so only
even numbers may be used to
2.

space is set up in the extra segment to hold both the


space is denoted by the symbol "vars", and variables
In this implementation, the program stack grows from
The virtual space is assumed to be made up of words

access it.

3.

Stack:
The stack pointer is the si register, which is initialized to 3270C.
grows, the si register is reduced by two. Ppush and ppop will push ana pop two
registers. "Push_one" and "Pop_one" will push and pop single words to and from

4.

Addressing Program Variables: Each program variable is assigned a two-tuple A


scope and
is the offset from the base address of variables in that scope.
turn the address of a variable given A.

5.

Scoping:
Initially the scope is set to 0: the global scope.
The variable
space containing the outer scope, and the variable "S_Nest" contains the current
new scope is created, "S_Nest" is increased by one, and the three-tuple S =
(L = Static Link, pointing nesting level of the outer scope, N is the nesting
is the base address of display of variables for this scope.
When a scope is deleted, the top of the stack is saved, the top instantiation of
and S_Link and S_Nest are recalculated.

Inserting/Extracting Program Variables: "I_Assign" will insert an integer or


scope contained in S_Nest when it is requested.
"Iputvaiue" will insert the
resoponding tuple A on the stack.
"Igetvalue" will pop the tupie A off the top of
the value of the integer pointed to by A.

***********************************************************************
***********************************************************************
* Modified
*
EC
22 Feb 87 Add/del_scope changed to save TOS
*
16 Apr 87 Added check for stack/varspace crash, includes*
*
*
message to observer
***********************************************************************
:

145

.it********************************************************************
*
*
Public Procedures
.it*********************************************************************

public
public
public
public
public
public
public
public
public
public
public
public
public
public
public
public
public
public
public
public
public
public
public
public
public
public
public

i_mov
i_formal
igetvaiue
finis
iputvalue
find_addr
add_scope
del_scope
initial
finis
ppush
ppop
iassign
lor

land
iequ
ineq
ilt
igt

ilteq
igteq
negation
iadd
isub
imult
idivn
print_top

A******************************************************************
*

I/O Procedures

*******************************************************************
*********************** print char ********************************
Print a char to the screen
assumes letter to be printed is in dl register
print_char
push ax
mov ah, 06
int 21h
pop ax

/save registers
;put int vector

ret

************************* Eoln *********************************


Prints end of line character to the screen
/Moves appro ascii values to crt
IBM specific

mov dl, 10
eoln:
call print_char
mov dl, 13
call print_char
ret

********************* Print Num. ********************************


a number, the value found in the bx register

Prints, as

146

print_num:
push ax
push bx
push ex
push dx
mov ex, 10000
emp bx,
jge small
mov dx,
call print_char
neg bx

rBase for dividing


:Check if negative
If not, jump to start
rEmit negative sign
r

'

small:
emp bx,
jl final

rtest

10

rlf not

xor dx,

10

jump

deer ex by factor of 10

Mov ax to ex and continue

Main printing loop


Set up dx register

bx

Divide

Move remainder to bx
Add for ascii
Print

up dx for division
Divide base value by 10

dx
ex

ax,
ex,

zero,

^Otherwise,

div ex
mov bx, dx
add ax, 4 8
mov dx, ax
call print char

mov
mov
div
mov
emp

if less than

Divide bx by ex
Set up dx register

mov ax, bx
div_loop:
xor dx, dx
div ex
emp ax,
jne P_l oop
mov ax, ex
mov ex, 10
xor dx, dx
div ex
mov ex, ax
jmp div_loop
mov ax,
p loop:
xor dx, dx

Negate

Set

10

ex
ex,
ax,

ax
If base value
Else continue

jne p loop

final
add bx, 4 8
mov dx, bx
call print char
call eoln
pop dx
pop ex
pop bx
pop ax
ret

1,

end loop

Print final value

End of line

********************** Print too *******************************


Prints the space pointed to by the top tuple of the program stack
prir.t_top

add
mov
add
mov

di,
dx,

mov di si
,

vars [di

;Get nesting level

vars [di

;Mov offset to ex

di,2
ex,

147

;Mov address into si reg

call find_addr
mov di, ex
mov bx, vars [di]
call print_num
call eoln

;Mov num from address to ox


; Print
number
; Inset
eoln

ret

************************* print s ******************************


assumes address of is in the dx register
assumes string ends with a "$" sign

push ax
mov ah,
int 21h
pop ax

/save register
9

ret

*******************************************************************
*

Stack Procedures

*******************************************************************
************************* ppush ***********************************
Pushes values from ex (offset) and di (nesting level)
ppush:
sub
mov
sub
emp

mov vars
si,

vars
si,
si,

[si],

offset in stack
stack pointer
Nest level into stack
stack pointer
;Check for stack/varspace crash
;If no crash, go to end
;Get string for error message
;Print it
;Hait execution

ex

;Put
Inc
;Put
; Inc

[si],

di

curr_addr
p_return
mov dx, offset crash
call print_s
call finis
jg

p_return:

ret

************************* Push one *****************************


Push a single integer from ex register to the program stack
push_one:
mov vars [si], ex
sub si, 2

Put word in stack


Inc stack pointer

ret

************************** ppop ********************************


Pop values from the program stack to di (nesting level) and ex (offset)
ppop:

add si,
mov di, vars
add si,
mov ex, vars

[si]

Set up ptr
;Get nesting level

[si]

;Recalc pointer
;Get offset

ret

************************* Pop One ******************************


Pop a single integer from the stack to the ex register
; Set
up pointer
;Get word

add si, 2
pop_one:
mov ex, vars [si]

148

*******************************************************************
*
*
Varspace Management Procedures
*******************************************************************
*********************** i As s ign ***********************************
Assign an integer value to a variable space in current scope
Assumes value is in ax; offset is set to current max offset
mov di, s_link
iassign:
;get static link
sub di,2
mov di, varsfdi]
add di, max_offset
mov vars[di], ax
add max_offset,2
add curr_addr
ret

/decrement it to pt to base address


mov base address to di
; add
offset
;mov number into that address space
Inc max offset and current address
;

************************ igetvalue *****************************


;Pop the stack and move the integer value pointed to into the ax
register
.

;Get nesting level and offset

igetvalue:
call ppop;
mov dx, di
call find_addr
mov di, ex
mov ax, vars [di]

;Get addr of

(S_Nest, Max_Offset)

;Get integer value

ret

*********************** iputvalue ******************************


Takes an integer from AX register, puts its value into varspace,
then puts its address on the top of the stack
mov dx, s_nest
iputvalue:
mov ex, max_offset
call find_addr
mov di, ex
mov vars [di], ax
mov di, s_nest
mov ex, max_offset
call ppush
add max_offset, 2
add curr_addr, 2

;Get static nesting level


;Get addr of

(S_Nest,

Max_Offseti

;Put value into memory

(S_Nest, Max_Offset)
;Inc max offset and curr_addr
,-Store

ret

*******************************************************************
*

Scoping Procedures

*******************************************************************
********************* Find Addr ***********************************
Returns address of variable at nesting level dx, offset ex to ex reg
find_addr:

mov di,

find_loop: emp es vars [di


je f_out
:

;Get addr of current static pointer

s_link
j

;If stack value = scope,

dx

149

exit loop

add di,
mov di, es:vars[di]
jmp find_loop
f

;Else jump to next scope

ar.d

loco

;Calc ptr to base addr of scope vars


;Add offset

sub di,2
add ex, es:vars[di]

out:

ret

.******************** Add Scope ************************************


Start new scope by adding static link, starting address, & nesting
level
;

add_scope: mov ex, s_link


inc s_nest
mov di, s_nest
call ppush
mov ex, curr_addr
mov di, max_offset
call ppush
mov max_offset,
mov s_link, si
add s_link,

Get static link

;Get new nesting level


;Save link and level

;Save curr addr


Re initialize max offset

ret

********************
Deletes a scope

dq]_

Scope ************************************

del_scope: call ppop;


mov dx, di
call find_addr
push ex
dec s_nest
mov si, s_link
sub si,

;Save top of stack

Save absolute address of tos


Reduce nesting level
/Decrease stkptr to current link
;
;

mov ex, es:vars [si]


mov max_offset, ex
mov bx,
mov ex, es:vars [si+bx]
mov curr_addr, ex
add si, 6
mov ex, es:vars [si]
mov s_link, ex
pop di
mov ax, es:vars [di]
call iputvalue

Get current static link

/Restore top of stack

ret

*******************************************************************
*

Begin/End Procedures

*******************************************************************
************************ initial **********************************
initialize the stack, and variables
must initialize ex to base of stack heap before calling this
mov si,
initial:
mov di,
mov ex,
call ppush
ret

/Initialize base of stack

SPACE_TOP

/Push base_scope and address

150

*********************** finis **********************************


finis:

;end procedure

mov ax,04c00h
int 21h
ret

*****************************************************************
*
*
Booleans
*****************************************************************
************************* Necrat ion ******************************
Negates a boolean value
;Get boolean

negation:
call igetvalue
cmp ax, 1
jne zero
mov ax,
jmp p
mov ax,
zero
call iputvalue
p:
ret

Jump to end

/Stuff boolean

&

put addr on stack

************************* Lor **********************************


Takes logical or of two booleans and stacks address of answer
call igetvalue

lor:

;get 1st boolean off stack to the ex

reg

/save boolean
/get 2nd value using the stack ptr
/Perform or
/Put value into varspace & in stack

mov bx, ax
call igetvalue
or ax, bx
call iputvalue
ret

************************ Land **********************************


Takes logical and of two booleans and stacks address of answer
call igetvalue
mov bx, ax
call igetvalue
and ax, bx
call iputvalue

/get 1st boolean off stack to ex reg


/save value
/get second value using stacK ptr

land:

/Perform and
/Push boolean address onto stack

ret

************************ i ecru ***********************************


Takes logical equal of two integers and stacks address of answer
call igetvalue
mov bx, ax
call igetvalue
cmp ax, bx
je eql
mov ax, FALSE
cont
call iputvalue

/get 1st int off stack to the ex reg


/save value
/get 2nd value using the stack ptr

iequ:

/Jump if equal
/put false value into varspace
/Put value into varspace, addr on stack

ret

eql:
mov ax,
jmp cont
ret

/put true value into varspace

TRUE

151

************************ inecr ***********************************


Takes logical not equal of two integers and stacks address of answer
call igetvalue
mov bx, ax
call igetvalue
cmp ax, bx
jne neql
mov ax, FALSE
call iputvalue
fal:

get 1st int off stack to the ex reg


;save value
second value using stack ptr
; get

ineq:

;Jump if equal
;put false value into varspace
;Put value into varspace, addr on stack

ret

mov ax,
neql:
jmp fal
ret

;put true value into varspace

TRUE

************************* Ht **********************************
Takes logical less than of two integers and stacks address of answer
Returns true if first value is less than the second value
call igetvalue
mov bx, ax
call igetvalue
cmp ax, bx
jge less
mov ax, TRUE
call iputvalue
con:

;get 1st int off stack to the ex reg


; save
value
;get 2nd value using the stack ptr

lit:

Compare
Jump if less
;put false value into varspace
;Put value into varspace, addr on stack
;

ret

less:
mov ax,
jmp con
ret

;put true value into varspace

FALSE

************************* Xot. **********************************


Takes logical greater than of two integers and stacks address of answer
Returns true if first value is greater than the second value
Igt

call igetvalue
mov bx, ax
call igetvalue
cmp ax, bx
jle greater_than
mov ax, TRUE
call iputvalue
conl:

;get 1st int off stack to the ex reg


/save value
second value using stack ptr
; get

/Compare
/Jump if greater than
/put false value into varspace
/Put value into varspace, addr on stack

ret

greater_than

mov ax,

/put true value into varspace

FALSE

jmp conl
ret

************************ iitecj *********************************


Takes logical < of two integers and stacks address of answer
Returns true if first value is less than or equal to the second value
/get 1st int off stack to the ex rec
/save value
/get 2nd value using the stack ptr

call igetvalue
mov bx, ax
call igetvalue
cmp ax, bx
jg lteq

Ilteq:

/Compare
/Jump if less to error

152

false value into varspace


Put value into varspace, addr on stack

mov ax, TRUE


call iputvalue
con2

'put

ret

lteq:

^put true value into varspace

mov ax, FALSE

jmp con2
ret

************************ iq-tecr *********************************


Takes logical > of two integers and stacks address of answer
Returns true if first value is greater than or equal to the second
value
call igetvalue
mov bx, ax
call igetvalue
cmp ax, bx
gteq
jl
mov ax, TRUE
call iputvalue
con3:

;get 1st int off stack to the ex reg


value
; save
;get second value using stack ptr

Igteq:

/Compare
Jump if greater than or equal to
;Pput false value into varspace
/Put value into varspace, addr on stack
;

ret

mov ax,
gteq:
jmp con3
ret

;put true value into varspace

FALSE

*******************************************************************
*
*
Integer Operations
*******************************************************************
************************* i add ************************************
Adds two integer values
Assumes offset off second value is in SI register
Offset of first value is at the top of the stack
call igetvalue
mov bx, ax
call igetvalue
add ax, bx
jo err

ladd:

;First value to ex register


/Perform addition
;if overflow, run time error

call iputvalue
ret
err:
mov dx,
call print_s
call eoln
call finis
ret

;Put integer into varspace

offset add_err

Error handler for overflow

************************* i Sub *********************************


;Subs two integer values
/Assumes offset off second value is in SI register
/Offset of first value is at the top of the stack
.

call igetvalue
mov bx, ax
call igetvalue

isub:

sub ax,

/First value to ex register


/Perform subtraction

bx

153

errs

jo

/if overflow,

call iputvalue

run time error

;Put integer into varspace

ret

mcv dx,
errs:
call print_s
call eoin
call finis
ret

;Print error message on overflow

offset sub_err

************************* iMult *********************************


Multiplies two integer values
Assumes offset off second value is in SI register
Offset of first value is at the top of the stack
imult
call igetvalue
mov bx, ax
call igetvalue
imul bx
jc errl

First value to ex register


/Perform mult, result in AX
;if carry set, run time error
;

;Put integer into varspace

call iputvalue
rec

errl:
mov dx,
call print_s
call eoln
call finis

offset mul_err

;put error message in dx register

/print it
;end

ret

************************* iDivn *********************************


/Divides two integer values, result in varspace, address of result
stacked
/Offset of first value is at the top of the stack
.

idivn

;Save Registers

push ex
push dx
call igetvalue
mov bx, ax
call igetvalue
xor
mov
mov
emp

dx,
cl,
ch,
bx,

;Get divisor

Mov divisor to bx
;Get dividend to ax
;

dx

Set dx to
;cl and ch are negative flags
;

test2
errd

jg
je

;bx
;bx
;bx
;bx

neg cl
neg bx

test2

is
is
is
is

positive, no 'action needed


0, ERROR
negative, cl flag negated
made positive

;test dividend

emp ax,0

/dividend >= 0, no action


/ax is negative, ch flag negated
/ax is made positive

jge dloop
neg ch
neg ax

/loop and count subtractions

dloop:
sub ax,bx
emp ax,
dene
jl
inc dx
jmp dloop

/if ax less than 0,

/store result in dx
/continue loop

154

done

/Multiply ch and cl

mov al, cl
done:
mul ch
cmp al,
jge-dend
neg dx
mov ax,dx
dend:
pop dx
pop ex
call iputvalue

;if product not negative,

no action

;else negate answer

;Put

integer into varspace

ret

mov dx,
errd:
call print_s
call eoln
call finis

;put error message in dx register


;print it

offset div_err

;end

ret

***********************************************************************
Function

Calling Procedures

***********************************************************************
******************************
mov **********************************
Movs integer or boolean actuals with addresses at the top of stack to
the lowest addresses within a scope
Assumes bx has number of actuals needed to be moved
j_

;Save i_mov's return address

i_mov:
pep ret_addr
call add_scope
strt:
pop dx
pop ex
call find_addr
mov di, ex

;rnov

addresses to ex and dxi regs

;Get virtual address of the integer

mov ax, es:vars [di]


call iassign
dec bx
cmp bx,

;Set up ax for iassign

jne strt

push ret_addr

/Restore i_mov's return address

ret

.********************* j q rma i ************************************


;Puts a formal to the top of the stack
/Assumes offset of formal in ex register
i_formai:
mov di,0
mov di, s_nest[di]
call ppush

/Get nesting level


/Push offset and nest onto stack

ret

***********************************************************************
*
*

Variables

***********************************************************************
dseg

155

****************************** Constants ******************************


TRUE
FALSE
SPACE_TOP

EQU
EQU

EQU

2,2100

Top of memory space

.************************* intecrer Variables ***************************


dw
dw
dw

max_offset
curr_addr
s_link
dw
S_nest
ret_addr

/Maximum current offset w/in scope


/Current maximum address
/Current address of static link
/Current static nesting level

-32700
SPACE_T0P

dw

.************************** Error Messaaaes ****************************


div_err
db

db
'

mul_err

db
db

add_err
db

'MULTIPLICATION OVERFLOW,

IDIOT!'

db

'ADDITION OVERFLOW,

DIMWIT!'

'S'

db
'

'SUBTRACTION OVERFLOW, NITWIT!'

'

crash
db

FOOL!'

'$'

sub_err
db

'DIVISION BY ZERO,

$'

db

'STACK/VARIABLE SPACE CRASH'

'$'

.************************** Error Messaaoes ****************************


eseg
vars
end

dw

156

APPENDIX N

TEST SUITE

SIMPLE TESTS OF FUNCTIONS AND VARIABLES


let

c (20)

$Z

-> $Z;

where

c (n)

else 3

==

if

= 2 then

3 * n

+ n endif

--Simple "Hello I'm Alive Test"

let c
$Z -> $Z;
c (1 * 2) where c (n)
:

==

n * 3

Test for expression in functions's formals

let c

c (k

$Z
2)
c

-> $Z;

where k == 2 and
(n) == if n = 1 then n

* 3 else n

+ 4 endif

Test for expression in function's formals

TESTS FOR RECURSION


let c

$Z

c (k * 2)

$Z

(n)

==

n * 3

-> $Z;

where

c (0)

c (n)

==

if

n =

then

* n endif

else c (n

1)

else c (n

1) *

Test for recursion in functions

let

$Z

-> $Z;

where c

c (5)

where k == 2 and c

Test for expression in function's formals

let

-> $Z;

(n)

==

if

n =

then

Test for recursion in functions

let c

$Z

-> $Z;

157

n endif

where c

c (3)
--

==

if

n =

then

else n * c (n

1)

endif

else n * c (n

1)

endif

Test for recursion in functions

let

$Z

-> $Z;

where c

c (7)
--

(n)

(n)

==

if

then

Test for recursion in functions

TESTS OF COMPLEX FUNCTIONS, INCLUDING BOOLEANS AS


ARGUMENTS AND RESULTS
letc:$Z->$B;
c (1) where
c (n)

==

n = 6

Test for booleans

let

c(2

$Z

$Z

$Z

in

function

-> $Z;

where c(n,m,x) == n

1,3,4)

* x

--Test for multiple arguments

letc:$Z->$B;
let d
$Z -> $Z;
:

c (1) where
c (n) ==

d(k)

= d(l) where

== k

Test for chaining in functions

let

let

lete

$Z -> $Z;
$Z -> $Z;
:$Z->$B;

c (3) where
c (n) ==

1 + d(n) where
d(k)==ife(l)
then k else k + 1 endif
where e (k) == k = 3

Test for nesting in functions

158

$Z -> $Z;
$Z -> $Z;
let d
$Z -> $B;
let e
let

c (3) * 10

where

==

1 + d(n) where
d(k)==ife(l)
then k else k + 1 endif
where e (k) == k = 3

c (n)

Test for nesting

in functions, result multiplied

by constant

$Z -> $Z;
let d
$Z -> $Z;
let e
$Z -> $B;
let

c (3) * c(4)
c (n) ==

where
1 + d(n) where
d(k)==ife(l)
then k else k + 1 endif
where e (k) == k = 3
and b == 10

--

Test for two functions, same definition


Also, test for extraneous variable defined at end of program

$Z -> $Z;
let d
$Z -> $Z;
lete:$B->$B;
let

c (3) * c(4)
c (n) ==

where
1 + d(n) where
d(k)==ife(2 = 3A4 =
then k else k + 1 endif
where e (k) == k

--

5)

Test for boolean expression as an actual

TESTS FOR "AND" AND "WHERE" NESTING AND COMBINATIONS


$Z -> $Z;
let d
$Z -> $Z;
let c

c (3) *

b where b == 10 and
== n * d (n) where

c (n)

d(n)==3
~

Test for nesting in functions

159

let

let

$Z -> $Z;
$Z -> $Z;

c (3) * b

where b == 10 and
== n * d (n) where
d (n) == 3 * e where e == 10

c (n)

Test for nesting in functions

let

let

let

$Z -> $Z;
$Z -> $Z;
$Z -> $Z;

c (3) + b where b == 10 and


c (n)==d(l) + if n = e (1) then 2 else lOendif
where e (k) == - 1 and

--

(g)

== g +

Test for nested wheres and ands

let

let

let

$Z -> $Z;
$Z -> $Z;
$Z -> $B;

c (3) where
c (n) ==

d(k)

+ d(n) where

if

e(l) then k else k

where e
--

(b)

== b =

endif

Test for nesting in functions

$Z

let

let

d $Z;

-> $Z;

where c (n) == d
and d == 10 * 5

c(5)

--

Test for single and statement


Test for datadef declaration

let

let

let

$Z;
$Z;
$Z;

where c == (d + 10 + e where

==

10)

160

and d == 10
Test for Multiple ands

let

let

let

$Z;
$Z;
$Z;

where c == d + 10 +
and d == 10
and e == 10

Test for Multiple ands

let

let

let

$Z -> $Z;
$Z -> $Z;
$Z -> $Z;

where c(n) == d(n) + 12


and d(s) == 10 + s

c(5)

--

Test for Multiple ands using functions

let

let

let

$Z -> $Z;
$Z -> $Z;
$Z -> $Z;

where c(n) == d(n) + 12


and d(s) == 10 + e (s)
and e(k) == 20 + k + t where

c(5)

--

Test for Multiple ands

let

let

let

== 100

nested wheres

$Z;
$Z;
$Z;

where c == d + 10 + e where
e == 10 and d == 10
-Test for Multiple ands

$Z -> $B;
let d
$Z -> $B;
let k
$Z -> $Z;
let

161

c(l)

c (n)

d(2) where
== n = 3 and

(n)

--

(1)

== (1 = k (n
== + 10)

1)

where

Test for proper use of "and" and implementation of


Parens

let c
let

let

$Z -> $Z;
$Z -> $Z;
$Z -> $Z;

where c(n) == d(n) + 12 where k == 100


and d(s) == 10 + e (s)
and e(k) == 20 + k

c(5)

--

Test for Multiple ands, multiple wheres and formal/variable collisions

$Z -> $Z;
let d
$Z -> $Z;
let e
$Z -> $Z;
let

where c(n) == d(n) + 12 where k == 100


and d(s) == 10 + e (s) where t == 100
and e(k) == 20 + k + t

c(5)

--

Test for Multiple ands, multiple wheres and formal/variable collisions

let

let

let

$Z -> $Z;
$Z -> $Z;
$Z -> $Z;

where c(n) == d(n) + 12 where t == 100


and d(s) == 10 + e (s) where t == 120
and e(k) == 20 + k + t

c(5)

---

Test for Multiple ands, multiple wheres and formal/variable collisions


Also test to see if the proper "t" (120) was picked up

let

let

let

$Z * $Z -> $Z;
$Z * $Z -> $Z;
$Z * $Z -> $Z;

162

where c(n,m) == d(n,m) + 12 where t == 100


and d(s,z) == 10 + e (s,z) where t == 120
and e(k,l) == 20 + k + t + 1

c(5,l)

--

Test for Multiple ands, multiple wheres and formal/variable collisions


Test specifically for functions with multiple arguments

$Z

-> $Z;

let

let

d $Z -> $Z;

let

$Z

-> $Z;

where c(n) == d(n) where t == 100


and d(s) == (e (s) where k == 2)
and e(k) == 20 + t

c(5)

--

Test for Multiple ands, multiple wheres and formal/variable collisions

let

let

let

$Z -> $Z;
$Z -> $Z;
$Z -> $Z;

c(10) where c(n) == d(n) where t == 100


and d(s) == e (s) where k == 10

and
--

e(r)

== 20 +

+k

Test for Multiple ands, multiple wheres and formal/variable collisions

let

let

let

$Z -> $Z;
$Z -> $Z;
$Z -> $Z;

c(10) where c(n) == d(n) + t where


and d(s) == e (s) where k == 10

and
--

e(r)

== 20 +

==

(r *

100 where

==

2)

+k

Test for Multiple ands, multiple wheres and formal/variable collisions

let

let

let

let f

$Z -> $Z;
$Z -> $Z;
$Z -> $Z;

$N ->

$Z;

c(10) where c(n) == d(n) + t where


and d(s) == e (s) where k == 10

and

e(r)

== 20 +

==

f (r)

163

(r *

100 where

==

2)

and
--

==

f(r)

Test for Multiple ands, multiple wheres and formal/variable collisions

let

let

let

let f

$Z -> $Z;
$Z -> $Z;
$Z -> $Z;

$N -> $Z;

c(10) where c(n) == d(n) + t where


and d(s) == e (s) where k == 10

and
and
--

e(r)
f(r)

== 20 +
== k

==

(r *

100 where

==

2)

f (r)

Test for Multiple ands, multiple wheres and formal/variable collisions

$Z -> $Z;
let d
$Z -> $Z;
let e
$Z -> $Z;
let

let f

$N -> $Z;

c(10) where c(n) == d(n) + t where


and d(s) == e (s) where k == 10

and
and

e(r)
f(r)

== 20 + r + f(r)
== if r = then 100

==

else f (r

(r *

1)

100 where

==

2)

endif

Test for Multiple ands, multiple wheres and formal/variable collisions


Test for if-then-else collisions with multiple ands, wheres

--

--

$Z -> $Z;
d $Z -> $Z;
let e
$Z -> $Z;
let

let

let f
let

$N ->

zebra

$Z;
$Z;

== d(n) + t where t == (r * 100 where


and d(s) == (e (s) where k == 10
and e(r) == 20 + r + f(r) + zebra
and f(r)==ifr = then 100 else f(r- 1) endif
and zebra
t)

c(10) where c(n)

==

2)

---

Test for Multiple ands, multiple wheres and formal/variable collisions


Test for if-then-else collisions with multiple ands, wheres

let

let

let

$Z -> $Z;
$Z -> $Z;
$Z -> $Z;

164

where c(n) == d(n) + 12 where t == 100


and d(s) == (10 + e (s) where k == 100
and e(k) == 20 + k + t)

c(5)

--Note the use of parenthesis here if they are removed, the program will
-bomb because t will be undefined
:

ERROR TESTING
let

:$z;

letj:$Z;
let i:$z;

where i ==x%j
and x ==5 and j ==0

- Gives

let

Division by Zero run time error

b:$b;

let i:$Z;
let j:$z;
let

n:$n;

let x: $z;

b then i
~(b A b) then j
else x endif
where
b == i=2 where
if

elsif

i==0

and where j
and where z == 69
Gives two parser errors
where following "and"

let fac

fac (5)

$N

line 13

and

14,

undefined and

-> $N;

where fac

- Check

(n)

==

fac (n

1)

for stack overflow

too_much where too_much == 1000

1000

- Check for Multiplication Overflow


too_much where too_much == 30000 + 30000

- Check

for Addition overflow

165

too_much where too_much == -30000

Check

--

for Subtraction

30000

Overflow

:$Z->$B;
letd:$Z->$B;
$Z -> $Z;
let k
let g
$Z -> $Z;
letc

c(l)

d(2) where

(n)

(1)

c
--

== ( 1 = k (n - 1 ) where
== + 10) and
(n) == n = 3
1

Test for proper use of comments; note that there is no


delimiter on the second line of comments, as there should

--be

MISCELLANEOUS TESTS
let

b:$b;

let i:$Z;

let j:$z;
let

n:$n;

let x: $z;

if(bV~b)theni

V ~b)

elsif (b

then

where
b == i=2 where

else x endif

i==0
and j ==2
and x == 69

Test for not construct, boolean constructs

let

b:$b;

let i:$Z;
let j:$z;
let

n:$n;

let x: $z;

if~(bV~b)theni
elsif

~(b

A ~b) then j

else x endif

where

== i=2 where
i==0
and j ==2
and x == 69
b

166

should give 2
Check and, or, notand, notor

--

---

Check

Especially, check

let

a:$Z;

let

b:$z;

let

y:$n;

let

else, elseif
all in

combination

$z;

let x:

let

if,

$n*$n->$n;
times $n*$n->$n;
f:

f(30,30)

where

== times(a,b) where
times(x,y) == x*y

f(a,b)

Multiargument Checking
Natural Type Checking

let

a:$Z;

let

b:$z;

let

y:$z;
$z;

let x:

let
let

$z*$z->$z;
times $n*$n->$z;

f:

f(30,4)

where

== times(a,b) where
times(x,y) ==

f(a,b)

if

= l)thenx%y

else 2 endif

end

Integer Division Checking

c $Z -> $B;
letd:$Z->$B;
let k
$Z -> $Z;
let g
$Z -> $Z;
let

c(l)

d(2) where

(n)

==

c (n)
--

=k

(n - 1) where
+ 10) and
== n = 3

(1

k 0) ==

Test for proper use of "and" and implementation of


Parens

167

APPENDIX O

ROCK COMPILER

USER'S

MANUAL

Installation

I.

The rock compiler program comes on a 5.25" disk with all


domain programs necessary to run it. To install this
program on another floppy disk or a hard disk, use the following
public

procedures:
1)

Change

the system drive to the disk drive containing the

floppy disk.
2) Type "INSTALL", followed by a space and the drive and
directory on which you want the program installed.

Note

that the

Rock compiler

uses three unsupplied files to

RASM86, LINK86, and your choice of word processor. The


RASM86 and LINK86 programs must be installed on the same

operate:

directory as the compiler.

Running the Compiler

II.

a.

Type

figure

in

"ROCK"

and wait for the screen display shown

in

to appear.

ROCK COMPILER
Press Escape

Program

to

Key

to Exit

Compiler

Compile ->

Figure

b. When the prompt appears, type in the file name of the


source file you want to compile, then press return. The
compiler will accept directory specifications in the
If the source file is found, the
file designation.
compilation will begin immediately, and the screen will
appear as shown in figure 2. If the file is not found,
the screen will appear as shown in figure 3.

168

a successful compilation takes place, the prompt for


If the compilation is not
file reappears.
successful, error messages will appear on the screen,
c.

If

a source

and a copy of these messages can be found

in a file

ROCK COMPILER
Press Escape

Program

to

Compile ->

Key

to Exit

Compiler

SQRT.PHI
Compiling: Please Wait

Figure 2

ROCK COMPILER
Key

to Exit

File not

Found

Press Escape

Program

to

Compile ->

Compiler

NOTFOUND

Press

ESCAPE

to exit,

any other key

Figure 3

A typical error display is shown in


After perusing the errors, you may press any
key to return to the prompt for a source file.
named

Errors.Phi.

figure 4.

169

to continue

ROCKY ERRORS
formals list missing or error
misplaced or missing
number of errors = 2
line

line

PRESS

formals

in

list

ANY KEY TO CONTINUE


Figure 4

If

d.
file

compilation

is

will be created.

successful, both an .exe

occurs, neither

file will

WARNING

If

same

prefix,

and an

.obj

In the event that an error

be created.

you choose to compile two programs with


ensure you save the first one before

the

compiling the second one; otherwise, the second


compilation will overwrite the output file of the first
compilation.

To cleanly stop the compiler, press the ESCAPE key any


e.
time the system asks for an input. If you have started
to

compile a program and you need a "panic"

exit,

press

"Control-Break". If you do this, the cursor will not


reappear on the screen. However, you can get it back by
running the ROCK program again and making a normal exit.

III.

Error Handling

those found during


Errors are divided into two categories
compilation and those found during run time. The following two
sections list the errors messages from both categories which you
might encounter. Each message includes a brief synopsis of what
causes the error.
:

COMPILER ERRORS
Message
incomplete

Explanation
Either an

'l->'

where

without following

logical

OR is

'/',

or "I-" was found


was expected.

single backslash

where a
(V)

170

"I"

"l->"

was found

logical or construct

was expected.

'$'

without following

RVNVZVB'.or
invalid numeric

constant
literal

==>

incomplete type declaration was found.

An

illegal

in this

3.

constant

example,

was found;

"3."

An

unterminated literal was


found, or a literal spanned
more than one line.

without ending

A character with

unidentified char
in input

An

'1'

program ==> #

found

in the

no meaning was

source

MEMORY OVERFLOW

The source program

DURING COMPILATION

for the host

machine

file; '#',

in this

example.

too big

is

to compile.

error in statement

following

==>

An

illegal

statement follows
'*',

the specified character,

in the

example.

error in type

definition following

==>

An

illegal type definition follows the


specified character; '*', in the example.

An

unable to complete
definition of
after

keyword

after

LET

missing or misplaced

unspecified error was found

LET, and the compiler is


so completely sandbagged that
it cannot recover.

blockbody

A declaration, preceded by

';'

after definition

"LET", was not followed by a semicolon.

valid qualexp/exp

An

invalid expression

was found

not found in the def/auxdef

An

valid typeexp not found


in the

expression defining a
type was either missing or incorrect.

def

Formals were expected but not found,


or formals were incompletely specified.

formals list missing


or error in formals list

misplaced or missing

A PHI keyword or delimiter was

')'

expected or not found;


at least one identifier
must follow keyword

TYPE

found without an

in the

example.

identifier.

TYPE
Improper or no expression found

unable to complete
def/auxdef following

keyword

')'

following

AND

171

AND.

Improper or no definition following

missing or invalid auxdef


after

keyword

WHERE

WHERE
Formals found without closing

missing or misplaced
closing paren in formals

parenthesis.

list

error in processing

One

multiple Actuals

error

missing

FILE was found without


name being designated.

after

literal

keyword FILE

IF statement

actual.

file-

keyword was spotted, but the


following expression was illegal.

missing or invalid

exp following

was found, but an


was spotted in a subsequent

actual

KEYWORD

No ENDIF

w/o ENDIF

to close off an IF statement.

error in formals

"l->" found, but the

preceding

list

l->

preceding

it

formals
contained an error.

A list of elements was found

missing or invalid
QualExp following

with an illegal expression in

it.

COMMA operator
An

ArgBinding
check QualExp

improper expression in an
argument binding was found, or
the closing bracket on an argument binding

error in
-

or closing bracket

was not found.

OZONE LEVEL

Unimplemented

I -

feature found,

for 19.99 the feature can be

implemented

in

1999

NUMERIC VALUE EXPECTED

Non- numeric type found where a


numeric type was expected.

NATURAL EXPECTED

Natural type was not found where


it was expected.

INTEGER OR NATURAL EXPECTED


is

ERROR IN TUPLE DEFINITION

Either an integer or natural type


proper, but neither was found.

A tuple is improperly defined


the source file used

types or

improper

number of types in defining


mean
variable was improperly defined.

the tuple. This can also

a single

UNDEFINED VARIABLE
IN AND SCOPE

An
in

172

undefined variable was found


one of the two branches of an

in its scope.

FUNCTION WITHOUT
FUNCTION DEFINITION

declaration of

FORMALS MISMATCHED

Formals

function

FUNCTION CALLED WITHOUT


FUNCTION DEFINITION

No

REAL NUMBER EXPECTED

An

type and formals.

its

function definition
in either type or
as those in the function's declaration.
in a

are not the

number

was defined without a

same

function definition found for

the function called.

INVALID CONSTANT
EXPRESSION

An

BOOLEAN VALUE EXPECTED

was found where


number was expected.

incorrect type

a real

invalid constant

was found.

boolean value was expected, but

none was found.

BOOLEAN OPERATOR EXPECTED A boolean operator was expected,


but none

OUT OF RUN-TIME

was found.

Not enough space to accommodate


program during run-time.

MEMORY SPACE

the

RUN-TIME ERRORS
DIVISION BY ZERO

Division by zero attempted.

MULTIPLICATION OVERFLOW

A multiplication operation resulted in


a numeric value outside the language limits.

ADDLTION OVERFLOW

An

addition operation resulted in

a numeric value outside the language limits.

SUBTRACTION OVERFLOW

subtraction operation resulted

numeric value outside the


language limits.

in a

STACK/VARIABLE SPACE CRASH The

173

stack overwrote the variable space.

INITIAL DISTRIBUTION LIST

No. Copies

1.

Library,

Code 0142

Naval Postgraduate School


Monterey, California 93943-5002
2.

Chairman, Code 52
Department of Computer Science
Naval Postgraduate School
Monterey, California 93943

3.

Computer Technology Programs, Code 37


Naval Postgraduate School
Monterey, California 93943

4.

D. L. Davis, Code 52Dv


Department of Computer Science
Naval Postgraduate School
Monterey, California 93943

5.

B.

J.

MacLennan, Code 52M1

Department of Computer Science


Naval Postgraduate School
Monterey, California 93943
6.

Capt.

J.

E. Connell,

USMC

#5 Jack Ray Park


Wentzville, Missouri 63385
7.

Maj. E.

J.

Cole,

USMC

156HavilandRd
Ridgefield, Connecticut
8.

06877

Defense Technical Information Center

Cameron

Station

Alexandria, Virginia

22304-6145

174

Thesis
C53169
c.l

Thesis
C53159
c.l

Cole
Implementation of a
compiler for the functional programming language PHI - (D.

Coie

Implementation of a
compiler for the functional programming language PHI - <D.

Anda mungkin juga menyukai