From 30b5c93cfa18d0f7ce4533ff75cff38488288229 Mon Sep 17 00:00:00 2001 From: "Eric S. Raymond" Date: Tue, 10 Feb 2004 11:00:05 +0000 Subject: [PATCH] We have gotten rid of the keyword collision. --- mad | 89 ++++++++++++++++++++++++++++++++++++++----------------------- 1 file changed, 56 insertions(+), 33 deletions(-) diff --git a/mad b/mad index 5fbab39..39a891d 100755 --- 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") -- 2.43.0