From 23076faf5a2993b0249b6ba9e86fe9b4a0c3ae67 Mon Sep 17 00:00:00 2001 From: "Eric S. Raymond" Date: Sat, 14 Feb 2004 01:30:16 +0000 Subject: [PATCH] Better error-catching during analysis. --- mad | 241 +++++++++++++++++++++++++++++++----------------------------- 1 file changed, 126 insertions(+), 115 deletions(-) diff --git a/mad b/mad index a7bfd72..dcd8691 100755 --- a/mad +++ b/mad @@ -59,7 +59,7 @@ def t_STRING(t): return t def t_FUNCALL(t): - r'[A-Z][A-Z0-9]*\.(?=\s*(\(|eos))' + r'[A-Z][A-Z0-9]*\.(?=\s*(\(|eos|,|\)))' t.type = reserved_map.get(t.value, 'FUNCALL') t.value = t.value.lower() return t @@ -470,6 +470,12 @@ def p_function_application(t): if t[1] in ('elog.', 'sqrt.') and "math" not in headers: headers.append("math") +def p_expression_funcall0(t): + 'expression : FUNCALL' + var = t[1] + t[0] = ('variable', var) + refcount[var] = refcount.get(var, 0) + 1 + def p_expression_name(t): 'expression : NAME' var = t[1] @@ -520,123 +526,128 @@ def analyze(): if statement[0] == 'end_function' and i < len(deck)-1 and deck[i+1][3][0] != 'extern': deck.insert(i+1, (file, line, None, ('entry', 'main.', ()))) hasmain = True - # Mine the code for compile-time directives - for (file, line, label, statement) in deck: - if statement[0] == 'boolean': - for var in statement[1:]: - typedict[currentfunc][var] = 'bool' - elif statement[0] == 'dimension': - for (var, dimlist) in statement[1]: - dimensions[var] = dimlist - elif statement[0] == 'entry': - currentfunc = statement[1] - funcline = line - typedict[currentfunc] = {} - elif statement[0] == 'integer': - for var in statement[1:]: - typedict[currentfunc][var] = 'int' - elif statement[0] == 'normal': - global normalmode - normalmode = statement[1] - elif statement[0] in ("print", "read"): - if "stdio" not in headers: - headers.append("stdio") - elif statement[0] == 'values': - var = statement[1] - if var in refcount: - static[var] = statement[2] - else: - format[var] = statement[2] - # Reorder code tuples so internal functions are just after entry points - lastentry = -1 - savelist = [] - internalcount = 0 - for i in range(len(deck)): - (file, line, label, statement) = deck[i] - if statement[0] == 'entry': - lastentry = i - internalcount = 1 - for line in savelist: - deck.insert(i, deck.pop(line)) - savelist = [] - elif statement[0] == 'internal': - if lastentry != -1: - deck.insert(lastentry + internalcount, deck.pop(i)) - else: - savelist.append(i) - internalcount += 1 - # Reorder code tuples so SET LIST arrays are global. - firstentry = -1 - for i in range(len(deck)): - (file, line, label, statement) = deck[i] - if statement[0] == 'entry' and firstentry == -1: - firstentry = i - elif statement[0] == 'set_list_to': - deck.insert(firstentry, deck.pop(i)) - # Do type deductions from format fields - for card in deck: - (file, line, label, statement) = card - if statement[0] == 'entry': - currentfunc = statement[1] - funcline = line - elif statement[0] == 'read': - if statement[1] not in format: - croak(card, "uninitialized format string" +`statement[1]`) - else: - (fmt, types) = fmt_convert(format[statement[1]]) - for (vtype, var) in zip(types, statement[2:]): - if type(var) == type(()) and var[0] == 'range': - 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 - # expression evaluation until we can't deduce any more int or bool - # type bindings for variables. Everything else just defaults to - # double. - while True: - deductions = 0 + try: + # Mine the code for compile-time directives + for (file, line, label, statement) in deck: + if statement[0] == 'boolean': + for var in statement[1:]: + typedict[currentfunc][var] = 'bool' + elif statement[0] == 'dimension': + for (var, dimlist) in statement[1]: + dimensions[var] = dimlist + elif statement[0] == 'entry': + currentfunc = statement[1] + funcline = line + typedict[currentfunc] = {} + elif statement[0] == 'integer': + for var in statement[1:]: + typedict[currentfunc][var] = 'int' + elif statement[0] == 'normal': + global normalmode + normalmode = statement[1] + elif statement[0] in ("print", "read"): + if "stdio" not in headers: + headers.append("stdio") + elif statement[0] == 'values': + var = statement[1] + if var in refcount: + static[var] = statement[2] + else: + format[var] = statement[2] + # Reorder code tuples so internal functions are just after entry points + lastentry = -1 + savelist = [] + internalcount = 0 + for i in range(len(deck)): + (file, line, label, statement) = deck[i] + if statement[0] == 'entry': + lastentry = i + internalcount = 1 + for line in savelist: + deck.insert(i, deck.pop(line)) + savelist = [] + elif statement[0] == 'internal': + if lastentry != -1: + deck.insert(lastentry + internalcount, deck.pop(i)) + else: + savelist.append(i) + internalcount += 1 + # Reorder code tuples so SET LIST arrays are global. + firstentry = -1 + for i in range(len(deck)): + (file, line, label, statement) = deck[i] + if statement[0] == 'entry' and firstentry == -1: + firstentry = i + elif statement[0] == 'set_list_to': + deck.insert(firstentry, deck.pop(i)) + # Do type deductions from format fields for card in deck: (file, line, label, statement) = card if statement[0] == 'entry': - # Bookkeeping, so we know what function we're in currentfunc = statement[1] funcline = line - elif statement[0] == 'return': - # Give the function the type of the last return statement. - # We're screwed if two different returns in a function have - # different modes. - m = mode(statement[1]) - returntypes[currentfunc] = m - if m != normalmode and returntypes[currentfunc] != m: - deductions += 1 - elif statement[0] == 'restore': - for var in statement[1]: - typedict[currentfunc][var] = normalmode - elif statement[0] == 'substitution': - # Propagate type markers through assignment - var = statement[1] - m = mode(statement[2]) - typedict[currentfunc][var] = m - if m != normalmode and typedict[currentfunc][statement[1]]!=m: - deductions += 1 - if deductions == 0: - break - # Now associate entry point names with function definitions: - for i in range(len(deck)): - (file, line, label, statement) = deck[i] - if statement[0] == 'entry' and len(statement) == 2: - name = statement[1] - for j in range(i): - prev = deck[i-j-1][3] - if prev[0] == 'external_function': - deck[i] = (file, line, label, ('entry', name, prev[1])) - break - elif prev[0] == 'entry': - croak(deck[i-j-1],"multiple ENTRY points are not supported") - else: - croak(deck[i], 'no EXTERNAL declaration matches this ENTRY') + elif statement[0] == 'read': + if statement[1] not in format: + croak(card, "uninitialized format string" +`statement[1]`) + else: + (fmt, types) = fmt_convert(format[statement[1]]) + for (vtype, var) in zip(types, statement[2:]): + if type(var) == type(()) and var[0] == 'range': + 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 + # expression evaluation until we can't deduce any more int or bool + # type bindings for variables. Everything else just defaults to + # double. + while True: + deductions = 0 + for card in deck: + (file, line, label, statement) = card + if statement[0] == 'entry': + # Bookkeeping, so we know what function we're in + currentfunc = statement[1] + funcline = line + elif statement[0] == 'return': + # Give the function the type of the last return statement. + # We're screwed if two different returns in a function have + # different modes. + m = mode(statement[1]) + returntypes[currentfunc] = m + if m != normalmode and returntypes[currentfunc] != m: + deductions += 1 + elif statement[0] == 'restore': + for var in statement[1]: + typedict[currentfunc][var] = normalmode + elif statement[0] == 'substitution': + # Propagate type markers through assignment + var = statement[1] + m = mode(statement[2]) + typedict[currentfunc][var] = m + if m != normalmode and typedict[currentfunc][statement[1]]!=m: + deductions += 1 + if deductions == 0: + break + # Now associate entry point names with function definitions: + for i in range(len(deck)): + (file, line, label, statement) = deck[i] + if statement[0] == 'entry' and len(statement) == 2: + name = statement[1] + for j in range(i): + prev = deck[i-j-1][3] + if prev[0] == 'external_function': + deck[i] = (file, line, label, ('entry', name, prev[1])) + break + elif prev[0] == 'entry': + croak(deck[i-j-1],"multiple ENTRY points are not supported") + else: + croak(deck[i], 'no EXTERNAL declaration matches this ENTRY') + except: + sys.stderr.write("mad: internal error while analyzing code for line %d\n" % line) + (exc_type, exc_value, exc_traceback) = sys.exc_info() + raise exc_type, exc_value, exc_traceback def mode(t): "Compute the return type of an expression" @@ -857,7 +868,7 @@ def print_C_statement(statement): types = typedict[currentfunc] rep = "\n" + returntypes.get(currentfunc, normalmode) + " " + currentfunc[:-1] + "(" defaulted = [] - if statement[2]: + if len(statement) > 2: for (dummy, var) in statement[2]: declarator = ("*" * arraydepths.get(var, 0)) + var if var in types: @@ -870,7 +881,7 @@ def print_C_statement(statement): rep = rep + ") {" #if defaulted: # sys.stderr.write("warning: defaulted base type for %s\n" % ", ".join(defaulted)) - declarations = "" + declarations = "\n" for vtype in ('double', 'int', 'bool', 'char'): vars = filter(lambda x: types[x] == vtype, types.keys()) if vars: -- 2.43.0