]> thyrsus.com Git - mad.git/commitdiff
This passes our regression test.
authorEric S. Raymond <esr@thyrsus,com>
Fri, 13 Feb 2004 11:17:30 +0000 (11:17 +0000)
committerEric S. Raymond <esr@thyrsus,com>
Fri, 13 Feb 2004 11:17:30 +0000 (11:17 +0000)
mad

diff --git a/mad b/mad
index 651eddf1c1635d60b93a7ac5b53f76aab1e41a22..662f66340d0ac29cb59ba551a4bee34f1611691d 100755 (executable)
--- a/mad
+++ b/mad
@@ -46,13 +46,17 @@ t_DIVIDE  = r'/'
 t_EQUALS  = r'='
 t_LPAREN  = r'\('
 t_RPAREN  = r'\)'
-t_STRING  = r'\$[^$]*\$'
 t_DOTRANGE= r'\.\.\.'
 
 reserved_map = { }
 for r in reserved:
     reserved_map[r] = r
 
+def t_STRING(t):
+    r'\$[^$]*\$'
+    t.value = t.value[1:-1]
+    return t
+
 def t_NAME(t):
     r'[A-Z][A-Z0-9_]*(\.(?!P))?'
     t.type = reserved_map.get(t.value, 'NAME')
@@ -248,8 +252,11 @@ def p_pause(t):
 
 ## PRINT_FORMAT
 def p_print_format(t):
-    'statement : PRINT_FORMAT outlist'
-    t[0] = ('print',) + tuple(t[2])
+    'statement : PRINT_FORMAT NAME COMMA outlist'
+    t[0] = ('print', t[2]) + tuple(t[4])
+def p_print_format0(t):
+    'statement : PRINT_FORMAT NAME'
+    t[0] = ('print', t[2])
     # This is shared with SAVE DATA
 def p_outlist_continue(t):
     'outlist : outlist COMMA outval'
@@ -263,7 +270,7 @@ def p_outval(t):
     t[0] = t[1]
 def p_range(t):
     'range : NAME application DOTRANGE NAME application'
-    t[0] = ('range', t[1], t[2], t[5])
+    t[0] = ('range', t[1], t[2][0], t[5][0])
     if t[1] != t[4]:
         sys.stderr.write("variable names in range don't match!")
         sys.exit(1)
@@ -271,15 +278,15 @@ def p_range(t):
 ## R
 def p_remark1(t):
     'statement : COMMENT STRING'
-    t[0] = ('remark', t[2][1:-1])
+    t[0] = ('remark', t[2])
 def p_remark2(t):
     'statement : COMMENT'
     t[0] = ('remark',)
 
 ## READ_FORMAT
 def p_read_format(t):
-    'statement : READ_FORMAT varlist'
-    t[0] = ('read',) + tuple(t[2])
+    'statement : READ_FORMAT NAME COMMA varlist'
+    t[0] = ('read', t[2]) + tuple(t[4])
     # This is shared with RESTORE_DATA
 def p_varlist_continue(t):
     'varlist : varlist COMMA lval'
@@ -517,7 +524,7 @@ def analyze():
             if var in refcount:
                 static[var] = statement[2]
             else:
-                format[var] = statement[2][1:-1]
+                format[var] = statement[2]
     # Reorder code tuples so internal functions are just after entry points
     for i in range(len(deck)):
         (file, line, label, statement) = deck[i]
@@ -546,8 +553,14 @@ def analyze():
                 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
+                for (vtype, var) in zip(types, statement[2:]):
+                    if type(var) == type(()) and var[0] == 'range':
+                        if type == 'string':
+                            typedict[currentfunc][var[1]] = 'char'
+                        else:
+                            typedict[currentfunc][var[1]] = vtype
+                    else:
+                        typedict[currentfunc][var] = vtype
     # Type inference loop.  We initialized for this by deducing types
     # from READ FORMAT statements. INTEGER, and BOOLEAN declarations
     # above.  Now propagate markers of non-normalmode type through
