From 632eb856425048ef6dc0ea5d0d4cd05021507f2e Mon Sep 17 00:00:00 2001 From: "Eric S. Raymond" Date: Fri, 13 Feb 2004 11:17:30 +0000 Subject: [PATCH] This passes our regression test. --- mad | 69 +++++++++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 51 insertions(+), 18 deletions(-) diff --git a/mad b/mad index 651eddf..662f663 100755 --- 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 -- 2.43.0