]> thyrsus.com Git - mad.git/commitdiff
Format translation appears to work.
authorEric S. Raymond <esr@thyrsus,com>
Tue, 20 Jan 2004 12:14:51 +0000 (12:14 +0000)
committerEric S. Raymond <esr@thyrsus,com>
Tue, 20 Jan 2004 12:14:51 +0000 (12:14 +0000)
mad

diff --git a/mad b/mad
index d5614de585ef630efa803de6693b9684b69d0a21..bbf146412d9f706d087275d899e9df2e81065d5a 100755 (executable)
--- a/mad
+++ b/mad
@@ -47,19 +47,20 @@ t_STRING  = r'\$[^$]*\$'
 reserved_map = { }
 for r in reserved:
     reserved_map[r] = r
+refcount = {}
 
 def t_NAME(t):
     r'[A-Z][A-Z0-9]*\.?'
-    t.type = reserved_map.get(t.value, "NAME")
+    t.type = reserved_map.get(t.value, 'NAME')
     if t.type and t.value[-1] == '.':
         t.type = 'FUNCALL'
     t.value = t.value.lower()
     return t
 
-t_ignore = " \n"
+t_ignore = ' \n'
 
 def t_error(t):
-    print "Illegal character %s" % `t.value[0]`
+    print 'Illegal character %s' % `t.value[0]`
     t.skip(1)
     
 # Build the lexer
@@ -116,18 +117,18 @@ def p_dimension_list_continue(t):
 
 ## END
 def p_end_of_program(t):
-    "statement : END OF PROGRAM"
+    'statement : END OF PROGRAM'
     t[0] = ('end_program',)
 def p_end_of_conditional(t):
-    "statement : END OF CONDITIONAL"
+    'statement : END OF CONDITIONAL'
     t[0] = ('end_conditional',)
 def p_end_of_functions(t):
-    "statement : END OF FUNCTION"
+    'statement : END OF FUNCTION'
     t[0] = ('end_function',)
 
 ## INTEGER
 def p_integer(t):
-    "statement : INTEGER varlist"
+    'statement : INTEGER varlist'
     t[0] = ('integer',) + tuple(t[2])
 def p_varlist(t):
     'varlist : NAME'
@@ -138,12 +139,12 @@ def p_varlist_continue(t):
 
 ## READ FORMAT
 def p_read_format(t):
-    "statement : READ FORMAT varlist"
+    'statement : READ FORMAT varlist'
     t[0] = ('read',) + tuple(t[3])
 
 ## PRINT FORMAT
 def p_print_format(t):
-    "statement : PRINT FORMAT varlist"
+    'statement : PRINT FORMAT varlist'
     t[0] = ('print',) + tuple(t[3])
 
 ## THROUGH
@@ -164,7 +165,7 @@ def p_map_continue(t):
 
 ## TRANSFER TO
 def p_transfer(t):
-    "statement : TRANSFER TO NAME"
+    'statement : TRANSFER TO NAME'
     t[0] = ('goto', t[3])
     targets.append(t[3])
 
@@ -178,7 +179,7 @@ def p_whenever_complex(t):
 
 # VECTOR VALUES
 def p_vector_values(t):
-    "statement : VECTOR VALUES NAME EQUALS STRING"
+    'statement : VECTOR VALUES NAME EQUALS STRING'
     t[0] = ('values',) + (t[3], t[5])
 
 ## Assignment
@@ -243,34 +244,36 @@ def p_expression_float(t):
 def p_expression_subscript(t):
     'expression : NAME application'
     t[0] = ('variable', t[1], tuple(t[2]))
+    refcount[var] = refcount.get(var, 0) + 1 
 
 def p_function_application(t):
     'expression : FUNCALL application'
     t[0] = ('apply', t[1], tuple(t[2]))
 
 def p_expression_application(t):