@@ -598,9 +611,9 @@ def mode(t):
     "Compute the return type of an expression"
     #print "->mode", t
     if t[0] == 'variable':
-        #print "<-mode of ", t[1]
+        #print "<-mode of ", t[1], typedict[currentfunc].get(t[1], normalmode)
         return typedict[currentfunc].get(t[1], normalmode)
-    elif t[0] in ('UMINUS', 'UPLUS', 'POW', 'ABS'):
+    elif t[0] in ('p', 'abs') or t[0] in ('+', '-') and len(t) == 2:
         #print "<-mode of ", t[1]
         return mode(t[1])
     elif t[0] == 'intnum':
@@ -626,13 +639,14 @@ def mode(t):
     else:
         left = mode(t[1])
         right = mode(t[2])
+        #print "left mode %s, right mode %s" % (left, right)
         if left == 'double' or right == 'double':
             #print "<-mode of binary operand"
             return 'double'
         if left == 'int' or right == 'int':
             #print "<-mode of binary operand"
             return 'int'
-        sys.write.stderr("mad: internal error while computing mode of %s\n"%t)
+        sys.stderr.write("mad: internal error while computing mode of %s\n" % `t`)
         sys.exit(1)
 
 def prinC1(t):
@@ -743,6 +757,13 @@ def fmt_convert(str, write=True):
             str = str[i+1:]
             for i in range(count):
                 types += innertypes * count
+        elif str[0] == 'C':
+            i = 1
+            while str[i] in '0123456789':
+                i += 1
+            res += "%" + `count * int(str[1:i])` + "s"
+            str = str[i:]
+            types += ['string']
         elif str[0] == 'F':
             i = 1
             while str[i] in '0123456789.':
@@ -809,10 +830,10 @@ def print_C_statement(statement):
         #if defaulted:
         #    sys.stderr.write("warning: defaulted base type for %s\n" % ", ".join(defaulted))
         declarations = ""
-       for type in ('double', 'int', 'bool'):
-            vars = filter(lambda x: types[x] == type, types.keys())
+       for vtype in ('double', 'int', 'bool'):
+            vars = filter(lambda x: types[x] == vtype, types.keys())
             if vars: 
-                declarations +=  type + " " + ", ".join(vars) + "; "
+                declarations +=  vtype + " " + ", ".join(vars) + "; "
         if declarations:
             rep += "    " + declarations[:-1] + "\n"
         return rep
@@ -856,7 +877,19 @@ def print_C_statement(statement):
             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:])) + ');'
+        inlist = []
+        for (inspec, intype) in zip(statement[2:], types):
+            if type(inspec) == type(""):
+                inlist.append("&" + inspec)
+            elif type(inspec) == type(()) and inspec[0] == 'range' and intype == 'string':
+                if inspec[2] == ('intnum', '1'):
+                    inlist.append(print_C_expr(('variable', inspec[1])))
+                else:
+                    inlist.append(print_C_expr(('+',('variable', inspec[1]),('-',inspec[2],('intnum', '1')))))
+            else:
+                sys.stderr.write("unsupported type in READ FORMAT\n")
+                sys.exit(1)
+        return 'scanf("' + fmt + '", ' + ', '.join(inlist) + ');'
     elif statement[0] == 'remark':
         if len(statement) == 1:
             return "\n"
@@ -968,7 +1001,7 @@ if __name__ == '__main__':
         # Put them after every newline, then remove if they're followed
         # by whitespace and a continuation digit
         source = source.replace("\n", " eos\n")
-        source = re.sub(';\n(\s*)[0-9]+', '\n\\1', source)
+        source = re.sub('eos\n(\s*)[0-9]+', '\n\\1', source)
         # Transform some adjacent groups of keywords into
         # agglomerates. This lets us get away with stuff like SET LIST
         # TO LIST that the parser would otherwise choke on, because