]> thyrsus.com Git - mad.git/commitdiff
Partiaal range support -- parsing foos up at this point.
authorEric S. Raymond <esr@thyrsus,com>
Tue, 10 Feb 2004 21:54:23 +0000 (21:54 +0000)
committerEric S. Raymond <esr@thyrsus,com>
Tue, 10 Feb 2004 21:54:23 +0000 (21:54 +0000)
mad

diff --git a/mad b/mad
index 189a38dcbee46cce6f66229d698b77d0c5721d47..c638cff7ea97cbff3c7061071398cbea44adc307 100755 (executable)
--- a/mad
+++ b/mad
@@ -6,8 +6,8 @@ reserved = ('BOOLEAN', 'CONDITIONAL', 'CONTINUE', 'DATA', 'DIMENSION',
             'OF', 'PAUSE', 'PRINT_FORMAT', 'PROGRAM', 'READ_FORMAT',
             'RESTORE', 'RETURN', 'SAVE', 'SET_LIST_TO', 'THROUGH',
             'TO', 'TRANSFER', 'VALUES', 'VECTOR', 'WHENEVER',
-            # This is a pseudo-keyword generated early in compilation.
-            'COMMENT')
+            # COMMENT is a pseudo-keyword generated early in compilation.
+            'COMMENT', 'DOTRANGE')
 
 tokens = reserved + (
     'SEMI', 'COMMA',
@@ -47,6 +47,7 @@ t_EQUALS  = r'='
 t_LPAREN  = r'\('
 t_RPAREN  = r'\)'
 t_STRING  = r'\$[^$]*\$'
+t_DOTRANGE= r'\.\.\.'
 
 reserved_map = { }
 for r in reserved:
@@ -114,8 +115,6 @@ funcnames = []              # List of function names
 dimensions = {}                # Dictionary of array depths
 arraydepths = {}       # Dictionary of array dimensions
 returntypes = {}       # Dictionary of function returntypes
-normalmode = 'double'  # Default type as set by NORMAL statement
-dummycount = 0         # Count of FOR VALUES statements
 static = {}            # Dictionary of static char variables
 format = {}            # Dictionary of format strings
 hasmain = False                # Does this program have a main line?
@@ -234,7 +233,7 @@ def p_internal(t):
 ## NORMAL MODE IS
 def p_normal(t):
     "statement : NORMAL MODE IS typeval"
-    t[0] = ('normal', t[1])
+    t[0] = ('normal', t[4])
 def p_typeval_int(t):
     "typeval : INTEGER"
     t[0] = 'int'
@@ -249,23 +248,33 @@ def p_pause(t):
 
 ## PRINT_FORMAT
 def p_print_format(t):
-    'statement : PRINT_FORMAT NAME COMMA exprlist'
+    'statement : PRINT_FORMAT NAME COMMA outlist'
     t[0] = ('print', t[2]) + tuple(t[4])
-def p_exprlist(t):
-    'exprlist : expression'
-    t[0] = [t[1]]
-def p_exprlist_continue(t):
-    'exprlist : exprlist COMMA expression'
-    t[0] = t[1] + [t[3]]
 def p_print_format0(t):
     'statement : PRINT_FORMAT NAME'
     t[0] = ('print', t[2])
+    # This is shared with SAVE DATA
+def p_outlist(t):
+    'outlist : outval'
+    t[0] = [t[1]]
+def p_outlist_continue(t):
+    'outlist : outlist COMMA outval'
+    t[0] = t[1] + [t[3]]
+def p_outval(t):
+    '''outval : range
+              | expression'''
+    t[0] = t[1]
+def p_range(t):
+    'range : NAME application DOTRANGE NAME application'
+    t[0] = ('slice', t[1], t[2], t[5])
+    if t[1] != t[4]:
+        sys.stderr.write("variable names in range don't match!")
+        sys.exit(1)
 
 ## R
 def p_remark1(t):
     'statement : COMMENT STRING'
     t[0] = ('remark', t[2][1:-1])
-
 def p_remark2(t):
     'statement : COMMENT'
     t[0] = ('remark',)
@@ -274,9 +283,13 @@ def p_remark2(t):
 def p_read_format(t):
     'statement : READ_FORMAT NAME COMMA varlist'
     t[0] = ('read', t[2]) + tuple(t[4])
+    # This is shared with RESTORE_DATA
 def p_varlist(t):
     'varlist : NAME'
     t[0] = [t[1]]
+def p_varlist_range(t):
+    'varlist : varlist COMMA range'
+    t[0] = t[1] + [t[3]]
 def p_varlist_continue(t):
     'varlist : varlist COMMA NAME'
     t[0] = t[1] + [t[3]]
@@ -291,7 +304,7 @@ def p_restore_return(t):
 
 ## SAVE
 def p_save_data(t):
-    'statement : SAVE DATA exprlist'
+    'statement : SAVE DATA outlist'
     t[0] = ('save', tuple(t[3]))
 def p_save_return(t):
     'statement : SAVE RETURN'
@@ -461,6 +474,8 @@ def croak(t, msg):
 # functions deliberately shared a global, but this doesn't happen in
 # any of the examples.
 typedict = {}          # Dictionary of per-function dictionaries of locals
+normalmode = 'double'  # Default type as set by NORMAL statement
+dummycount = 0         # Count of FOR VALUES statements
 
 def analyze():
     "Gather variable types and determine function boundaries."
@@ -623,7 +638,7 @@ def mode(t):
         sys.write.stderr("mad: internal error while computing mode of %s\n"%t)
         sys.exit(1)
 
-def prin1(t):
+def prinC1(t):
     if t[0] == 'variable':
         res = t[1]
         if len(t) > 2:
@@ -632,59 +647,59 @@ def prin1(t):
         return res
     elif t[0] == 'apply':
         madfunc = t[1][:-1]
-        return madfunc_map.get(madfunc, madfunc) + '(' + ', '.join(map(prin1, t[2])) + ')'
+        return madfunc_map.get(madfunc, madfunc) + '(' + ', '.join(map(prinC1, t[2])) + ')'
     elif t[0] == '+':
         if len(t) == 2:
-            return '%s' % prin1(t[1])
+            return '%s' % prinC1(t[1])
         else:
-            return '(%s + %s)' % (prin1(t[1]), prin1(t[2]))
+            return '(%s + %s)' % (prinC1(t[1]), prinC1(t[2]))
     elif t[0] == '-':
         if len(t) == 2:
-            return '-%s' % prin1(t[1])
+            return '-%s' % prinC1(t[1])
         else:
-            return '(%s - %s)' % (prin1(t[1]), prin1(t[2]))
+            return '(%s - %s)' % (prinC1(t[1]), prinC1(t[2]))
     elif t[0] == 'not':
-        return "!%s" % prin1(t[1])
+        return "!%s" % prinC1(t[1])
     elif t[0] == '*':
-        return '(%s * %s)' % (prin1(t[1]), prin1(t[2]))
+        return '(%s * %s)' % (prinC1(t[1]), prinC1(t[2]))
     elif t[0] == '/':
-        return '(%s / %s)' % (prin1(t[1]), prin1(t[2]))
+        return '(%s / %s)' % (prinC1(t[1]), prinC1(t[2]))
     elif t[0] == 'l':
-        return '(%s < %s)' % (prin1(t[1]), prin1(t[2]))
+        return '(%s < %s)' % (prinC1(t[1]), prinC1(t[2]))
     elif t[0] == 'g':
-        return '(%s > %s)' % (prin1(t[1]), prin1(t[2]))
+        return '(%s > %s)' % (prinC1(t[1]), prinC1(t[2]))
     elif t[0] == 'le':
-        return '(%s <= %s)' % (prin1(t[1]), prin1(t[2]))
+        return '(%s <= %s)' % (prinC1(t[1]), prinC1(t[2]))
     elif t[0] == 'ge':
-        return '(%s >= %s)' % (prin1(t[1]), prin1(t[2]))
+        return '(%s >= %s)' % (prinC1(t[1]), prinC1(t[2]))
     elif t[0] == 'e':
-        return '(%s == %s)' % (prin1(t[1]), prin1(t[2]))
+        return '(%s == %s)' % (prinC1(t[1]), prinC1(t[2]))
     elif t[0] == 'ne':
-        return '(%s != %s)' % (prin1(t[1]), prin1(t[2]))
+        return '(%s != %s)' % (prinC1(t[1]), prinC1(t[2]))
     elif t[0] == 'p':
-        return 'pow(%s, %s)' % (prin1(t[1]), prin1(t[2]))
+        return 'pow(%s, %s)' % (prinC1(t[1]), prinC1(t[2]))
     elif t[0] == 'and':
-        return '(%s && %s)' % (prin1(t[1]), prin1(t[2]))
+        return '(%s && %s)' % (prinC1(t[1]), prinC1(t[2]))
     elif t[0] == 'or':
-        return '(%s || %s)' % (prin1(t[1]), prin1(t[2]))
+        return '(%s || %s)' % (prinC1(t[1]), prinC1(t[2]))
     elif t[0] == 'then':
-        return '!(%s && !(%s))' % (prin1(t[1]), prin1(t[2]))
+        return '!(%s && !(%s))' % (prinC1(t[1]), prinC1(t[2]))
     elif t[0] == 'eqv':
-        return '(%s == %s)' % (prin1(t[1]), prin1(t[2]))
+        return '(%s == %s)' % (prinC1(t[1]), prinC1(t[2]))
     elif t[0] == 'abs':
         argmode = mode(t[1])
         if argmode == 'double':
-            return 'fabs(%s)' % prin1(t[1])
+            return 'fabs(%s)' % prinC1(t[1])
         else:
-            return 'abs(%s)' % prin1(t[1])     # int or bool
+            return 'abs(%s)' % prinC1(t[1])    # int or bool
     elif t[0] in ('intnum', 'doublenum'):
         return t[1]
     else:
         return '***'+`t`
 
-def print_expr(t):
-    "Cosmetic wrapper round prin1"
-    res = prin1(t)
+def print_C_expr(t):
+    "Cosmetic wrapper round prinC1"
+    res = prinC1(t)
     if res[0] == "(" and res[-1] == ")":
         res = res[1:-1]
     return res
@@ -763,7 +778,7 @@ def fmt_convert(str, write=True):
     #print "<-fmt_convert() = %s" % res
     return (res, types)
 
-def print_statement(statement):
+def print_C_statement(statement):
     global currentfunc
     if statement[0] in ('boolean',
                         'dimension',
@@ -805,22 +820,22 @@ def print_statement(statement):
             rep += "    " + declarations[:-1] + "\n"
         return rep
     elif statement[0] == 'execute':
-        return print_expr(statement[1]) + ";"
+        return print_C_expr(statement[1]) + ";"
     elif statement[0] == 'external_call':
-        return "\n" + print_expr(('apply', statement[1], statement[2])) + ";"
+        return "\n" + print_C_expr(('apply', statement[1], statement[2])) + ";"
     elif statement[0] == 'for':
         (keyword, label, dummy, start, increment, predicate) = statement
-        return 'for (%s = %s; %s; %s += %s) { /* label %s */ ' % (dummy, print_expr(start), print_expr(predicate), dummy, print_expr(increment), label)
+        return 'for (%s = %s; %s; %s += %s) { /* label %s */ ' % (dummy, print_C_expr(start), print_C_expr(predicate), dummy, print_C_expr(increment), label)
     elif statement[0] == 'goto':
         return 'goto ' + statement[1] + ';' 
     elif statement[0] == 'if':
-        return 'if (' + print_expr(statement[1]) + ') ' + print_statement(statement[2])
+        return 'if (' + print_C_expr(statement[1]) + ') ' + print_C_statement(statement[2])
     elif statement[0] == 'internal':
         rep = returntypes.get(statement[1], normalmode) + " " + statement[1][:-1] +"("
         for (dummy, var) in statement[2]:
             rep += mode((dummy, var)) + " " + var + ", "
         rep = rep[:-2]
-        rep += ') {return %s;}' % print_expr(statement[3])
+        rep += ') {return %s;}' % print_C_expr(statement[3])
         return rep
     elif statement[0] == 'map':
         global dummycount
@@ -831,17 +846,17 @@ def print_statement(statement):
         rep += "((%s [%d]){%s})[%s];" % (statement[3][0][0][:-3], count, ", ".join(map(lambda x: `x[1]`, statement[3])), dummy)
         return rep
     elif statement[0] == 'or':
-        return 'else if (' + print_expr(statement[2]) + ') {'
+        return 'else if (' + print_C_expr(statement[2]) + ') {'
     elif statement[0] == 'otherwise':
         return 'else {'
     elif statement[0] == 'pause':
-        return('printf("%o", ' + print_expr(statement[1]) + '); getchar();')
+        return('printf("%o", ' + print_C_expr(statement[1]) + '); getchar();')
     elif statement[0] == 'print':
         (fmt, types) = fmt_convert(format[statement[1]])
         if len(statement) < 3:
             return 'printf("' + fmt + '");'
         else:
-            return 'printf("' + fmt + '", ' + ', '.join(map(print_expr, statement[2:])) + ');'
+            return 'printf("' + fmt + '", ' + ', '.join(map(print_C_expr, statement[2:])) + ');'
     elif statement[0] == 'read':
         (fmt, types) = fmt_convert(format[statement[1]], write=False)
         return 'scanf("' + fmt + '", ' + ', '.join(map(lambda x: '&'+x, statement[2:])) + ');'
@@ -859,23 +874,23 @@ def print_statement(statement):
         if len(statement) == 1:
             return "return;"
         else:
-            return "return %s;" % print_expr(statement[1])
+            return "return %s;" % print_C_expr(statement[1])
     elif statement[0] == 'save':
         rep = ''
         for expr in statement[1]:
-            rep += '*recursor++ = (double)(%s); ' % print_expr(expr)
+            rep += '*recursor++ = (double)(%s); ' % print_C_expr(expr)
         return rep
     elif statement[0] == 'set_list_to':
         var = statement[1]
-        return normalmode + " " + prin1(('variable', var, dimensions[var])) + ", *recursor = " + var + ";"
+        return normalmode + " " + prinC1(('variable', var, dimensions[var])) + ", *recursor = " + var + ";"
     elif statement[0] == 'substitution':
-        return statement[1] + ' = ' + print_expr(statement[2]) + ';'
+        return statement[1] + ' = ' + print_C_expr(statement[2]) + ';'
     elif statement[0] == 'whenever':
-        return 'if (' + print_expr(statement[1]) + ') {'
+        return 'if (' + print_C_expr(statement[1]) + ') {'
     else:
         return('// ' + `statement`)
 
-def generate(out):
+def generate_C_code(out):
     out.write("/* generated by the MAD compiler */\n")
     for header in headers:
         out.write('#include <%s.h>\n' % header)
@@ -899,7 +914,7 @@ def generate(out):
             out.write("  " + label+':\n')
         if statement[0] in ('for', 'map'):
             scopes.append(statement[1])
-        rep = print_statement(statement)
+        rep = print_C_statement(statement)
         if rep:
             indentchange = rep.count('{') - rep.count('}')
             if indentchange < 0:
@@ -991,7 +1006,7 @@ if __name__ == '__main__':
 
     # Generate code
     if arguments == ['-']:
-        generate(sys.stdout)
+        generate_C_code(sys.stdout)
         sys.exit(0)
 
     if not target and len(arguments) == 1:
@@ -1000,7 +1015,7 @@ if __name__ == '__main__':
         sys.stderr.write("mad: -o is required with multiple sourcefiles.\n")
         sys.exit(1)
     out = open(target + ".c", "w")
-    generate(out)
+    generate_C_code(out)
     out.close()
     if binary:
         # Must be gcc, else compilation of internal functions will fail