-    "application : LPAREN inner_expression RPAREN"
+    'application : LPAREN inner_expression RPAREN'
     t[0] = t[2]
 
 def p_expression_tail_empty(t):
-    "inner_expression : expression"
+    'inner_expression : expression'
     t[0] = [t[1]]
 
 def p_expression_tail_nonempty(t):
-    "inner_expression : inner_expression COMMA expression"
+    'inner_expression : inner_expression COMMA expression'
     t[0] = t[1] + [t[3]]
 
 def p_expression_name(t):
     'expression : NAME'
     var = t[1]
     t[0] = ('variable', var)
+    refcount[var] = refcount.get(var, 0) + 1 
     if var not in integers + bools + floats + untyped:
         untyped.append(var)
 
 # Error handling
 
 def p_error(t):
-    print "Syntax error at '%s'" % t.value
+    print 'Syntax error at "%s"' % t.value
 
 import yacc
 yacc.yacc()
@@ -282,6 +285,7 @@ floats = []
 bools = []
 dimensions = {}
 static = {}
+format = {}
 
 # Map MAD intrinsics to C library functions
 madfunc_map = {'elog':'log'}
@@ -297,7 +301,6 @@ def analyze(deck):
     # Mine the code for compile-time directives
     for (label, statement) in deck:
         if statement[0] == 'integer':
-            print "Bar!", statement
             for var in statement[1:]:
                 declare(var, integers)
         elif statement[0] == 'dimension':
@@ -307,153 +310,164 @@ def analyze(deck):
             var = statement[1]
             if var not in integers + bools + floats + untyped:
                 untyped.append(var)
-        if statement[0] == 'values':
-            static[statement[1]] = statement[2]
+        elif statement[0] in ('read', 'print'):
+            pass
+        elif statement[0] == 'values':
+            var = statement[1]
+            if var in refcount:
+                static[var] = statement[2]
+            else:
+                format[var] = statement[2]
 
 def print_expr(t):
     if t[0] == 'variable':
         res = t[1]
         if len(t) > 2:
             for dim in t[2]:
-                res += "[" + dim[1] + "]"
+                res += '[' + dim[1] + ']'
         return res
     elif t[0] == 'apply':
         madfunc = t[1][:-1]
-        return madfunc_map.get(madfunc, madfunc) + "(" + " ,".join(map(print_expr, t[2])) + ")"
+        return madfunc_map.get(madfunc, madfunc) + '(' + ' ,'.join(map(print_expr, t[2])) + ')'
     elif t[0] == '+':
         if len(t) == 2:
-            return "%s" % print_expr(t[1])
+            return '%s' % print_expr(t[1])
         else:
-            return "(%s + %s)" % (print_expr(t[1]), print_expr(t[2]))
+            return '(%s + %s)' % (print_expr(t[1]), print_expr(t[2]))
     elif t[0] == '-':
         if len(t) == 2:
-            return "-%s" % print_expr(t[1])
+            return '-%s' % print_expr(t[1])
         else:
-            return "(%s - %s)" % (print_expr(t[1]), print_expr(t[2]))
+            return '(%s - %s)' % (print_expr(t[1]), print_expr(t[2]))
     elif t[0] == '*':
-        return "(%s * %s)" % (print_expr(t[1]), print_expr(t[2]))
+        return '(%s * %s)' % (print_expr(t[1]), print_expr(t[2]))
     elif t[0] == '/':
-        return "(%s / %s)" % (print_expr(t[1]), print_expr(t[2]))
+        return '(%s / %s)' % (print_expr(t[1]), print_expr(t[2]))
     elif t[0] == 'l':
-        return "(%s < %s)" % (print_expr(t[1]), print_expr(t[2]))
+        return '(%s < %s)' % (print_expr(t[1]), print_expr(t[2]))
     elif t[0] == 'g':
-        return "(%s > %s)" % (print_expr(t[1]), print_expr(t[2]))
+        return '(%s > %s)' % (print_expr(t[1]), print_expr(t[2]))
     elif t[0] == 'le':
