]> thyrsus.com Git - mad.git/commitdiff
Better error-catching during analysis.
authorEric S. Raymond <esr@thyrsus,com>
Sat, 14 Feb 2004 01:30:16 +0000 (01:30 +0000)
committerEric S. Raymond <esr@thyrsus,com>
Sat, 14 Feb 2004 01:30:16 +0000 (01:30 +0000)
mad

diff --git a/mad b/mad
index a7bfd72cbf925f04deec225f598bb97bc02a16b0..dcd869148985aafb93dd3a37c3f566c1a7c66be5 100755 (executable)
--- 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: