■
大学院の願書を提出
Haskell、splitすら標準ライブラリにないのか…wordsとか、あまり汎用的でないものはあるのになあ。ああ不便。
Data.HashTableによって、IO汚染というものを初めて実感しました。今までHaskellプログラムを書いていなかっただけなのだけど…
そもそもHashTableなんて使うのが悪いのだ。Data.Mapに切り替え。しかしこれでも何度もはまる。はまる原因は、引数の順序ミス。あー統一性がない!
import Data.Map as M main = do stm <- getContents let st = (concatMap splitSymbol).Main.split ':' $ concat $ lines stm in do step st [] empty step c e s = case am c e s of Nothing -> putStrLn "Terminated." Just (c, e, s) -> do putStrLn $ show c putStrLn $ show e putStrLn $ show s putStrLn "" step c e s data Stack = A Int | B Bool deriving Show am :: [String] -> [Stack] -> (Map String Stack) -> Maybe ([String], [Stack], (Map String Stack)) am ("PUSH":"-":n:c') e s = Just (c', [A $ read n] ++ e, s) am ("TRUE":c') e s = Just (c', [B True] ++ e, s) am ("FALSE":c') e s = Just (c', [B False] ++ e, s) am ("FETCH":"-":x:c') e s = Just (c', [getValue x] ++ e, s) where getValue :: String -> Stack getValue key = case M.lookup key s of Just val -> val Nothing -> A 0 am ("STORE":"-":x:c') (elm:e') s = Just (c', e', insert x elm s) am ("ADD":c') (a1:a2:e') s = arithmeticOp (+) a1 a2 c' e' s am ("MULT":c') (a1:a2:e') s = arithmeticOp (*) a1 a2 c' e' s am ("SUB":c') (a1:a2:e') s = arithmeticOp (-) a1 a2 c' e' s am ("EQ":c') (a1:a2:e') s = arith2boolOp (==) a1 a2 c' e' s am ("LE":c') (a1:a2:e') s = arith2boolOp (<=) a1 a2 c' e' s am ("AND":c') (a1:a2:e') s = booleanOp (&&) a1 a2 c' e' s am ("NEG":c') (a:e') s = booleanOp1 not a c' e' s am ("BRANCH":c') (elm:e') s = let (c1, c2, c) = splitComma c' in case elm of B True -> Just (c1 ++ c, e', s) _ -> Just (c2 ++ c, e', s) am ("LOOP":c') e s = let (c1, c2, c) = splitComma c' in Just $ (c1 ++ ["BRANCH"] ++ ["("] ++ c2 ++ ["LOOP"] ++ ["("] ++ c1 ++ [","] ++ c2 ++ [")"] ++ [","] ++ ["NOOP"] ++ [")"] ++ c, e, s) am ("NOOP":c') e s = Just $ (c', e, s) am ("COPY":c') (a:e') s = Just $ (c', [a,a] ++ e', s) am [] e s = Nothing am _ _ _ = Nothing arithmeticOp func (A a) (A b) c e s = operator $ Just (A (a `func` b), c, e, s) arithmeticOp _ _ _ _ _ _ = operator Nothing arith2boolOp func (A a) (A b) c e s = operator $ Just (B (a `func` b), c, e, s) arith2boolOp _ _ _ _ _ _ = operator Nothing booleanOp func (B a) (B b) c e s = operator $ Just (B (a `func` b), c, e, s) booleanOp _ _ _ _ _ _ = operator Nothing booleanOp1 func (B a) c e s = operator $ Just (B (func a), c, e, s) booleanOp1 _ _ _ _ _ = operator Nothing operator func = case func of Just (x, c, e, s) -> Just (c, [x] ++ e, s) Nothing -> Nothing splitComma insts = f [] insts 0 where f lhs (head:rhs) cn | head == "(" = if cn == 0 then f lhs rhs (cn+1) else f (lhs ++ [head]) rhs (cn+1) | head == ")" = f (lhs ++ [head]) rhs (cn-1) | head == "," = if cn == 1 then (lhs, fst $ g [] rhs 1, snd $ g [] rhs 1) else f (lhs ++ [head]) rhs cn | otherwise = f (lhs ++ [head]) rhs cn g lhs (head:rhs) cn | head == "(" = g (lhs ++ [head]) rhs (cn+1) | head == ")" = if cn == 1 then (lhs, rhs) else g (lhs ++ [head]) rhs (cn-1) | otherwise = g (lhs ++ [head]) rhs cn split :: Char -> String -> [String] split delim str = f "" str where f elm (c:str') | c == delim = [elm] ++ f [] str' | otherwise = f (elm ++ [c]) str' f [] [] = [] f elm [] = [elm] splitSymbol :: String -> [String] splitSymbol str = f "" str where f elm (c:str') | c == ',' || c == '(' || c == ')' || c == '-' = if elm == "" then [[c]] ++ f "" str' else [elm, [c]] ++ f "" str' | otherwise = f (elm ++ [c]) str' f [] [] = [] f elm [] = [elm]
use strict; my $stm = join '', map{chomp;$_} <>; print &cs($stm); sub ca($){ my $elm = shift; if($elm =~ /^(\d+)$/){ return "PUSH-$1"; }elsif($elm =~ /^([a-z]\d*)$/){ return "FETCH-$1"; }else{ my @elmchar = split '', $elm; my $paren = 0; for(0..$#elmchar){ $paren += paren_shift($elmchar[$_]); if($elmchar[$_] =~ /[-+*]/ && $paren == 0){ my $lhs = join '', @elmchar[0..$_-1]; my $rhs = join '', @elmchar[$_+1..$#elmchar]; if($elmchar[$_] eq '+'){ return ca($rhs) . ':' . ca($lhs) . ':ADD'; }elsif($elmchar[$_] eq '*'){ return ca($rhs) . ':' . ca($lhs) . ':MULT'; }elsif($elmchar[$_] eq '-'){ return ca($rhs) . ':' . ca($lhs) . ':SUB'; } } } if($paren == 0){ my $body; return ca($body) if(length($body = remove_paren($elm))); return ca($body) if(length($body = remove_space($elm))); } die "parse error"; } } sub cb($){ my $elm = shift; if($elm =~ /^true$/){ return "TRUE"; }elsif($elm =~ /^false$/){ return "FALSE"; }elsif($elm =~ /^!(.*)/){ return cb($1) . ':NEG'; }else{ my @elmchar = split '', $elm; my $paren = 0; for(0..$#elmchar){ $paren += paren_shift($elmchar[$_]); if($elmchar[$_] =~ /[<=&]/ && $paren == 0){ my $lhs = join '', @elmchar[0..$_-1]; my $rhs = join '', @elmchar[$_+1..$#elmchar]; if($elmchar[$_] eq '='){ return ca($rhs) . ':' . ca($lhs) . ':EQ'; }elsif($elmchar[$_].$elmchar[$_+1] eq '<='){ return ca(substr($rhs, 1)) . ':' . ca($lhs) . ':LE'; }elsif($elmchar[$_] eq '&'){ return cb($rhs) . ':' . cb($lhs) . ':AND'; } } } if($paren == 0){ my $body; return cb($body) if(length($body = remove_paren($elm))); return cb($body) if(length($body = remove_space($elm))); } die "parse error"; } } sub cs($){ my $elm = shift; my @elmchar = split '', $elm; my $paren = 0; for(0..$#elmchar){ $paren += paren_shift($elmchar[$_]); if($elmchar[$_] eq ';' && $paren == 0){ my $lhs = join '', @elmchar[0..$_-1]; my $rhs = join '', @elmchar[$_+1..$#elmchar]; return css($lhs) . ':' . cs($rhs); } } return css($elm) if($paren == 0); die "parse error"; } sub css($){ my $elm = shift; if($elm =~ /^skip$/){ return "NOOP"; }elsif($elm =~ /^([a-z]\d*)\s*:=\s*(.*)$/){ return ca($2) . ':' . "STORE-$1"; }elsif($elm =~ /^while(.*)/){ my $tmpwhile = $1; if($tmpwhile =~ /^(.*?)do(.*)$/){ return 'LOOP(' . cb($1) . ',' . cs($2) . ')'; }else{ die "parse error"; } }elsif($elm =~ /^if(.*?)then(.*)$/){ my $cond = $1; my $paren = 0; my $yetread = $2; my $alreadyread = ''; while($yetread =~ s/(.*?)(if|else)(.*)/$3/){ $alreadyread .= $1; if($2 eq 'if'){ $paren++; }elsif($2 eq 'else'){ last if($paren == 0); $paren--; } $alreadyread .= $2; } return cb($cond) . ':BRANCH(' . cs($alreadyread) . ',' . cs($yetread) . ')'; }elsif($elm =~ /^repeat(.*)/){ my $cond; my $paren = 0; my $yetread = $1; my $alreadyread = ''; while($yetread =~ s/(.*?)(repeat|until)(.*)/$3/){ $alreadyread .= $1; if($2 eq 'repeat'){ $paren++; }elsif($2 eq 'until'){ $cond = $3; last if($paren == 0); $paren--; } $alreadyread .= $2; } return cs($alreadyread) . ':LOOP(' . cb($cond) . ',' . cs($alreadyread) . ')'; }elsif($elm =~ /^for(.*?):=(.*?)to(.*?)do(.*)/){ my $tmpvar = $1; my $start = $2; my $end = $3; return cs($tmpvar . ':=' . $start) . ':LOOP(' . cb($tmpvar . '<=' . $end) . ',' . cs($4.';'.$tmpvar.':='.$tmpvar.'+1') . ')'; } my $body; return cs($body) if(length($body = remove_paren($elm))); return css($body) if(length($body = remove_space($elm))); die "parse error"; } sub paren_shift($){ my $char = shift; if($char eq '('){ return 1; }elsif($char eq ')'){ return -1; } return 0; } sub remove_paren($){ my $str = shift; if($str =~ /^\((.*)\)$/){ return $1; } return ''; } sub remove_space($){ my $str = shift; if($str =~ /^(\s*)(.+?)(\s*)$/){ return $2 if(length $1 || length $3); } return ''; }
x:=3;y:=1;while !(x=1) do (y:=y*x; x:=x-1) x:=17;y:=5;z:=0; while y<=x do (z:=z+1; x:=x-y)