]> thyrsus.com Git - mad.git/commitdiff
We can emit code for three statement types now.
authorEric S. Raymond <esr@thyrsus,com>
Wed, 14 Jan 2004 17:39:06 +0000 (17:39 +0000)
committerEric S. Raymond <esr@thyrsus,com>
Wed, 14 Jan 2004 17:39:06 +0000 (17:39 +0000)
mad

diff --git a/mad b/mad
index a508c96ad09b9ba492339f48288e352e71736847..79226b0d224db652f9cc216cc2ad3ddfb196ad1b 100755 (executable)
--- a/mad
+++ b/mad
@@ -12,7 +12,7 @@ tokens = reserved + (
     'PLUS','MINUS','TIMES','DIVIDE','EQUALS',
     'NOT', 'OR', 'AND', 'THEN', 'EQV',
     'EQ', 'NE', 'LT', 'LE', 'GT', 'GE',
-    'ABS', 'EXP',
+    'ABS', 'POW',
     )
 
 # Tokens
@@ -21,7 +21,7 @@ t_SEMI    = r';'
 t_TAB     = r'\t'
 t_COMMA   = r'\,'
 t_ABS     = r'\.ABS\.'
-t_EXP     = r'\.P\.'
+t_POW     = r'\.P\.'
 t_NOT     = r'\.NOT\.'
 t_OR      = r'\.OR\.'
 t_AND     = r'\.AND\.'
@@ -52,6 +52,7 @@ def t_NAME(t):
     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"
@@ -76,11 +77,13 @@ precedence = (
     ('left','PLUS','MINUS'),
     ('left','TIMES','DIVIDE'),
     ('right','UMINUS'),
-    ('left','EXP'),
+    ('left','POW'),
     ('right', 'ABS', 'UPLUS')
     )
 
 cards = []
+scopes = []
+targets = []
 
 # Program level
 
@@ -101,7 +104,7 @@ def p_labeled_card(t):
 ## DIMENSION
 def p_statement_dimension(t):
     'statement : DIMENSION dimension_list'
-    t[0] = ('dimension', t[1], t[2])
+    t[0] = ('dimension', t[2])
 def p_dimension_list(t):
     'dimension_list : NAME application'
     t[0] = [[t[1], tuple(t[2])]]
@@ -112,13 +115,13 @@ def p_dimension_list_continue(t):
 ## END
 def p_end_of_program(t):
     "statement : END OF PROGRAM"
-    t[0] = ('end_program')
+    t[0] = ('end_program',)
 def p_end_of_conditional(t):
     "statement : END OF CONDITIONAL"
-    t[0] = ('end_conditional')
+    t[0] = ('end_conditional',)
 def p_end_of_functions(t):
     "statement : END OF FUNCTION"
-    t[0] = ('end_function')
+    t[0] = ('end_function',)
 
 ## INTEGER
 def p_integer(t):
@@ -144,10 +147,12 @@ def p_print_format(t):
 ## THROUGH
 def p_through_for(t):
     'statement : THROUGH NAME COMMA FOR NAME EQUALS expression COMMA expression COMMA expression'
-    t[0] = ('for', t[2], t[7], t[9], t[11])
+    t[0] = ('for', t[2], t[5], t[7], t[9], t[11])
+    scopes.append(t[2])
 def p_through_map(t):
     'statement : THROUGH NAME COMMA FOR VALUES OF NAME EQUALS value_list'
     t[0] = ('map', t[2], t[7], t[9])
+    scopes.append(t[2])
 def p_map(t):
     'value_list : expression'
     t[0] = [t[1]]
@@ -159,6 +164,7 @@ def p_map_continue(t):
 def p_transfer(t):
     "statement : TRANSFER TO NAME"
     t[0] = ('goto', t[3])
+    targets.append(t[3])
 
 ## WHENEVER
 def p_whenever_simple(t):
@@ -173,7 +179,6 @@ def p_whenever_complex(t):
 #    "statement : VECTOR VALUES assignlist"
 #    t[0] = ('values',) + tuple(t[3])
 
-
 ## Assignment
 def p_statement_substitution(t):
     'statement : NAME EQUALS expression'