-        return "(%s <= %s)" % (print_expr(t[1]), print_expr(t[2]))
+        return '(%s <= %s)' % (print_expr(t[1]), print_expr(t[2]))
     elif t[0] == 'ge':
-        return "(%s >= %s)" % (print_expr(t[1]), print_expr(t[2]))
+        return '(%s >= %s)' % (print_expr(t[1]), print_expr(t[2]))
     elif t[0] == 'e':
-        return "(%s == %s)" % (print_expr(t[1]), print_expr(t[2]))
+        return '(%s == %s)' % (print_expr(t[1]), print_expr(t[2]))
     elif t[0] == 'ne':
-        return "(%s != %s)" % (print_expr(t[1]), print_expr(t[2]))
+        return '(%s != %s)' % (print_expr(t[1]), print_expr(t[2]))
     elif t[0] == 'p':
-        return "pow(%s, %s)" % (print_expr(t[1]), print_expr(t[2]))
+        return 'pow(%s, %s)' % (print_expr(t[1]), print_expr(t[2]))
     elif t[0] == 'and':
-        return "(%s && %s)" % (print_expr(t[1]), print_expr(t[2]))
+        return '(%s && %s)' % (print_expr(t[1]), print_expr(t[2]))
     elif t[0] == 'or':
-        return "(%s || %s)" % (print_expr(t[1]), print_expr(t[2]))
+        return '(%s || %s)' % (print_expr(t[1]), print_expr(t[2]))
     elif t[0] == 'then':
-        return "!(%s && !(%s))" % (print_expr(t[1]), print_expr(t[2]))
+        return '!(%s && !(%s))' % (print_expr(t[1]), print_expr(t[2]))
     elif t[0] == 'eqv':
-        return "(%s == %s)" % (print_expr(t[1]), print_expr(t[2]))
+        return '(%s == %s)' % (print_expr(t[1]), print_expr(t[2]))
     elif t[0] == 'abs':
-        return "abs(%s)" % print_expr(t[1])
+        return 'abs(%s)' % print_expr(t[1])
     elif t[0] in ('intnum', 'floatnum'):
         return t[1]
     else:
-        return "***"+`t`
-
-def print_statement(statement):
-    if statement[0] in ('dimension', 'end_program', 'integer', 'values'):
-        pass
-    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))
-    elif statement[0] == 'goto':
-        return "goto " + statement[1] + ";" 
-    elif statement[0] == 'if':
-        return "if (" + print_expr(statement[1]) + ") " + print_statement(statement[2])
-    elif statement[0] == 'read':
-        return 'scanf(' + statement[1] + ', ' + ", ".join(map(lambda x: "&"+x, statement[2:])) + ");"
-    elif statement[0] == 'print':
-        return 'printf(' + statement[1] + ', ' + ", ".join(statement[2:]) + ");"
-    elif statement[0] == 'substitution':
-        return statement[1] + " = " + print_expr(statement[2]) + ";"
-    else:
-        return("// " + `statement`)
+        return '***'+`t`
 
-def fmt_convert(str):
+def fmt_convert(str, write=True):
     "Convert MAD format string to C printf/scanf"
-    res = ""
+    res = ''
     str = str[1:-1]
     while True:
-        if str[0] == "*":
+        if str[0] == '*':
             break
         elif str[0] == 'S':
-            i = 0
-            while str[i].isdigit():
+            i = 1
+            while str[i] != ',':
                 i += 1
             if i <= 0:
-                sys.stderr.write("invalid spacer in %s\n" % str)
+                sys.stderr.write('invalid spacer in %s\n' % str)
                 sys.exit(1)
-            count = int(str[:i])
-            res += " " * count
-            str = str[i:]
-            break
+            count = int(str[1:i])
+            if write:
+                res += ' ' * count
+            str = str[i+1:]
         # All other format codes require a prefix.
         i = 0
         while str[i].isdigit():
             i += 1
         if i <= 0:
