]> thyrsus.com Git - mad.git/commitdiff
We have gotten rid of the keyword collision.
authorEric S. Raymond <esr@thyrsus,com>
Tue, 10 Feb 2004 11:00:05 +0000 (11:00 +0000)
committerEric S. Raymond <esr@thyrsus,com>
Tue, 10 Feb 2004 11:00:05 +0000 (11:00 +0000)
mad

diff --git a/mad b/mad
index 5fbab39575439f6f627b2876747f9306a839e573..39a891d769b0ddd3e2e0de3a6f24b7fd99b54549 100755 (executable)
--- a/mad
+++ b/mad
@@ -1,11 +1,11 @@
 #!/usr/bin/env python
 
-reserved = ('BOOLEAN', 'CONDITIONAL', 'CONTINUE', 'DATA', 'DIMENSION', 'END',
-            'ENTRY', 'EXECUTE', 'EXTERNAL', 'FOR', 'FORMAT',
-            'FUNCTION', 'INTEGER', 'INTERNAL', 'IS', 'LIST', 'MODE',
-            'NORMAL', 'OF', 'PAUSE', 'PRINT', 'PROGRAM', 'READ', 'RESTORE',
-            'RETURN', 'SAVE', 'SET', 'THROUGH', 'TO', 'TRANSFER',
-            'VALUES', 'VECTOR', 'WHENEVER',
+reserved = ('BOOLEAN', 'CONDITIONAL', 'CONTINUE', 'DATA', 'DIMENSION',
+            'END', 'ENTRY', 'EXECUTE', 'EXTERNAL', 'FOR', 'FUNCTION',
+            'INTEGER', 'INTERNAL', 'IS', 'MODE', 'NORMAL',
+            'OF', 'PAUSE', 'PRINT_FORMAT', 'PROGRAM', 'READ_FORMAT',
+            'RESTORE', 'RETURN', 'SAVE', 'SET_LIST_TO', 'THROUGH',
+            'TO', 'TRANSFER', 'VALUES', 'VECTOR', 'WHENEVER',
             # This is a pseudo-keyword generated early in compilation.
             'COMMENT')
 
@@ -53,9 +53,9 @@ for r in reserved:
     reserved_map[r] = r
 
 def t_NAME(t):
-    r'[A-Z][A-Z0-9]*(\.(?!P))?'
+    r'[A-Z][A-Z0-9_]*(\.(?!P))?'
     t.type = reserved_map.get(t.value, 'NAME')
-    if t.type and t.value[-1] == '.':
+    if t.value[-1] == '.':
         t.type = 'FUNCALL'
     t.value = t.value.lower()
     return t
@@ -117,12 +117,17 @@ arraydepths = {}
 returntypes = {}
 normalmode = 'double'
 dummycount = 0
+dimensions = {}
+static = {}
+format = {}
+hasmain = False
 
 def initfunc(f):
     global currentfunc
     currentfunc = f
     typedict[currentfunc] = {}
     arraydepths[currentfunc] = {}
+    dimensions[currentfunc] = {}
     funcnames.append(currentfunc)
 
 initfunc("main.")
@@ -252,10 +257,10 @@ def p_pause(t):
     "statement : PAUSE expression"
     t[0] == ('pause', t[1])
 
-## PRINT FORMAT
+## PRINT_FORMAT
 def p_print_format(t):
-    'statement : PRINT FORMAT NAME COMMA exprlist'
-    t[0] = ('print', t[3]) + tuple(t[5])
+    'statement : PRINT_FORMAT NAME COMMA exprlist'
+    t[0] = ('print', t[2]) + tuple(t[4])
 def p_exprlist(t):
     'exprlist : expression'
     t[0] = [t[1]]
@@ -263,7 +268,7 @@ def p_exprlist_continue(t):
     'exprlist : exprlist COMMA expression'
     t[0] = t[1] + [t[3]]
 def p_print_format0(t):
-    'statement : PRINT FORMAT NAME'
+    'statement : PRINT_FORMAT NAME'
     t[0] = ('print', t[3])
 
 ## R
@@ -275,10 +280,10 @@ def p_remark2(t):
     'statement : COMMENT'
     t[0] = ('remark',)
 
-## READ FORMAT
+## READ_FORMAT
 def p_read_format(t):
-    'statement : READ FORMAT NAME COMMA varlist'
-    t[0] = ('read', t[3]) + tuple(t[5])
+    'statement : READ_FORMAT NAME COMMA varlist'
+    t[0] = ('read', t[2]) + tuple(t[4])
 def p_varlist(t):
     'varlist : NAME'
     t[0] = [t[1]]
@@ -302,10 +307,10 @@ def p_save_return(t):
     'statement : SAVE RETURN'
     t[0] = ('save_return',)
 
-## SET LIST
+## SET_LIST_TO
 def p_set_list(t):
-    'statement : SET LIST TO NAME'
-    t[0] = ('set_list', t[3])
+    'statement : SET_LIST_TO NAME'
+    t[0] = ('set_list_to', t[2])
 
 ## THROUGH
 def p_through_for(t):
@@ -451,11 +456,6 @@ yacc.yacc()
 
 import sys, re
 
-dimensions = {}
-static = {}
-format = {}
-hasmain = False
-
 # Map MAD intrinsics to C library functions
 madfunc_map = {'elog':'log'}
 
@@ -476,7 +476,7 @@ def analyze():
     else:
         for i in range(len(deck)):
             (file, line, label, statement) = deck[i]
-            if statement[0] == 'end_function' and i < len(deck)-1 and deck[i+1][2][0] != 'extern':
+            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
@@ -802,7 +802,7 @@ def print_statement(statement):
     elif statement[0] == 'goto':
         return 'goto ' + statement[1] + ';' 
     elif statement[0] == 'if':
-        scopes.append(t[1])
+        scopes.append(statement[1])
         return 'if (' + print_expr(statement[1]) + ') ' + print_statement(statement[2])
     elif statement[0] == 'internal':
         return '%s %s {return %s;}' % \
@@ -841,8 +841,8 @@ def print_statement(statement):
             return "return %s;" % print_expr(statement[1])
     elif statement[0] == 'or':
         return 'else if (' + print_expr(statement[2]) + ') {'
-    elif statement[0] == 'set_list':
-        return normaltype + " *recursor = " + statement[2] + ";"
+    elif statement[0] == 'set_list_to':
+        return normalmode + " *recursor = " + statement[1] + ";"
     elif statement[0] == 'substitution':
         return statement[1] + ' = ' + print_expr(statement[2]) + ';'
     elif statement[0] == 'whenever':
@@ -886,9 +886,10 @@ if __name__ == '__main__':
     import os, getopt
     mad_debug = 0
     binary = True
+    lexercise = False
     dump_tuples = False
     target = None
-    (options, arguments) = getopt.getopt(sys.argv[1:], "cd:go:")
+    (options, arguments) = getopt.getopt(sys.argv[1:], "cd:glo:")
     for (opt, val) in options:
         if opt == '-c':
             binary = False
@@ -896,6 +897,8 @@ if __name__ == '__main__':
             mad_debug = int(val)
         elif opt == '-g':
             dump_tuples = True
+        elif opt == '-l':
+            lexercise = True
         elif opt == '-o':
             target = val
 
@@ -914,16 +917,36 @@ if __name__ == '__main__':
             fp = open(file)
             source = fp.read()
             fp.close()
-        # A grotty hack to transform remarks
-        source = re.sub(r'\tR\n', '\tCOMMENT\n', source)
-        source = re.sub(r'\tR (.*)', '\tCOMMENT $\\1$', source)
+        # A grotty hack to transform remarks; we need a leader that cannot
+        # be mistaken for a name, so we make it > 6 chars long
+        source = re.sub(r'(^\s*)R\n', '\\1COMMENT\n', source)
+        source = re.sub(r'(\n\s*)R\n', '\\1COMMENT\n', source)
+        source = re.sub(r'(\n\s*)R (.*)', '\\1COMMENT $\\2$', source)
         # Equally grotty hack to add end-of-statement delimiters.
         # Put them after every newline, then remove if they're followed
         # by whitespace and a continuation digit
         source = source.replace("\n", " ;\n")
         source = re.sub(';\n(\s*)[0-9]+', '\n\\1', source)
-        # Parse
-        yacc.parse(source, debug=mad_debug)
+        # OK, now for a real kluge.  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 the keywords have been lifted out of where they
+        # can collide with identifier space.
+        source = source.replace("SET LIST TO", "SET_LIST_TO")
+        source = source.replace("PRINT FORMAT", "PRINT_FORMAT")
+        source = source.replace("READ FORMAT", "READ_FORMAT")
+        # Lex or parse
+        if lexercise:
+            lex.input(source)
+            while 1:
+                tok = lex.token()
+                if not tok: break
+                print "(%s,'%s',%d)" % (tok.type, tok.value, tok.lineno)
+        else:
+            yacc.parse(source, debug=mad_debug)
+
+    if lexercise:
+        sys.exit(0)
 
     if not deck:
         sys.stderr.write("mad: empty deck\n")