]> thyrsus.com Git - mad.git/commitdiff
Reduce special cases.
authorEric S. Raymond <esr@thyrsus,com>
Tue, 27 Jan 2004 17:27:38 +0000 (17:27 +0000)
committerEric S. Raymond <esr@thyrsus,com>
Tue, 27 Jan 2004 17:27:38 +0000 (17:27 +0000)
mad

diff --git a/mad b/mad
index 9cdcf5a55b009084396370faebaf797a084b5bd4..f7747ffb4e16d7293906f2b1421c991e6325fb1c 100755 (executable)
--- a/mad
+++ b/mad
@@ -1,9 +1,12 @@
 #!/usr/bin/env python
 
 reserved = ('CONDITIONAL', 'CONTINUE', 'DIMENSION', 'END', 'EXECUTE',
-            'FOR', 'FORMAT', 'FUNCTION', 'INTEGER', 'INTERNAL', 'OF',
-            'PAUSE', 'PRINT', 'PROGRAM', 'READ', 'COMMENT', 'THROUGH',
-            'TO', 'TRANSFER', 'VALUES', 'VECTOR', 'WHENEVER')
+            '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')
 
 tokens = reserved + (
     'SEMI', 'COMMA',
@@ -154,6 +157,19 @@ def p_execute_noargs(t):
     'statement : EXECUTE FUNCALL'
     t[0] = ('execute', ('apply', t[2], []))
 
+## EXTERNAL FUNCTION
+def p_external(t):
+    "statement : INTERNAL FUNCTION FUNCALL application"
+    t[0] = ('external', t[3], tuple(t[4]))
+
+## FUNCTION RETURN
+def p_function_return(t):
+    "statement : FUNCTION RETURN expression"
+    t[0] = ('return', t[3])    
+def p_function_return_void(t):
+    "statement : FUNCTION RETURN"
+    t[0] = ('return')    
+
 ## INTEGER
 def p_integer(t):
     'statement : INTEGER varlist'
@@ -168,7 +184,7 @@ def p_varlist_continue(t):
 ## INTERNAL FUNCTION
 def p_internal(t):
     "statement : INTERNAL FUNCTION FUNCALL application EQUALS expression"
-    t[0] = ('function', t[3], tuple(t[4]), t[6])
+    t[0] = ('internal', t[3], tuple(t[4]), t[6])
 
 ## PAUSE
 def p_pause(t):
@@ -355,9 +371,9 @@ def declare(var, lst):
         untyped.remove(var)
     lst.append(var)
 
-def analyze(deck):
-    "Gather variable types."
-    global integers, floats, bools
+def analyze():
+    "Gather variable types and determine function boundaries."
+    global integers, floats, bools, deck
     # Mine the code for compile-time directives
     for (line, label, statement) in deck:
         if statement[0] == 'integer':
@@ -379,6 +395,9 @@ def analyze(deck):
                 untyped.remove(var)
             else:
                 format[var] = statement[2]
+    # We may need to generate a pseudo-function call
+    if deck[3][0] != 'external':
+        deck = [(0, None, ('external', 'main.', ()))] + deck
 
 def print_expr(t):
     if t[0] == 'variable':
@@ -493,17 +512,18 @@ def fmt_convert(fmt, write=True):
 
 def print_statement(statement):
     if statement[0] in ('dimension',
-                        'end_program',
-                        'function',
+                        'internal',
                         'integer',
                         'values'):
         pass
     elif statement[0] == 'continue':
         return "/* continue */;"
-    elif statement[0] == 'end_conditional':
+    elif statement[0] in ('end_program', 'end_function', 'end_conditional'):
         return "}"
     elif statement[0] == 'execute':
-            return print_expr(statement[1]) + ";"
+        return print_expr(statement[1]) + ";"
+    elif statement[0] == 'external':
+        return "\n" + print_expr(('apply', statement[1], statement[2])) + " {"
     elif statement[0] == 'for':
         (keyword, label, dummy, start, increment, predicate) = statement
         return 'for (%s = %s; %s; %s += %s) {' % (dummy, print_expr(start), print_expr(predicate), dummy, print_expr(increment))
@@ -519,7 +539,12 @@ def print_statement(statement):
         if len(statement) == 1:
             return "\n"
         else:
-            return "/* %s */\n" % statement[1].strip()
+            return "/* %s */" % statement[1].strip()
+    elif statement[0] == 'return':
+        if len(statement) == 1:
+            return "return;"
+        else:
+            return "return %s" % peint_expr(statement[1])
     elif statement[0] == 'or':
         return 'else if (' + print_expr(statement[2]) + ') {'
     elif statement[0] == 'otherwise':
@@ -540,38 +565,37 @@ def print_statement(statement):
 def generate(out):
     out.write('#include <math.h>\n\n')
 
-    for (line, label, statement) in deck:
-        if statement[0] == 'function':
-            # FIXME: someday, deduce when return is of integral type
-            out.write('float %s {return %s;}\n' % \
-                      (print_expr(('apply', statement[1], statement[2])), print_expr(statement[3])))
-
-    out.write('\nmain(int argc, char *argv[])\n')
-    out.write('{\n')
     if integers:
-        out.write('\tint ' + ', '.join(integers) + ';\t/* INTEGER */\n')
+        out.write('int ' + ', '.join(integers) + ';\t/* INTEGER */\n')
     if bools:
-        out.write('\tint ' + ', '.join(bools) + ';\t/* boolean */\n')
+        out.write('int ' + ', '.join(bools) + ';\t/* boolean */\n')
     if untyped:
-        out.write('\tfloat ' + ', '.join(untyped) + ';\t/* untyped */\n')
+        out.write('float ' + ', '.join(untyped) + ';\t/* untyped */\n')
     if floats:
-        out.write('\tfloat ' + ', '.join(floats) + ';\n')
+        out.write('float ' + ', '.join(floats) + ';\n')
     for (id, value) in static.items():
-        out.write('\tstatic const char *%s\t= "%s";\n' % (id, fmt_convert(value)))
+        out.write('static const char *%s\t= "%s";\n' % (id, fmt_convert(value)))
+    for (line, label, statement) in deck:
+        if statement[0] == 'internal':
+            # FIXME: someday, deduce when return is of integral type
+            out.write('float %s {return %s;}\n' % \
+                      (print_expr(('apply', statement[1], statement[2])), print_expr(statement[3])))
+
     indent = 0
     global sourceline
     for (sourceline, label, statement) in deck:
         if label in targets:
-            out.write(label+':')
+            out.write("  " + label+':\n')
         rep = print_statement(statement)
         if rep:
-            out.write('\t' + '    '*indent + rep + '\n')
+            if rep[-1] == '}':
+                indent -= 1
+            out.write('    '*indent + rep + '\n')
             if rep[-1] == '{':
                 indent += 1
         if label in scopes:
             indent -= 1
-            out.write(('\t' + '    '*indent) + '}\n')
-    out.write('}\n')
+            out.write(('    '*indent) + '}\n')
 
 if __name__ == '__main__':
     import os, getopt
@@ -616,7 +640,7 @@ if __name__ == '__main__':
         yacc.parse(source, debug=mad_debug)
 
     # Perform global analysis
-    analyze(deck)
+    analyze()
 
     if (dump_tuples):
         for t in deck: