]> thyrsus.com Git - mad.git/commitdiff
Ready to try optimizing.
authorEric S. Raymond <esr@thyrsus,com>
Sat, 31 Jan 2004 02:53:32 +0000 (02:53 +0000)
committerEric S. Raymond <esr@thyrsus,com>
Sat, 31 Jan 2004 02:53:32 +0000 (02:53 +0000)
mad

diff --git a/mad b/mad
index 84588da380fc521e61da6f43a39a0a8d8f3fb8b0..8a48df955d4a276594aa44b13128524289e646a0 100755 (executable)
--- a/mad
+++ b/mad
@@ -1,10 +1,10 @@
 #!/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')
 
@@ -18,6 +18,9 @@ tokens = reserved + (
     'ABS', 'POW',
     )
 
+logops = ('NOT', 'OR', 'AND', 'THEN', 'EQV',
+          'EQ', 'NE', 'LT', 'LE', 'GT', 'GE',)
+
 # Tokens
 
 t_SEMI    = r';'
@@ -105,6 +108,7 @@ deck = []
 scopes = []
 targets = {}
 headers = []
+funcnames = []
 
 currentfunc = 'main.'
 typedict = {'main.':{}}
@@ -125,6 +129,19 @@ def p_labeled_card(t):
 
 # 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'
@@ -159,6 +176,7 @@ def p_entry(t):
     currentfunc = t[3]
     t[0] = ('entry', currentfunc)
     typedict[currentfunc] = {}
+    funcnames.append(currentfunc)
 
 ## EXECUTE
 def p_execute(t):
@@ -188,19 +206,22 @@ def p_function_return_void(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):
@@ -234,6 +255,13 @@ def p_remark2(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):
@@ -278,7 +306,6 @@ def p_statement_substitution(t):
     'statement : NAME EQUALS expression'
     newvar = t[1]
     t[0] = ('substitution', newvar, t[3])
-    typedict[currentfunc][newvar] = 'double'
 
 # Expression parsing
 
@@ -341,8 +368,6 @@ def p_expression_subscript(t):
     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'
@@ -368,8 +393,6 @@ def p_expression_name(t):
     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
 
@@ -413,13 +436,12 @@ def analyze():
                 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:
@@ -427,6 +449,16 @@ def analyze():
                 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]
@@ -442,6 +474,15 @@ def analyze():
             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]
@@ -489,7 +530,11 @@ def prin1(t):
     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:
@@ -505,6 +550,7 @@ def print_expr(t):
 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] == '*':
@@ -541,16 +587,19 @@ def fmt_convert(fmt, write=True):
                 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)
@@ -558,12 +607,12 @@ def fmt_convert(fmt, write=True):
     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
@@ -585,7 +634,7 @@ def print_statement(statement):
             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) + "; "
@@ -603,10 +652,14 @@ def print_statement(statement):
         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"
@@ -622,7 +675,7 @@ def print_statement(statement):
     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:
@@ -635,17 +688,18 @@ def print_statement(statement):
         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
@@ -730,7 +784,8 @@ if __name__ == '__main__':
             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)