anticipated the free-format syntax of ALGOL 60's descendants,
including Pascal and C. The DEFINE statement, which supports
syntactic extension of the language, was an interesting experiment not
-emulated in most later designs.</para>
+emulated in most later designs. And, as the Simpson's Rule example
+illustrates, MAD even supported what was later called
+<quote>higher-order programming</quote> — passing around
+function-valued variables!</para>
<para>In most of the respects we've described, however, MAD is very
typical of its time. This will become apparent from a look at the
the data to be unpacked into int or double arrays, but that code
would have been far more complicated to generate and hard to read.</para>
-<para>In original MAD all variables were global, and arguments were
-passed by reference. In the interests of generating reasonably clean
-C, this implementation makes variables local to the functions in which
-they occur and passes arguments by value. Exploiting the original MAD
-behaviors was considered bad style even then, and none of the examples
-given in the manual rely on them.</para>
+<para>In original MAD arguments were passed by name. This is
+difficult to simulate in C, so the generated code passes arguments by
+value. None of the examples given in the manual rely on
+pass-by-reference, and given that all variables are global it is
+difficult to imagine code that would.</para>
<para>Label arrays, array-mode variables, and the associated
-computed-transfer statement are not implemented. Neither are ERROR
-RETURN, multiple ENTRY points, or TAPE and DRUM statements.</para>
+computed-transfer statement are not implemented. Neither are multiple
+ENTRY points, or TAPE and DRUM statements.</para>
+
+<para>Only the no-argument case of ERROR RETURN is supported. The
+language describing the more general case of this feature is deeply
+confusing, and I was unable to extract a coherent semantics for
+it. None of the examples use the general case.</para>
<para>On the other hand, some limits in original MAD are not present
in this implementation, mainly because it would have required actual
have been preserved as ISO soft-hyphen entities.</para>
<para>The program listings in the original failed to distinguish
-between 0 and O; this does not reflect incompetence but rather the
-fact that typewriters of the period did not have a separate 0 key.
-This distinction has been restored.</para>
+between 0 and O, and between 1 and l; this does not reflect
+incompetence but rather the fact that although computer line printers
+of the period had separate forms for these character pairs,
+typewriters of the period did not have. This distinction has been
+added in the present text.</para>
<para>Some program listings in the original were missing continuation
punches required by the language. These have been corrected, and the
corrections noted in XML coments.</para>
+<para>Most of the original listings were typed so there was whitespace
+between remark or continuation punches and following statements or
+comments. The language's card-based, column-sensitive format did not
+require this, however, and a few listings had a remark or continuation
+character stuck to the first statement token. These have been
+whitespace-separated so that a modern token-oriented parser can read
+them.</para>
+
<para>In the original, the description of flowcharting conventions
in Chapter 1 include small hand-drawn geometrical shapes after each
of the items A, B, and the words "diamonds" and "rectangles" in item
sys.stderr.write('"%s", line %d: %s\n' % (file, line, msg))
# All MAD variables are global, you have to simulate locals using SAVE DATA and
-# RETURN DATA. Thus most of the variable lookup tables about are straight
-# dictionaries not qualified by current function name. typedict is an
-# exception; we use this to generate per-function variables as C auto
-# variables and get nicer C code. This would break if two MAD external
-# functions deliberately shared a global, but this doesn't happen in
-# any of the examples.
-typedict = {} # Dictionary of per-function dictionaries of locals
+# RETURN DATA. Thus the variable lookup tables about are straight
+# dictionaries not qualified by current function name.
+typedict = {} # Types of globals
normalmode = 'double' # Default type as set by NORMAL statement
dummycount = 0 # Count of FOR VALUES statements
for (file, line, label, statement) in deck:
if statement[0] == 'boolean':
for var in statement[1:]:
- typedict[currentfunc][var] = 'bool'
+ typedict[var] = 'bool'
elif statement[0] == 'dimension':
for (var, dimlist) in statement[1]:
dimensions[var] = dimlist
elif statement[0] == 'entry':
currentfunc = statement[1]
funcline = line
- typedict[currentfunc] = {}
elif statement[0] == 'integer':
for var in statement[1:]:
- typedict[currentfunc][var] = 'int'
+ typedict[var] = 'int'
elif statement[0] == 'normal':
global normalmode
normalmode = statement[1]
(fmt, types) = fmt_convert(format[statement[1]])
for (vtype, var) in zip(types, statement[2:]):
if type(var) == type(()) and var[0] == 'range':
- typedict[currentfunc][var[1]] = vtype
+ typedict[var[1]] = vtype
else:
- typedict[currentfunc][var] = vtype
+ typedict[var] = vtype
# Type inference loop. We initialized for this by deducing types
# from READ FORMAT statements. INTEGER, and BOOLEAN declarations
# above. Now propagate markers of non-normalmode type through
deductions += 1
elif statement[0] == 'restore':
for var in statement[1]:
- typedict[currentfunc][var] = normalmode
+ if var not in typedict:
+ typedict[var] = normalmode
+ deductions += 1
elif statement[0] == 'substitution':
# Propagate type markers through assignment
var = statement[1]
m = mode(statement[2])
- typedict[currentfunc][var] = m
- if m != normalmode and typedict[currentfunc][statement[1]]!=m:
+ typedict[var] = m
+ if m != normalmode and typedict[statement[1]]!=m:
deductions += 1
if deductions == 0:
break
"Compute the return type of an expression"
#print "->mode", t
if t[0] == 'variable':
- #print "<-mode of ", t[1], typedict[currentfunc].get(t[1], normalmode)
- return typedict[currentfunc].get(t[1], normalmode)
+ #print "<-mode of ", t[1], typedict.get(t[1], normalmode)
+ return typedict.get(t[1], normalmode)
elif t[0] in ('p', 'abs') or t[0] in ('+', '-') and len(t) == 2:
#print "<-mode of ", t[1]
return mode(t[1])
return "} else {"
elif statement[0] == 'entry':
currentfunc = statement[1]
- types = typedict[currentfunc]
rep = "\n" + returntypes.get(currentfunc, normalmode) + " " + currentfunc[:-1] + "("
defaulted = []
if len(statement) > 2:
for (dummy, var) in statement[2]:
declarator = ("*" * arraydepths.get(var, 0)) + var
- if var in types:
- rep += types[var] + " " + declarator + ", "
- del types[var]
+ if var in typedict:
+ rep += typedict[var] + " " + declarator + ", "
+ del typedict[var]
else:
rep += normalmode + " " + declarator + ", "
defaulted.append(var)
- rep = rep[:-2]
+ if rep.endswith(", "):
+ rep = rep[:-2]
rep = rep + ") {"
#if defaulted:
# sys.stderr.write("warning: defaulted base type for %s\n" % ", ".join(defaulted))
- declarations = "\n"
- for vtype in ('double', 'int', 'bool', 'char'):
- vars = filter(lambda x: types[x] == vtype, types.keys())
- if vars:
- declarations += vtype
- for var in vars:
- declarations += " " + var
- if var in dimensions:
- for dim in dimensions[var]:
- declarations += "[" + print_C_expr(dim) + "]"
- declarations += ","
- declarations = declarations[:-1] + "; "
- if declarations:
- rep += " " + declarations[:-1]
return rep
elif statement[0] == 'error_return':
return 'puts("ERROR RETURN"); exit(1);'
popoff = list(statement[1])
popoff.reverse()
for var in popoff:
- rep += "%s = (%s)(*--recursor); " % (var, typedict[currentfunc].get(var, normalmode))
+ rep += "%s = (%s)(*--recursor); " % (var, typedict.get(var, normalmode))
return rep;
elif statement[0] == 'return':
if len(statement) == 1:
out.write('#include <%s.h>\n' % header)
if headers:
out.write("\n")
- needbool = False
- for funvars in typedict.values():
- if 'bool' in funvars.values():
- needbool = True
- if needbool:
+ if 'bool' in typedict.values():
out.write("typedef int bool;\n")
for (id, value) in static.items():
out.write('static const char *%s\t= "%s";\n' % (id,fmt_convert(value)))
+ declarations = ""
+ for vtype in ('double', 'int', 'bool', 'char'):
+ vars = filter(lambda x: typedict[x] == vtype, typedict.keys())
+ if vars:
+ declarations += vtype
+ for var in vars:
+ declarations += " " + var
+ if var in dimensions:
+ for dim in dimensions[var]:
+ declarations += "[" + print_C_expr(dim) + "]"
+ declarations += ","
+ declarations = declarations[:-1] + "; "
+ if declarations:
+ out.write(declarations[:-1])
+ out.write("\n")
+
indent = 0
global sourceline
scopes = [] # THROUGH scopes that are pending