-            sys.stderr.write("invalid format string %s\n" % str)
+            sys.stderr.write('invalid format string %s\n' % str)
             sys.exit(1)
         count = int(str[:i])
         str = str[i:]
         if str[0] == 'F':
             i = 1
-            while str[i] in "0123456789.":
+            while str[i] in '0123456789.':
                 i += 1
-            res += ("%" + str[1:i] + "f") * count
+            res += ('%' + str[1:i] + 'f') * count
             str = str[i:]
         elif str[0] == 'H':
-            res += str[1:count+1]
+            if write:
+                res += str[1:count+1]
             str = str[count+1:]
         else:
-            sys.stderr.write("invalid field code in format string!")
+            sys.stderr.write('invalid field code in format string!')
             sys.exit(1)
+    # Clip off format character
+    if write:
+        res = res[1:]
+    res = res + '\\n'
     return res
 
+def print_statement(statement):
+    if statement[0] in ('dimension', 'end_program', 'integer', 'values'):
+        pass
+    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))
+    elif statement[0] == 'goto':
+        return 'goto ' + statement[1] + ';' 
+    elif statement[0] == 'if':
+        return 'if (' + print_expr(statement[1]) + ') ' + print_statement(statement[2])
+    elif statement[0] == 'read':
+        return 'scanf("' + fmt_convert(format[statement[1]], write=False) + '", ' + ', '.join(map(lambda x: '&'+x, statement[2:])) + ');'
+    elif statement[0] == 'print':
+        return 'printf("' + fmt_convert(format[statement[1]]) + '", ' + ', '.join(statement[2:]) + ');'
+    elif statement[0] == 'substitution':
+        return statement[1] + ' = ' + print_expr(statement[2]) + ';'
+    else:
+        return('// ' + `statement`)
+
 if __name__ == '__main__':
     source = sys.stdin.read()
     # Grotty hack to add end-of-statement delimiters
-    source = re.sub("\n([A-Z]|\t)", " ;\n\\1", source).rstrip() + " ;\n"
+    source = re.sub('\n([A-Z]|\t)', ' ;\n\\1', source).rstrip() + ' ;\n'
     yacc.parse(source)
 
     analyze(deck)
 
-    print "#include <math.h>"
-    print "main(int argc, char *argv[])"
-    print "{"
+    print '#include <math.h>'
+    print 'main(int argc, char *argv[])'
+    print '{'
     if integers:
-        print "\tint " + ", ".join(integers) + ";\t/* INTEGER */"
+        print '\tint ' + ', '.join(integers) + ';\t/* INTEGER */'
     if bools:
-        print "\tint " + ", ".join(bools) + ";\t/* boolean */"
+        print '\tint ' + ', '.join(bools) + ';\t/* boolean */'
     if untyped:
-        print "\tfloat " + ", ".join(untyped) + ";\t/* untyped */"
+        print '\tfloat ' + ', '.join(untyped) + ';\t/* untyped */'
     if floats:
-        print "\tfloat " + ", ".join(floats) + ";"
+        print '\tfloat ' + ', '.join(floats) + ';'
     for (id, value) in static.items():
         print '\tstatic const char *%s\t= "%s";' % (id, fmt_convert(value))
     indent = 0
     for (label, statement) in deck:
         if label in targets:
-            sys.stdout.write(label+":")
+            sys.stdout.write(label+':')
         rep = print_statement(statement)
         if rep:
-            sys.stdout.write("\t" + "    "*indent + rep + "\n")
+            sys.stdout.write('\t' + '    '*indent + rep + '\n')
             if rep[-1] == '{':
                 indent += 1
         if label in scopes:
             indent -= 1
-            print ("\t" + "    "*indent) + "}"
-    print "}"
+            print ('\t' + '    '*indent) + '}'
+    print '}'