Skip to content

Instantly share code, notes, and snippets.

@naoyamakino
Forked from ujihisa/a.py
Created September 1, 2011 00:23
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save naoyamakino/1185120 to your computer and use it in GitHub Desktop.
Save naoyamakino/1185120 to your computer and use it in GitHub Desktop.
# a = 1
# b = a + 2
# print b
program = [
('assign', 'a', ('value', 1)),
('assign', 'b', ('plus', ('refer', 'a'), ('value', 2))),
('print', ('refer', 'b')),
('variables',)]
variables = {}
def evaluate(ast):
inst = ast[0]
if inst == 'assign':
lhs = ast[1]
rhs = ast[2]
variables[lhs] = evaluate(rhs)
return False
elif inst == 'refer':
return variables[ast[1]]
elif inst == 'value':
return ast[1]
elif inst == 'plus':
arg1 = ast[1]
arg2 = ast[2]
return evaluate(arg1) + evaluate(arg2)
elif inst == 'print':
print evaluate(ast[1])
return False
elif inst == 'variables':
print variables
else:
print 'omg: ' + inst
return False
for ast in program:
evaluate(ast)
def compile(program):
memo = []
for ast in program:
memo += compile_one(ast)
return memo
def compile_one(ast):
inst = ast[0]
if inst == 'assign':
lhs = ast[1]
rhs = ast[2]
x = compile_one(rhs)
return x + [('set', lhs)]
elif inst == 'refer':
return [('get', ast[1])]
elif inst == 'value':
return [('put', ast[1])]
elif inst == 'plus':
arg1 = ast[1]
arg2 = ast[2]
return compile_one(arg1) + compile_one(arg2) + [('plus',)]
elif inst == 'print':
name = ast[1]
return compile_one(name) + [('print',)]
elif inst == 'variables': #
return [('variables',)]
else:
return 'omg: ' + inst
def execute(bytecode):
stack = []
variables = {}
for nme in bytecode:
inst = nme[0]
if inst == 'put':
stack.append(nme[1])
elif inst == 'set':
name = nme[1]
variables[name] = stack.pop()
elif inst == 'set2':
name = nme[1]
variables[name] = stack[len(stack)-1]
elif inst == 'get':
name = nme[1]
stack.append(variables[name])
elif inst == 'plus':
a = stack.pop()
b = stack.pop()
stack.append(a + b)
elif inst == 'print':
a = stack.pop()
print a
elif inst == 'variables':
print variables
def optimize(bytecode):
result = []
flag = False
for i in range(0, len(bytecode)-1):
if bytecode[i][0] == 'set' and bytecode[i+1][0] == 'get' and bytecode[i][1] == bytecode[i+1][1]:
result.append(('set2', bytecode[i][1]))
flag = True
elif flag:
flag = False
else:
result.append(bytecode[i])
if not flag:
result.append(bytecode[len(bytecode)-1])
return result
# a = 1
# b = a + 2
# print b
program = [
('assign', 'a', ('value', 1)),
('assign', 'b', ('plus', ('refer', 'a'), ('value', 2))),
('print', ('refer', 'b')),
('variables',)]
# put 1
# set a
# get a
# put 2
# plus
# set b
# get b
# print
for p in program:
print p
bytecode = compile(program)
for b in bytecode:
print b
execute(bytecode)
bytecode2 = optimize(bytecode)
execute(bytecode2)
{-# LANGUAGE OverloadedStrings #-}
import qualified Data.Text as T
import qualified Data.Text.IO as T
import qualified Data.Attoparsec.Text as P
import Control.Applicative ((<$>), (<|>), (*>), (<*))
main = do
-- content <- return "a = b + 2 + 3"
content <- return "print a + 2"
-- content <- return "variables"
case P.parseOnly parseAST content of
Right x -> print x
data AST = Assign String AST | Value Int | Plus AST AST | Refer String | Print AST | Variables
instance Show AST where
show (Assign s a) = "('assign', " ++ show s ++ ", " ++ show a ++ ")"
show (Value i) = "('value', " ++ show i ++ ")"
show (Plus a1 a2) = "('plus', " ++ show a1 ++ ", " ++ show a2 ++ ")"
show (Refer s) = "('refer', " ++ show s ++ ")"
show (Print a) = "('refer', " ++ show a ++ ")"
show Variables = "('variables',)"
parseAST :: P.Parser AST
parseAST = P.try assign <|> P.try print_ <|> P.try variables
print_ :: P.Parser AST
print_ = do
P.string "print"
P.many1 P.space
Print <$> plus
variables = P.string "variables" *> return Variables
assign :: P.Parser AST
assign = do
name <- word
P.skipSpace *> P.string "=" <* P.skipSpace
rhs <- P.try plus <|> expr
return $ Assign name rhs
plus = do
xs <- expr `P.sepBy` (P.skipSpace *> P.string "+" <* P.skipSpace)
return $ foldr1 Plus xs
expr :: P.Parser AST
expr = P.try value <|> refer
value :: P.Parser AST
value = Value . read . T.unpack <$> P.takeWhile1 (P.inClass "0-9")
refer :: P.Parser AST
refer = Refer <$> word
word :: P.Parser String
word = T.unpack <$> P.takeWhile (P.inClass "a-zA-Z_")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment