From: Eric S. Raymond Date: Tue, 20 Jan 2004 12:14:51 +0000 (+0000) Subject: Format translation appears to work. X-Git-Tag: 1.0~191 X-Git-Url: http://thyrsus.com/gitweb/?a=commitdiff_plain;h=0210ca44965ca10c8374023b79d2eda41753bfe6;p=mad.git Format translation appears to work. --- diff --git a/mad b/mad index d5614de..bbf1464 100755 --- 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 " - print "main(int argc, char *argv[])" - print "{" + print '#include ' + 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 '}'