tokens = (
'DEF',
'IF',
+ 'ELSE',
'NAME',
'NUMBER', # Python decimals
'STRING', # single quoted strings only; syntax of raw strings
RESERVED = {
"def": "DEF",
"if": "IF",
+ "else": "ELSE",
"return": "RETURN",
}
at_line_start = False
indent = MAY_INDENT
token.must_indent = False
-
+
elif token.type == "NEWLINE":
at_line_start = True
if indent == MAY_INDENT:
if token.must_indent:
print "must_indent",
print
-
+
# WS only occurs at the start of the line
# There may be WS followed by NEWLINE so
# only track the depth here. Don't indent/dedent
assert token is not None
for _ in range(1, len(levels)):
yield DEDENT(token.lineno)
-
+
# The top-level filter adds an ENDMARKER, if requested.
# Python's grammar uses it.
p[0] = p[1] + p[2]
else:
p[0] = p[1]
-
+
# funcdef: [decorators] 'def' NAME parameters ':' suite
# ignoring decorators
def p_funcdef(p):
"funcdef : DEF NAME parameters COLON suite"
p[0] = ast.Function(None, p[2], list(p[3]), (), 0, None, p[5])
-
+
# parameters: '(' [varargslist] ')'
def p_parameters(p):
"""parameters : LPAR RPAR
p[0] = []
else:
p[0] = p[2]
-
-# varargslist: (fpdef ['=' test] ',')* ('*' NAME [',' '**' NAME] | '**' NAME) |
+
+# varargslist: (fpdef ['=' test] ',')* ('*' NAME [',' '**' NAME] | '**' NAME) |
# highly simplified
def p_varargslist(p):
"""varargslist : varargslist COMMA NAME
"""stmt : simple_stmt"""
# simple_stmt is a list
p[0] = p[1]
-
+
def p_stmt_compound(p):
"""stmt : compound_stmt"""
p[0] = [p[1]]
p[0] = p[1]
def p_if_stmt(p):
- 'if_stmt : IF test COLON suite'
- p[0] = ast.If([(p[2], p[4])], None)
+ """if_stmt : IF test COLON suite ELSE COLON suite
+ | IF test COLON suite
+ """
+ if len(p) == 5:
+ p[0] = ast.If([(p[2], p[4])], None)
+ else:
+ p[0] = ast.If([(p[2], p[4])], p[7])
def p_suite(p):
"""suite : simple_stmt
p[0] = ast.Stmt(p[1])
else:
p[0] = ast.Stmt(p[3])
-
+
def p_stmts(p):
"""stmts : stmts stmt
p[0] = unary_ops[p[1]](p[2])
else:
p[0] = p[1]
-
+
# power: atom trailer* ['**' factor]
# trailers enables function calls. I only allow one level of calls
# so this is 'trailer'
def p_test(p):
"test : comparison"
p[0] = p[1]
-
+
# arglist: (argument ',')* (argument [',']| '*' test [',' '**' test] | '**' test)
if lexer is None:
lexer = IndentLexer(debug=1)
self.lexer = lexer
- self.parser = yacc.yacc(start="file_input_end")
+ self.parser = yacc.yacc(start="file_input_end",
+ debug=False, write_tables=False)
def parse(self, code):
self.lexer.input(code)
- result = self.parser.parse(lexer = self.lexer)
+ result = self.parser.parse(lexer = self.lexer, debug=True)
return ast.Module(None, result)
###### Code generation ######
-
+
from compiler import misc, syntax, pycodegen
class GardenSnakeCompiler(object):
return code
####### Test code #######
-
+
code = r"""
print('LET\'S TRY THIS \\OUT')
-
+
#Comment here
def x(a):
print('called with', a)
a=9
"""
-_code = r"""
+code = r"""
def x(a):
y = 5
z = 5
print('called with', a)
- return a*2
+ if a == 1:
+ print('a == 1')
+ if a * 5 == 5:
+ print('a*5 == 5')
+ return a*5
+ return a*2
+ else:
+ print('a != 1')
+ return a*6
+
+ return a
print (x(1))
+print (x(2))
"""
lexer = IndentLexer(debug=1)
# Tokenize
while True:
tok = lexer.token()
- if not tok:
+ if not tok:
break # No more input
print(tok)
+#sys.exit(0)
+
# Set up the GardenSnake run-time environment
def print_(*args):
print ("args", args)