#!/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')
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
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.")
"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]]
'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
'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]]
'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):
import sys, re
-dimensions = {}
-static = {}
-format = {}
-hasmain = False
-
# Map MAD intrinsics to C library functions
madfunc_map = {'elog':'log'}
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
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;}' % \
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':
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
mad_debug = int(val)
elif opt == '-g':
dump_tuples = True
+ elif opt == '-l':
+ lexercise = True
elif opt == '-o':
target = val
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")