summaryrefslogtreecommitdiff
path: root/examples/gfcc/compiler/CleanJVM.hs
blob: 72a0060c2468c367d8a1187d94816e463798d262 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
module Main where

import Char
import System

--- now works for programs with exactly 2 functions, main last

main :: IO ()
main = do
  jvm:src:_ <- getArgs
  s <- readFile jvm
  let cls = takeWhile (/='.') src
  let obj = cls ++ ".j"
  writeFile  obj $ boilerplate cls
  appendFile obj $ mkJVM cls s
  putStrLn $ "wrote file " ++ obj
  system $ "jasmin " ++ obj
  return () 

mkJVM :: String -> String -> String
mkJVM cls = unlines . map trans . lines where
  trans s = case words s of
    ".method":p:s:f:ns
        | take 5 f == "main_" -> ".method public static main([Ljava/lang/String;)V"   
        | otherwise  -> unwords [".method",p,s, unindex f ++ typesig ns]
    ".limit":"locals":ns -> ".limit locals " ++ show (length ns)
    "invokestatic":t:f:ns | take 8 f == "runtime/" -> 
        "invokestatic " ++ "runtime/" ++ t ++ drop 8 f ++ typesig ns 
    "invokestatic":f:ns  -> "invokestatic " ++ cls ++ "/" ++ unindex f ++ typesig ns 
    "alloc":ns           -> "; " ++ s
    t:('_':instr):[]     -> t ++ instr
    t:('_':instr):x:_    -> t ++ instr ++ " " ++ address x
    "goto":ns            -> "goto " ++ label ns
    "ifeq":ns            -> "ifeq " ++ label ns
    "label":ns           -> label ns ++ ":"
    ";":[] -> ""
    _ -> s
   where
     unindex = reverse . drop 1 . dropWhile (/= '_') . reverse
     typesig = init . map toUpper . concat
     address x = case (filter isDigit . reverse . takeWhile (/= '_') . reverse) x of
       s@(_:_) -> show $ read s - (1 :: Int)
       s -> s
     label   = init . concat

boilerplate :: String -> String
boilerplate cls = unlines [
  ".class public " ++ cls,
  ".super java/lang/Object",
  ".method public <init>()V",
  "aload_0",
  "invokenonvirtual java/lang/Object/<init>()V",
  "return",
  ".end method"
  ]