@@ -199,7 +204,7 @@ def p_expression_binop2(t):
                   | expression GE expression
                   | expression EQ expression
                   | expression NE expression
-                  | expression EXP expression
+                  | expression POW expression
                   '''
     t[0] = (t[2][1:-1].lower(), t[1], t[3])
 
@@ -225,7 +230,7 @@ def p_expression_group(t):
 
 def p_expression_integer(t):
     'expression : INTNUM'
-    t[0] = ('integer', t[1])
+    t[0] = ('intnum', t[1])
 
 def p_expression_float(t):
     'expression : FLOATNUM'
@@ -265,9 +270,110 @@ yacc.yacc()
 
 import sys, re
 
-source = sys.stdin.read()
-# Grotty hack to add end-of-statement delimiters
-source = re.sub("\n([A-Z]|\t)", " ;\n\\1", source).rstrip() + " ;\n"
-yacc.parse(source, debug=1)
-for card in cards:
-    print card
+indent = 0
+
+def recode(cards):
+    "Rewrite the statement list."
+    # Find first INTEGER declaration, move it to the front.
+    for statement in cards:
+        if statement[1][0] == 'integer':
+            declaration = statement
+            cards.remove(declaration)
+            cards = [declaration] + cards
+            break
+    return cards
+
+def print_expr(t):
+    if t[0] == 'variable':
+        res = t[1]
+        if len(t) > 2:
+            for dim in t[2]:
+                res += "[" + dim[1] + "]"
+        return res
+    elif t[0] == 'apply':
+        return t[1] + `t[2]`
+    elif t[0] == 'plus':
+        return "(%s + %s)" % (print_expr(t[1]), print_expr(t[2]))
+    elif t[0] == 'minus':
+        return "(%s - %s)" % (print_expr(t[1]), print_expr(t[2]))
+    elif t[0] == 'times':
+        return "(%s * %s)" % (print_expr(t[1]), print_expr(t[2]))
+    elif t[0] == 'divide':
+        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]))
+    elif t[0] == 'g':
+        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]))
+    elif t[0] == 'ge':
+        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]))
+    elif t[0] == 'ne':
+        return "(%s != %s)" % (print_expr(t[1]), print_expr(t[2]))
+    elif t[0] == 'pow':
+        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]))
+    elif t[0] == 'or':
+        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]))
+    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])
+    elif t[0] == '+':
+        return "%s" % print_expr(t[1])
+    elif t[0] == '-':
+        return "(-%s)" % print_expr(t[1])
+    elif t[0] in ('variable', 'intnum'):
+        return "%s" % print_expr(t[1])
+    else:
+        return "***"+`t`
+
+def print_statement(statement):
+    global indent
+    if statement[0] == 'end_program':
+        return "/* END OF PROGRAM */"
+    elif statement[0] == 'dimension':
+        declaration = "int";
+        for (var, dimlist) in statement[1]:
+            declaration += " " + var
+            for dim in dimlist:
+                declaration += "[" + dim[1] + "]"
+            declaration += ", "
+        return(declaration[:-2] + ";")
+    elif statement[0] == 'for':
+        print statement
+        (keyword, label, dummy, start, increment, predicate) = statement
+        indent += 1
+        return "for (%s = %s; %s; %s += %s) {" % (dummy, print_expr(start), print_expr(predicate), dummy, print_expr(increment))
+    elif statement[0] == 'if':
+        return "if (" + print_expr(statement[1]) + ") " + print_statement(statement[2]) + ";"
+    elif statement[0] == 'integer':
+        return "int " + ", ".join(statement[1:]) + ";"
+    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"
+    yacc.parse(source)
+    cards = recode(cards)
+
+    print "#include <math.h>"
+    print "main(int argc, char *argv[])"
+    print "{"
+    for (label, statement) in cards:
+        if label in targets:
+            sys.stdout.write(label+":")
+        sys.stdout.write("\t" + "    "*indent +print_statement(statement) + "\n")
+        if label in scopes:
+            indent -= 1
+            print ("\t" + "    "*indent) + "}"
+    print "}"