#!/usr/bin/env python
-reserved = ('CONDITIONAL', 'CONTINUE', 'DIMENSION', 'END', 'ENTRY', 'EXECUTE',
- 'EXTERNAL', 'FOR', 'FORMAT', 'FUNCTION', 'INTEGER',
- 'INTERNAL', 'OF', 'PAUSE', 'PRINT', 'PROGRAM', 'READ',
- 'RETURN', 'THROUGH', 'TO', 'TRANSFER', 'VALUES', 'VECTOR',
- 'WHENEVER',
+reserved = ('BOOLEAN', 'CONDITIONAL', 'CONTINUE', 'DIMENSION', 'END',
+ 'ENTRY', 'EXECUTE', 'EXTERNAL', 'FOR', 'FORMAT',
+ 'FUNCTION', 'INTEGER', 'INTERNAL', 'OF', 'PAUSE', 'PRINT',
+ 'PROGRAM', 'READ', 'RETURN', 'THROUGH', 'TO', 'TRANSFER',
+ 'VALUES', 'VECTOR', 'WHENEVER',
# This is a pseudo-keyword generated early in compilation.
'COMMENT')
'ABS', 'POW',
)
+logops = ('NOT', 'OR', 'AND', 'THEN', 'EQV',
+ 'EQ', 'NE', 'LT', 'LE', 'GT', 'GE',)
+
# Tokens
t_SEMI = r';'
scopes = []
targets = {}
headers = []
+funcnames = []
currentfunc = 'main.'
typedict = {'main.':{}}
# Statement level
+## BOOLEAN
+def p_boolean(t):
+ 'statement : BOOLEAN boollist'
+ t[0] = ('boolean',) + tuple(t[2])
+def p_boollist(t):
+ 'boollist : NAME'
+ t[0] = [t[1]]
+ typedict[currentfunc][t[1]] = 'bool'
+def p_boollist_continue(t):
+ 'boollist : boollist COMMA NAME'
+ t[0] = t[1] + [t[3]]
+ typedict[currentfunc][t[1]] = 'bool'
+
## CONTINUE
def p_statement_continue(t):
'statement : CONTINUE'
currentfunc = t[3]
t[0] = ('entry', currentfunc)
typedict[currentfunc] = {}
+ funcnames.append(currentfunc)
## EXECUTE
def p_execute(t):
## INTEGER
def p_integer(t):
- 'statement : INTEGER varlist'
+ 'statement : INTEGER intlist'
t[0] = ('integer',) + tuple(t[2])
-def p_varlist(t):
- 'varlist : NAME'
+def p_intlist(t):
+ 'intlist : NAME'
t[0] = [t[1]]
-def p_varlist_continue(t):
- 'varlist : varlist COMMA NAME'
+ typedict[currentfunc][t[1]] = 'int'
+def p_intlist_continue(t):
+ 'intlist : intlist COMMA NAME'
t[0] = t[1] + [t[3]]
+ typedict[currentfunc][t[3]] = 'int'
## INTERNAL FUNCTION
def p_internal(t):
"statement : INTERNAL FUNCTION FUNCALL application EQUALS expression"
t[0] = ('internal', t[3], tuple(t[4]), t[6])
+ funcnames.append(t[3])
## PAUSE
def p_pause(t):
def p_read_format(t):
'statement : READ FORMAT NAME COMMA varlist'
t[0] = ('read', t[3]) + tuple(t[5])
+def p_varlist(t):
+ 'varlist : NAME'
+ t[0] = [t[1]]
+def p_varlist_continue(t):
+ 'varlist : varlist COMMA NAME'
+ t[0] = t[1] + [t[3]]
+
## THROUGH
def p_through_for(t):
'statement : NAME EQUALS expression'
newvar = t[1]
t[0] = ('substitution', newvar, t[3])
- typedict[currentfunc][newvar] = 'double'
# Expression parsing
t[0] = ('variable', t[1], tuple(t[2]))
var = t[1]
refcount[var] = refcount.get(var, 0) + 1
- if not var in typedict[currentfunc]:
- typedict[currentfunc][var] = 'double'
def p_function_application(t):
'expression : FUNCALL application'
var = t[1]
t[0] = ('variable', var)
refcount[var] = refcount.get(var, 0) + 1
- if not var in typedict[currentfunc]:
- typedict[currentfunc][var] = 'double'
# Error handling
dimensions[var] = dimlist
elif statement == 'entry':
currentfunc = statement[1]
+ funcline = line
elif statement[0] == 'integer':
for var in statement[1:]:
typedict[currentfunc][var] = 'int'
elif statement[0] == 'substitution':
typedict[currentfunc][statement[1]] = 'double'
- elif statement[0] in ('read', 'print'):
- pass
elif statement[0] == 'values':
var = statement[1]
if var in refcount:
untyped.remove(var)
else:
format[var] = statement[2]
+ # Do type deductions from format fields
+ for card in deck:
+ (file, line, label, statement) = card
+ if statement[0] == 'read':
+ if statement[1] not in format:
+ croak(card, "uninitialized format string" +`statement[1]`)
+ else:
+ (fmt, types) = fmt_convert(format[statement[1]])
+ for (type, var) in zip(types, statement[2:]):
+ typedict[currentfunc][var] = type
# Now associate entry point names with function definitions:
for i in range(len(deck)):
(file, line, label, statement) = deck[i]
else:
croak(deck[i], 'no EXTERNAL declaration matches this ENTRY')
+def mode(t):
+ "Compute the return type of an expression"
+ if t[0] == 'variable':
+ return typedict[currentfunc].get(t[1], 'double')
+ elif t[0] in logops:
+ return 'bool'
+ else:
+ return 'double'
+
def prin1(t):
if t[0] == 'variable':
res = t[1]
elif t[0] == 'eqv':
return '(%s == %s)' % (print_expr(t[1]), print_expr(t[2]))
elif t[0] == 'abs':
- return 'abs(%s)' % print_expr(t[1])
+ argmode = mode(t[1])
+ if argmode == 'double':
+ return 'fabs(%s)' % print_expr(t[1])
+ else:
+ return 'abs(%s)' % print_expr(t[1]) # int or bool
elif t[0] in ('intnum', 'floatnum'):
return t[1]
else:
def fmt_convert(fmt, write=True):
"Convert MAD format string to C printf/scanf"
res = ''
+ types = []
str = fmt[1:-1]
while True:
if str[0] == '*':
i += 1
res += ('%' + str[1:i] + 'g') * count
str = str[i:]
+ types += ['double'] * count
elif str[0] == 'H':
if write:
res += str[1:count+1]
str = str[count+1:]
+ types += ['string']
elif str[0] == 'I':
i = 1
while str[i] in '0123456789':
i += 1
res += ('%' + str[1:i] + 'd') * count
str = str[i:]
+ types += ['int'] * count
else:
sys.stderr.write('"%s", line %d: invalid field code %s at %d in format string %s!\n' % (sourcefile, sourceline, `str[0]`, len(fmt)-len(str), `fmt`))
sys.exit(1)
if write:
res = res[1:]
res = res + '\\n'
- return res
+ return (res, types)
def print_statement(statement):
- if statement[0] in ('dimension',
+ if statement[0] in ('boolean',
+ 'dimension',
'external_function',
- 'internal',
'integer',
'values'):
pass
rep = rep[:-2]
rep = rep + ") {"
declarations = ""
- for type in ('double', 'int'):
+ for type in ('double', 'int', 'bool'):
vars = filter(lambda x: types[x] == type, types.keys())
if vars:
declarations += type + " " + ", ".join(vars) + "; "
return 'goto ' + statement[1] + ';'
elif statement[0] == 'if':
return 'if (' + print_expr(statement[1]) + ') ' + print_statement(statement[2])
+ elif statement[0] == 'internal':
+ return ' double %s {return %s;}\n' % \
+ (print_expr(('apply', statement[1], statement[2])), print_expr(statement[3]))
elif statement[0] == 'pause':
return('printf("%o", ' + print_expr(statement[1]) + '); getchar();')
elif statement[0] == 'read':
- return 'scanf("' + fmt_convert(format[statement[1]], write=False) + '", ' + ', '.join(map(lambda x: '&'+x, statement[2:])) + ');'
+ (fmt, types) = fmt_convert(format[statement[1]], write=False)
+ return 'scanf("' + fmt + '", ' + ', '.join(map(lambda x: '&'+x, statement[2:])) + ');'
elif statement[0] == 'remark':
if len(statement) == 1:
return "\n"
elif statement[0] == 'otherwise':
return 'else {'
elif statement[0] == 'print':
- fmt = fmt_convert(format[statement[1]])
+ (fmt, types) = fmt_convert(format[statement[1]])
if len(statement) < 3:
return 'printf("' + fmt + '");'
else:
return('// ' + `statement`)
def generate(out):
- out.write("/* generated by the MAD compiler */\n\n")
+ out.write("/* generated by the MAD compiler */\n")
for header in headers:
out.write('#include <%s.h>\n\n' % header)
+ needbool = False
+ for funvars in typedict.values():
+ if 'bool' in funvars.values():
+ needbool = True
+ if needbool:
+ 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)))
- for (file, line, label, statement) in deck:
- if statement[0] == 'internal':
- # FIXME: someday, deduce when return is of integral type
- out.write('double %s {return %s;}\n' % \
- (print_expr(('apply', statement[1], statement[2])), print_expr(statement[3])))
indent = 0
global sourceline
out.close()
srclist = " ".join(map(lambda x: x[:-4] + ".c", arguments))
if binary:
- compile = "cc %s -lm -o %s" % (srclist, target)
+ # Must be gcc, else compilation of internal functions will fail
+ compile = "gcc %s -lm -o %s" % (srclist, target)
if os.system(compile) == 0:
os.system("rm -f " + srclist)