|
|
1.1 root 1: .\" Copyright (c) 1980 Regents of the University of California.
2: .\" All rights reserved. The Berkeley software License Agreement
3: .\" specifies the terms and conditions for redistribution.
4: .\"
5: .\" @(#)manCh6.rno 6.1 (Berkeley) 4/29/86
6: .\"
7: .NS 1 "Implementation Notes"
8: .pp
9: FP was written in 3000 lines of \s-2FRANZ LISP\s+2 [Fod 80].
10: Table 1 breaks down the distribution of the code by functionality.
11: .(b
12: .sp
13: .TS
14: center box;
15: c|c
16: l|n.
17: Functionality % (bytes)
18: =
19: compiler 34
20: user interface 32
21: dynamic stats 16
22: primitives 14
23: miscellaneous 3
24: .TE
25: .sp 4p
26: .ce
27: .b "Table 1"
28: .sp 4p
29: .)b
30: .NS 2 "The Top Level"
31: .pp
32: The top-level function $runFp$ starts up the subsystem by calling
33: the routine \fIfpMain\fP,
34: that takes three arguments:
35: .BB
36: .np
37: A boolean argument that says whether debugging output
38: will be enabled.
39: .np
40: A Font identifier. Currently the only one is supported \fB'asc\fP (ASCII).
41: .np
42: A boolean argument that identifies whether the interpreter
43: was invoked from the shell. If so then all exits from FP return the
44: user back to the shell.
45: .EB
46: .pp
47: The compiler converts the FP functions into LISP equivalents in two
48: stages: first it forms the parse tree, and then it does the
49: code generation.
50: .sp
51: .NS 2 "The Scanner"
52: .sp
53: .pp
54: The scanner consists of a main routine, \fIget_tkn\fP, and a set of
55: action functions. There exists one set of action functions
56: for each character font
57: (currently only ASCII is supported). All the action functions are named
58: $scan dl "<font>"$, where $"<font>"$ is the specified font,
59: and each is keyed
60: on a particular character (or sometimes a particular character-type \-
61: \*(EG a letter or a number). \fIget_tkn\fP returns
62: the token type, and any ancillary
63: information, \*(EG for the token "name" the name itself will also be provided.
64: (See Appendix C for the font-token name correspondences).
65: When a character has been
66: read the scanner finds the action function by doing a
67: .sp
68: .ce 1
69: $(get ~ 'scan dl~ "<font> <char>")$
70: .sp
71: A syntax error message will be generated if
72: no action exists for the particular character read.
73: .sp
74: .NS 2 "The Parser"
75: .sp
76: The main parsing function, \fIparse\fP, accepts a single argument, that
77: identifies the parsing context, or
78: type of construct being handled.
79: Table 2
80: shows
81: the valid parsing contexts.
82: .(b
83: .sp 2
84: .TS
85: center box;
86: c|c
87: l|l.
88: \fBid\fP \fBconstruct\fP
89: =
90: top_lev initial call
91: constr$dd$ construction
92: compos$dd$ composition
93: alpha$dd$ apply-to-all
94: insert$dd$ insert
95: ti$dd$ tree insert
96: arrow$dd$ T{
97: .nf
98: affirmative clause
99: of conditional
100: .fi
101: T}
102: semi$dd$ T{
103: .nf
104: negative clause
105: of conditional
106: .fi
107: T}
108: lparen$dd$ parenthetic expr.
109: while$dd$ while
110: .TE
111: .sp
112: .ce 1
113: .b "Table 2, Valid Parsing Contexts"
114: .)b
115: .sp
116: .EQ
117: delim off
118: .EN
119: .pp
120: For each type of token there exists a set of parse action functions,
121: of the name \fIp$<tkn-name>\fP. Each parse-action function is keyed
122: on a valid context, and it is looked up in the same manner as
123: scan action functions are looked up. If an action function cannot
124: be found, then there is a syntax error in the source code.
125: .EQ
126: delim $$
127: .EN
128: Parsing proceeds as follows: initially $parse$ is called from the top-level,
129: with the context argument set to \fI\*(lqtop_lev\*(rq\fP.
130: Certain tokens cause parse to
131: be recursively invoked using that token as a context. The result
132: is the parse tree.
133: .sp
134: .NS 2 "The Code Generator"
135: .pp
136: The system
137: compiles FP source into LISP source. Normally, this code is interpreted by
138: the \s-2FRANZ LISP\s+2 system.
139: To speed up the implementation, there is an option to
140: compile into machine code using the \fIliszt\fP compiler [Joy 79].
141: This feature
142: improves performance tenfold,
143: for some programs.
144: .pp
145: The compiler expands all functional forms into their LISP equivalents
146: instead of
147: inserting calls to functions that generate the code
148: at run-time. Otherwise, \fIliszt\fP
149: would be ineffective in speeding up execution since
150: all the functional forms would
151: be executed interpretively.
152: Although the amount of code
153: generated by an expanding compiler
154: is 3 or 4 times greater than
155: would be generated by a non-expanding compiler, even in interpreted mode
156: the code runs twice as quickly as unexpanded code.
157: With \fIliszt\fP compilation this performance advantage increases to more
158: than tenfold.
159: .pp
160: A parse tree is either an atom or a hunk of parse trees. An atomic parse-tree
161: identifies either an fp built-in function or
162: a user defined function.
163: The hunk-type parse tree represents functional forms, \*(EG compose or
164: construct. The first element identifies the functional form and the other
165: elements are its functional parameters (they may in turn be
166: functional forms). Table 3 shows the parse-tree formats.
167: .(b
168: .sp 2
169: .TS
170: center box;
171: c|c
172: l|l.
173: Form Format
174: =
175: user-defined <atom>
176: fp builtin <atom>
177: apply-to-all $"{" "alpha" dd~~PHI"}"$
178: insert $"{"insert dd ~~PHI"}"$
179: tree insert $"{"ti dd ~~PHI"}"$
180: select $"{"select dd ~mu"}"$
181: constant $"{"constant dd ~mu"}"$
182: conditional $"{"condit dd ~~PHI sub 1 ~~PHI sub 2 ~~PHI sub 3"}"$
183: while $"{"while dd ~~PHI sub 1 ~~PHI sub 2"}"$
184: compose $"{"compos dd ~~PHI sub 1 ~~PHI sub 2"}"$
185: construct $"{"constr dd ~~PHI sub 1~~PHI sub 2~~,...,~~PHI sub n ~nil"}"$
186: .TE
187: .sp
188: Note: $PHI$ and the $PHI sub k$ are parse-trees and $mu$ is an optionally
189: signed integer constant.
190: .sp
191: .ce 1
192: .b "Table 3, Parse-Tree Formats"
193: .sp
194: .)b
195: .NS 2 "Function Definition and Application"
196: .sp
197: .pp
198: Once the code has been generated, then
199: the system defines the function via \fIputd\fP.
200: The source code is placed onto
201: a property list, $'sources$, to permit later access by the system
202: commands.
203: .pp
204: For an application,
205: the indicated function is compiled and then defined, only temporarily, as
206: $tmp dd$. The single argument is read and
207: $tmp dd$ is applied to it.
208: .NS 2 "Function Naming Conventions"
209: .pp
210: When the parser detects a named primitive function, it returns the name
211: $"<"name">" df$,
212: where \fI<name>\fP is the name that was parsed (all primitive
213: function-names
214: end in $df$). See Appendix D for the symbolic (\*(EG
215: compose, $+$) function names.
216: .pp
217: Any name that isn't found in the list of builtin functions
218: is assumed to represent a user-defined function; hence,
219: it isn't possible to redefine FP primitive functions.
220: FP protects itself
221: from accidental or malicious internal destruction
222: by appending the suffix \*(lq$_fp$\*(rq
223: to all user-defined function names, before
224: they are defined.
225: .NS 2 "Measurement Impelementation"
226: .pp
227: This work was done by Dorab Patel at UCLA.
228: Most of the measurement code is in the file 'fpMeasures.l'.
229: Many of the remaining changes were effected in
230: \&'primFp.l', to add calls on
231: the measurement package at run-time; to 'codeGen.l', to add
232: tracing of user defined functions; to 'utils.l', to add the new system
233: commands; and to 'fpMain.l',
234: to protect the user from forgetting to output statistics when he leaves
235: FP.
236: .NS 3 "Data Structures"
237: .pp
238: All the statistics are in the property list of the global symbol
239: \fIMeasures\fP.
240: Associated with each
241: each function (primitive or user-defined, or functional form)
242: is an
243: indicator;
244: the statistics gathered for each function are the corresponding values.
245: The names corresponding to primitive functions and functional forms end
246: in '$dl$fp' and the names corresponding to
247: user-defined functions end in '_fp'.
248: Each of the property values is an
249: association list:
250: .sp
251: .(l I
252: (get 'Measures 'rotl$dl$fp) ==> ((times . 0) (size . 0))
253: .)l
254: .sp
255: .pp
256: The car of the pair is the name of the statistic (\*(IE times, size)
257: and the cdr is the value.
258: There is one exception.
259: Functional forms have a statistic called funargtyp.
260: Instead of being a dotted pair, it is a list of two elements:
261: .sp
262: .(l I
263: (get 'Measures 'compose$dl$fp) ==>
264: ((times . 2) (size . 4) (funargtyp ((select$dl$fp . 2) (sub$dl$fp . 2))))
265: .)l
266: .sp
267: .pp
268: The car is the atom 'funargtyp' and the cdr is an alist.
269: Each element of the alist consists of a functional
270: argument-frequency dotted pair.
271: .pp
272: The statistic packages uses two other global symbols.
273: The symbol DynTraceFlg is non-nil if dynamic statistics are being
274: collected and is nil otherwise.
275: The symbol TracedFns is a list (initially nil) of the names of the
276: user functions being traced.
277: .NS 3 "Interpretation of Data Structures"
278: .NS 4 "Times"
279: .pp
280: The number of times this function has been called.
281: All functions and functional forms have this statistic.
282: .NS 4 "Size"
283: .pp
284: The sum of the sizes of the arguments passed to this
285: function.
286: This could be divided by the times statistic to give the average
287: size of argument this function was passed.
288: With few exceptions, the size of an object is its top-level length
289: (note: version 4.0 defined the size as the total number of \fIatoms\fP
290: in the object);
291: the empty sequence, \*(lq<>\*(rq,
292: has a size of 0 and all other atoms have size of one.
293: The exceptions are: \fIapndl, distl\fP (top-level length
294: of the second element), \fIapndr, distr\fP (top-level length of the first
295: element), and \fItranspose\fP (top level length of each top level
296: element).
297: .pp
298: This statistic is not collected for some primitive functions
299: (mainly binary operators like +,-,\(**).
300: .NS 4 "Funargno"
301: .pp
302: The number of functional arguments supplied to a functional
303: form.
304: .pp
305: Currently this statistic is gatherered only for the construction
306: functional form.
307: .NS 4 "Funargtyp"
308: .pp
309: How many times the named function was used as a
310: functional parameter to the particular functional form.
311: .NS 2 "Trace Information"
312: .pp
313: The level number of a call shows the number
314: of steps required to execute the function on an ideal machine
315: (\*(IE one with unbounded resources).
316: The level number is calculated under an assumption of infinite
317: resources, and
318: the system evaluates the
319: condition of a conditional before evaluating
320: either of its clauses.
321: The number of functions executed at each level can give an idea of the
322: distribution of parallelism in the given FP program.
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.