]> thyrsus.com Git - mad.git/commitdiff
This version parses wordlist correctly.
authorEric S. Raymond <esr@thyrsus,com>
Fri, 13 Feb 2004 08:56:59 +0000 (08:56 +0000)
committerEric S. Raymond <esr@thyrsus,com>
Fri, 13 Feb 2004 08:56:59 +0000 (08:56 +0000)
mad

diff --git a/mad b/mad
index bd201baf63c15fda44b8df548362271b25a47568..bd314e3e239bf7035bdc8931a4be83c9fc05771e 100755 (executable)
--- a/mad
+++ b/mad
@@ -10,8 +10,8 @@ reserved = ('BOOLEAN', 'CONDITIONAL', 'CONTINUE', 'DATA', 'DIMENSION',
             'COMMENT', 'DOTRANGE')
 
 tokens = reserved + (
-    'SEMI', 'COMMA',
-    'NAME','INTNUM', 'DOUBLENUM', 'BOOLNUM', 'STRING', 'FUNCALL',
+    'EOS', 'COMMA',
+    'NAME','ARRAYNAME','INTNUM', 'DOUBLENUM', 'BOOLNUM', 'STRING', 'FUNCALL',
     'LPAREN','RPAREN',
     'PLUS','MINUS','TIMES','DIVIDE','EQUALS',
     'NOT', 'OR', 'AND', 'THEN', 'EQV',
@@ -24,7 +24,7 @@ logops = ('NOT', 'OR', 'AND', 'THEN', 'EQV',
 
 # Tokens
 
-t_SEMI    = r';'
+t_EOS     = r'eos'
 t_COMMA   = r'\,'
 t_ABS     = r'\.ABS\.'
 t_POW     = r'\.P\.'
@@ -53,6 +53,11 @@ reserved_map = { }
 for r in reserved:
     reserved_map[r] = r
 
+def t_ARRAYNAME(t):
+    r'%[A-Z][A-Z0-9]*'
+    t.value = t.value.lower()[1:]
+    return t
+
 def t_NAME(t):
     r'[A-Z][A-Z0-9_]*(\.(?!P))?'
     t.type = reserved_map.get(t.value, 'NAME')
@@ -134,11 +139,11 @@ def p_program(t):
                | program card'''
 
 def p_card(t):
-    'card : statement SEMI' 
+    'card : statement EOS' 
     deck.append((sourcefile, t.lineno(1), None, t[1]))
 
 def p_labeled_card(t):
-    'card : NAME statement SEMI'
+    'card : NAME statement EOS'
     deck.append((sourcefile, t.lineno(1), t[1], t[2]))
 
 # Statement level
@@ -164,10 +169,10 @@ def p_statement_dimension(t):
     'statement : DIMENSION dimension_list'
     t[0] = ('dimension', t[2])
 def p_dimension_list(t):
-    'dimension_list : NAME application'
+    'dimension_list : ARRAYNAME application'
     t[0] = [[t[1], tuple(t[2])]]
 def p_dimension_list_continue(t):
-    'dimension_list : dimension_list COMMA NAME application'
+    'dimension_list : dimension_list COMMA ARRAYNAME application'
     t[0] = t[1] + [[t[3], tuple(t[4])]]
 
 ## END
@@ -248,25 +253,22 @@ def p_pause(t):
 
 ## PRINT_FORMAT
 def p_print_format(t):
-    '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])
+    'statement : PRINT_FORMAT outlist'
+    t[0] = ('print',) + tuple(t[2])
     # This is shared with SAVE DATA
-def p_outlist(t):
-    'outlist : outval'
-    t[0] = [t[1]]
 def p_outlist_continue(t):
     'outlist : outlist COMMA outval'
     t[0] = t[1] + [t[3]]
+def p_outlist(t):
+    'outlist : outval'
+    t[0] = [t[1]]
 def p_outval(t):
     '''outval : range
               | expression'''
     t[0] = t[1]
 def p_range(t):
-    'range : NAME application DOTRANGE NAME application'
-    t[0] = ('slice', t[1], t[2], t[5])
+    'range : ARRAYNAME application DOTRANGE ARRAYNAME application'
+    t[0] = ('range', t[1], t[2], t[5])
     if t[1] != t[4]:
         sys.stderr.write("variable names in range don't match!")
         sys.exit(1)
@@ -281,18 +283,19 @@ def p_remark2(t):
 
 ## READ_FORMAT
 def p_read_format(t):
-    'statement : READ_FORMAT NAME COMMA varlist'
-    t[0] = ('read', t[2]) + tuple(t[4])
+    'statement : READ_FORMAT varlist'
+    t[0] = ('read',) + tuple(t[2])
     # This is shared with RESTORE_DATA
-def p_varlist(t):
-    'varlist : NAME'
-    t[0] = [t[1]]
-def p_varlist_range(t):
-    'varlist : varlist COMMA range'
-    t[0] = t[1] + [t[3]]
 def p_varlist_continue(t):
-    'varlist : varlist COMMA NAME'
+    'varlist : varlist COMMA lval'
     t[0] = t[1] + [t[3]]
+def p_varlist(t):
+    'varlist : lval'
+    t[0] = [t[1]]
+def p_lval(t):
+    '''lval : range
+            | NAME'''
+    t[0] = t[1]
 
 ## RESTORE
 def p_restore_data(t):
@@ -418,7 +421,7 @@ def p_expression_float(t):
     t[0] = ('doublenum', t[1])
 
 def p_expression_subscript(t):
-    'expression : NAME application'
+    'expression : ARRAYNAME application'
     t[0] = ('variable', t[1], tuple(t[2]))
     var = t[1]
     refcount[var] = refcount.get(var, 0) + 1
@@ -518,7 +521,6 @@ def analyze():
             var = statement[1]
             if var in refcount:
                 static[var] = statement[2]
-                untyped.remove(var)
             else:
                 format[var] = statement[2][1:-1]
     # Reorder code tuples so internal functions are just after entry points
@@ -970,16 +972,22 @@ if __name__ == '__main__':
         # 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 = source.replace("\n", " eos\n")
         source = re.sub(';\n(\s*)[0-9]+', '\n\\1', source)
-        # 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.
+        # 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")
+        # SLR parsing seems to be a tad too weak for the full grammar of MAD.
+        # It hits lookahead problens in parsing array references and array
+        # ranges -- doesn't know that it should look ahead far enough to
+        # see the leading paren on the subscript.  So, decorate array
+        # references in a way that will make them syntactucally obvious.
+        source = re.sub(r"[A-Z][A-Z0-9]*\s*\(", r"%\g<0>", source)
         # Lex or parse
         if lexercise:
             lex.input(source)