tools/pas2c.hs
changeset 7628 bc7b1d228a2c
parent 7529 058fcb451b37
child 7949 91511b219de7
child 8442 535a00ca0d35
equal deleted inserted replaced
7533:7ee319134713 7628:bc7b1d228a2c
    15 import qualified Data.Map as Map
    15 import qualified Data.Map as Map
    16 import qualified Data.Set as Set
    16 import qualified Data.Set as Set
    17 import Data.List (find)
    17 import Data.List (find)
    18 import Numeric
    18 import Numeric
    19 
    19 
    20 import PascalParser
    20 import PascalParser(pascalUnit)
    21 import PascalUnitSyntaxTree
    21 import PascalUnitSyntaxTree
    22 
    22 
    23 
    23 
    24 data InsertOption =
    24 data InsertOption =
    25     IOInsert
    25     IOInsert
       
    26     | IOInsertWithType Doc
    26     | IOLookup
    27     | IOLookup
    27     | IOLookupLast
    28     | IOLookupLast
    28     | IOLookupFunction Int
    29     | IOLookupFunction Int
    29     | IODeferred
    30     | IODeferred
    30 
    31 
    31 type Record = (String, BaseType)
    32 data Record = Record
       
    33     {
       
    34         lcaseId :: String,
       
    35         baseType :: BaseType,
       
    36         typeDecl :: Doc
       
    37     }
       
    38     deriving Show
    32 type Records = Map.Map String [Record]
    39 type Records = Map.Map String [Record]
    33 data RenderState = RenderState
    40 data RenderState = RenderState
    34     {
    41     {
    35         currentScope :: Records,
    42         currentScope :: Records,
    36         lastIdentifier :: String,
    43         lastIdentifier :: String,
    37         lastType :: BaseType,
    44         lastType :: BaseType,
       
    45         lastIdTypeDecl :: Doc,
    38         stringConsts :: [(String, String)],
    46         stringConsts :: [(String, String)],
    39         uniqCounter :: Int,
    47         uniqCounter :: Int,
    40         toMangle :: Set.Set String,
    48         toMangle :: Set.Set String,
    41         currentUnit :: String,
    49         currentUnit :: String,
    42         currentFunctionResult :: String,
    50         currentFunctionResult :: String,
    43         namespaces :: Map.Map String Records
    51         namespaces :: Map.Map String Records
    44     }
    52     }
    45 
    53 
    46 emptyState = RenderState Map.empty "" BTUnknown [] 0 Set.empty "" ""
    54 rec2Records = map (\(a, b) -> Record a b empty)
       
    55 
       
    56 emptyState = RenderState Map.empty "" BTUnknown empty [] 0 Set.empty "" ""
    47 
    57 
    48 getUniq :: State RenderState Int
    58 getUniq :: State RenderState Int
    49 getUniq = do
    59 getUniq = do
    50     i <- gets uniqCounter
    60     i <- gets uniqCounter
    51     modify(\s -> s{uniqCounter = uniqCounter s + 1})
    61     modify(\s -> s{uniqCounter = uniqCounter s + 1})
    69 escapeStr :: String -> String
    79 escapeStr :: String -> String
    70 escapeStr = foldr escapeChar []
    80 escapeStr = foldr escapeChar []
    71 
    81 
    72 escapeChar :: Char -> ShowS
    82 escapeChar :: Char -> ShowS
    73 escapeChar '"' s = "\\\"" ++ s
    83 escapeChar '"' s = "\\\"" ++ s
       
    84 escapeChar '\\' s = "\\\\" ++ s
    74 escapeChar a s = a : s
    85 escapeChar a s = a : s
    75 
    86 
    76 strInit :: String -> Doc
    87 strInit :: String -> Doc
    77 strInit a = text "STRINIT" <> parens (doubleQuotes (text $ escapeStr a))
    88 strInit a = text "STRINIT" <> parens (doubleQuotes (text $ escapeStr a))
    78 
    89 
    79 renderStringConsts :: State RenderState Doc
    90 renderStringConsts :: State RenderState Doc
    80 renderStringConsts = liftM (vcat . map (\(a, b) -> text "const string255" <+> (text a) <+> text "=" <+> strInit b <> semi))
    91 renderStringConsts = liftM (vcat . map (\(a, b) -> text "static const string255" <+> (text a) <+> text "=" <+> strInit b <> semi))
    81     $ gets stringConsts
    92     $ gets stringConsts
    82 
    93 
    83 docToLower :: Doc -> Doc
    94 docToLower :: Doc -> Doc
    84 docToLower = text . map toLower . render
    95 docToLower = text . map toLower . render
    85 
    96 
   130     toNamespace nss (System tvs) =
   141     toNamespace nss (System tvs) =
   131         currentScope $ execState f (emptyState nss)
   142         currentScope $ execState f (emptyState nss)
   132         where
   143         where
   133         f = do
   144         f = do
   134             checkDuplicateFunDecls tvs
   145             checkDuplicateFunDecls tvs
   135             mapM_ (tvar2C True) tvs
   146             mapM_ (tvar2C True False True False) tvs
       
   147     toNamespace nss (Redo tvs) = -- functions that are re-implemented, add prefix to all of them
       
   148         currentScope $ execState f (emptyState nss){currentUnit = "fpcrtl_"}
       
   149         where
       
   150         f = do
       
   151             checkDuplicateFunDecls tvs
       
   152             mapM_ (tvar2C True False True False) tvs
   136     toNamespace _ (Program {}) = Map.empty
   153     toNamespace _ (Program {}) = Map.empty
   137     toNamespace nss (Unit (Identifier i _) interface _ _ _) =
   154     toNamespace nss (Unit (Identifier i _) interface _ _ _) =
   138         currentScope $ execState (interface2C interface) (emptyState nss){currentUnit = map toLower i ++ "_"}
   155         currentScope $ execState (interface2C interface True) (emptyState nss){currentUnit = map toLower i ++ "_"}
   139 
   156 
   140 
   157 
   141 withState' :: (RenderState -> RenderState) -> State RenderState a -> State RenderState a
   158 withState' :: (RenderState -> RenderState) -> State RenderState a -> State RenderState a
   142 withState' f sf = do
   159 withState' f sf = do
   143     st <- liftM f get
   160     st <- liftM f get
   147         , uniqCounter = uniqCounter s
   164         , uniqCounter = uniqCounter s
   148         , stringConsts = stringConsts s
   165         , stringConsts = stringConsts s
   149         })
   166         })
   150     return a
   167     return a
   151 
   168 
   152 withLastIdNamespace :: State RenderState Doc -> State RenderState Doc
       
   153 withLastIdNamespace f = do
   169 withLastIdNamespace f = do
   154     li <- gets lastIdentifier
   170     li <- gets lastIdentifier
   155     nss <- gets namespaces
   171     nss <- gets namespaces
   156     withState' (\st -> st{currentScope = fromMaybe Map.empty $ Map.lookup li (namespaces st)}) f
   172     withState' (\st -> st{currentScope = fromMaybe Map.empty $ Map.lookup li (namespaces st)}) f
   157 
   173 
   158 withRecordNamespace :: String -> [(String, BaseType)] -> State RenderState Doc -> State RenderState Doc
   174 withRecordNamespace :: String -> [Record] -> State RenderState Doc -> State RenderState Doc
   159 withRecordNamespace _ [] = error "withRecordNamespace: empty record"
   175 withRecordNamespace _ [] = error "withRecordNamespace: empty record"
   160 withRecordNamespace prefix recs = withState' f
   176 withRecordNamespace prefix recs = withState' f
   161     where
   177     where
   162         f st = st{currentScope = Map.unionWith un records (currentScope st), currentUnit = ""}
   178         f st = st{currentScope = Map.unionWith un records (currentScope st), currentUnit = ""}
   163         records = Map.fromList $ map (\(a, b) -> (map toLower a, [(prefix ++ a, b)])) recs
   179         records = Map.fromList $ map (\(Record a b d) -> (map toLower a, [Record (prefix ++ a) b d])) recs
   164         un [a] b = a : b
   180         un [a] b = a : b
   165 
   181 
   166 toCFiles :: Map.Map String Records -> (String, PascalUnit) -> IO ()
   182 toCFiles :: Map.Map String Records -> (String, PascalUnit) -> IO ()
   167 toCFiles _ (_, System _) = return ()
   183 toCFiles _ (_, System _) = return ()
       
   184 toCFiles _ (_, Redo _) = return ()
   168 toCFiles ns p@(fn, pu) = do
   185 toCFiles ns p@(fn, pu) = do
   169     hPutStrLn stdout $ "Rendering '" ++ fn ++ "'..."
   186     hPutStrLn stdout $ "Rendering '" ++ fn ++ "'..."
   170     toCFiles' p
   187     toCFiles' p
   171     where
   188     where
   172     toCFiles' (fn, p@(Program {})) = writeFile (fn ++ ".c") $ (render2C initialState . pascal2C) p
   189     toCFiles' (fn, p@(Program {})) = writeFile (fn ++ ".c") $ "#include \"fpcrtl.h\"\n" ++ (render2C initialState . pascal2C) p
   173     toCFiles' (fn, (Unit unitId@(Identifier i _) interface implementation _ _)) = do
   190     toCFiles' (fn, (Unit unitId@(Identifier i _) interface implementation _ _)) = do
   174         let (a, s) = runState (id2C IOInsert (setBaseType BTUnit unitId) >> interface2C interface) initialState{currentUnit = map toLower i ++ "_"}
   191         let (a, s) = runState (id2C IOInsert (setBaseType BTUnit unitId) >> interface2C interface True) initialState{currentUnit = map toLower i ++ "_"}
       
   192             (a', s') = runState (id2C IOInsert (setBaseType BTUnit unitId) >> interface2C interface False) initialState{currentUnit = map toLower i ++ "_"}
   175         writeFile (fn ++ ".h") $ "#pragma once\n\n#include \"pas2c.h\"\n\n" ++ (render (a $+$ text ""))
   193         writeFile (fn ++ ".h") $ "#pragma once\n\n#include \"pas2c.h\"\n\n" ++ (render (a $+$ text ""))
   176         writeFile (fn ++ ".c") $ "#include \"" ++ fn ++ ".h\"\n" ++ (render2C s . implementation2C) implementation
   194         writeFile (fn ++ ".c") $ "#include \"fpcrtl.h\"\n\n#include \"" ++ fn ++ ".h\"\n" ++ render (a' $+$ text "") ++ (render2C s . implementation2C) implementation
   177     initialState = emptyState ns
   195     initialState = emptyState ns
   178 
   196 
   179     render2C :: RenderState -> State RenderState Doc -> String
   197     render2C :: RenderState -> State RenderState Doc -> String
   180     render2C a = render . ($+$ empty) . flip evalState a
   198     render2C a = render . ($+$ empty) . flip evalState a
   181 
   199 
       
   200 
   182 usesFiles :: PascalUnit -> [String]
   201 usesFiles :: PascalUnit -> [String]
   183 usesFiles (Program _ (Implementation uses _) _) = "pas2cSystem" : uses2List uses
   202 usesFiles (Program _ (Implementation uses _) _) = ["pas2cSystem", "pas2cRedo"] ++ uses2List uses
   184 usesFiles (Unit _ (Interface uses1 _) (Implementation uses2 _) _ _) = "pas2cSystem" : uses2List uses1 ++ uses2List uses2
   203 usesFiles (Unit _ (Interface uses1 _) (Implementation uses2 _) _ _) = ["pas2cSystem", "pas2cRedo"] ++ uses2List uses1 ++ uses2List uses2
   185 usesFiles (System {}) = []
   204 usesFiles (System {}) = []
   186 
   205 usesFiles (Redo {}) = []
   187 
   206 
   188 pascal2C :: PascalUnit -> State RenderState Doc
   207 pascal2C :: PascalUnit -> State RenderState Doc
   189 pascal2C (Unit _ interface implementation init fin) =
   208 pascal2C (Unit _ interface implementation init fin) =
   190     liftM2 ($+$) (interface2C interface) (implementation2C implementation)
   209     liftM2 ($+$) (interface2C interface True) (implementation2C implementation)
   191 
   210 
   192 pascal2C (Program _ implementation mainFunction) = do
   211 pascal2C (Program _ implementation mainFunction) = do
   193     impl <- implementation2C implementation
   212     impl <- implementation2C implementation
   194     [main] <- tvar2C True
   213     [main] <- tvar2C True False True True (FunctionDeclaration (Identifier "main" BTInt) False (SimpleType $ Identifier "int" BTInt) [VarDeclaration False False ([Identifier "argc" BTInt], SimpleType (Identifier "Integer" BTInt)) Nothing, VarDeclaration False False ([Identifier "argv" BTUnknown], SimpleType (Identifier "PPChar" BTUnknown)) Nothing] (Just (TypesAndVars [], mainFunction)))
   195         (FunctionDeclaration (Identifier "main" BTInt) (SimpleType $ Identifier "int" BTInt) [] (Just (TypesAndVars [], mainFunction)))
       
   196     return $ impl $+$ main
   214     return $ impl $+$ main
   197 
   215 
   198 
   216 
   199 
   217 -- the second bool indicates whether do normal interface translation or generate variable declarations
   200 interface2C :: Interface -> State RenderState Doc
   218 -- that will be inserted into implementation files
   201 interface2C (Interface uses tvars) = do
   219 interface2C :: Interface -> Bool -> State RenderState Doc
       
   220 interface2C (Interface uses tvars) True = do
   202     u <- uses2C uses
   221     u <- uses2C uses
   203     tv <- typesAndVars2C True tvars
   222     tv <- typesAndVars2C True True True tvars
   204     r <- renderStringConsts
   223     r <- renderStringConsts
   205     return (u $+$ r $+$ tv)
   224     return (u $+$ r $+$ tv)
       
   225 interface2C (Interface uses tvars) False = do
       
   226     u <- uses2C uses
       
   227     tv <- typesAndVars2C True False False tvars
       
   228     r <- renderStringConsts
       
   229     return tv
   206 
   230 
   207 implementation2C :: Implementation -> State RenderState Doc
   231 implementation2C :: Implementation -> State RenderState Doc
   208 implementation2C (Implementation uses tvars) = do
   232 implementation2C (Implementation uses tvars) = do
   209     u <- uses2C uses
   233     u <- uses2C uses
   210     tv <- typesAndVars2C True tvars
   234     tv <- typesAndVars2C True False True tvars
   211     r <- renderStringConsts
   235     r <- renderStringConsts
   212     return (u $+$ r $+$ tv)
   236     return (u $+$ r $+$ tv)
   213 
   237 
   214 checkDuplicateFunDecls :: [TypeVarDeclaration] -> State RenderState ()
   238 checkDuplicateFunDecls :: [TypeVarDeclaration] -> State RenderState ()
   215 checkDuplicateFunDecls tvs =
   239 checkDuplicateFunDecls tvs =
   216     modify $ \s -> s{toMangle = Map.keysSet . Map.filter (> 1) . foldr ins initMap $ tvs}
   240     modify $ \s -> s{toMangle = Map.keysSet . Map.filter (> 1) . foldr ins initMap $ tvs}
   217     where
   241     where
   218         initMap = Map.empty
   242         initMap = Map.empty
   219         --initMap = Map.fromList [("reset", 2)]
   243         --initMap = Map.fromList [("reset", 2)]
   220         ins (FunctionDeclaration (Identifier i _) _ _ _) m = Map.insertWith (+) (map toLower i) 1 m
   244         ins (FunctionDeclaration (Identifier i _) _ _ _ _) m = Map.insertWith (+) (map toLower i) 1 m
   221         ins _ m = m
   245         ins _ m = m
   222 
   246 
   223 typesAndVars2C :: Bool -> TypesAndVars -> State RenderState Doc
   247 -- the second bool indicates whether declare variable as extern or not
   224 typesAndVars2C b (TypesAndVars ts) = do
   248 -- the third bool indicates whether include types or not
       
   249 
       
   250 typesAndVars2C :: Bool -> Bool -> Bool -> TypesAndVars -> State RenderState Doc
       
   251 typesAndVars2C b externVar includeType(TypesAndVars ts) = do
   225     checkDuplicateFunDecls ts
   252     checkDuplicateFunDecls ts
   226     liftM (vcat . map (<> semi) . concat) $ mapM (tvar2C b) ts
   253     liftM (vcat . map (<> semi) . concat) $ mapM (tvar2C b externVar includeType False) ts
   227 
   254 
   228 setBaseType :: BaseType -> Identifier -> Identifier
   255 setBaseType :: BaseType -> Identifier -> Identifier
   229 setBaseType bt (Identifier i _) = Identifier i bt
   256 setBaseType bt (Identifier i _) = Identifier i bt
   230 
   257 
   231 uses2C :: Uses -> State RenderState Doc
   258 uses2C :: Uses -> State RenderState Doc
   232 uses2C uses@(Uses unitIds) = do
   259 uses2C uses@(Uses unitIds) = do
       
   260 
   233     mapM_ injectNamespace (Identifier "pas2cSystem" undefined : unitIds)
   261     mapM_ injectNamespace (Identifier "pas2cSystem" undefined : unitIds)
       
   262     mapM_ injectNamespace (Identifier "pas2cRedo" undefined : unitIds)
   234     mapM_ (id2C IOInsert . setBaseType BTUnit) unitIds
   263     mapM_ (id2C IOInsert . setBaseType BTUnit) unitIds
   235     return $ vcat . map (\i -> text $ "#include \"" ++ i ++ ".h\"") $ uses2List uses
   264     return $ vcat . map (\i -> text $ "#include \"" ++ i ++ ".h\"") $ uses2List uses
   236     where
   265     where
   237     injectNamespace (Identifier i _) = do
   266     injectNamespace (Identifier i _) = do
   238         getNS <- gets (flip Map.lookup . namespaces)
   267         getNS <- gets (flip Map.lookup . namespaces)
   240 
   269 
   241 uses2List :: Uses -> [String]
   270 uses2List :: Uses -> [String]
   242 uses2List (Uses ids) = map (\(Identifier i _) -> i) ids
   271 uses2List (Uses ids) = map (\(Identifier i _) -> i) ids
   243 
   272 
   244 
   273 
       
   274 setLastIdValues vv = (\s -> s{lastType = baseType vv, lastIdentifier = lcaseId vv, lastIdTypeDecl = typeDecl vv})
       
   275 
   245 id2C :: InsertOption -> Identifier -> State RenderState Doc
   276 id2C :: InsertOption -> Identifier -> State RenderState Doc
   246 id2C IOInsert (Identifier i t) = do
   277 id2C IOInsert i = id2C (IOInsertWithType empty) i
       
   278 id2C (IOInsertWithType d) (Identifier i t) = do
   247     ns <- gets currentScope
   279     ns <- gets currentScope
   248     tom <- gets (Set.member n . toMangle)
   280     tom <- gets (Set.member n . toMangle)
   249     cu <- gets currentUnit
   281     cu <- gets currentUnit
   250     let (i', t') = case (t, tom) of
   282     let (i', t') = case (t, tom) of
   251             (BTFunction _ p _, True) -> (cu ++ i ++ ('_' : show p), t)
   283             (BTFunction _ p _, True) -> (cu ++ i ++ ('_' : show p), t)
   252             (BTFunction _ _ _, _) -> (cu ++ i, t)
   284             (BTFunction _ _ _, _) -> (cu ++ i, t)
   253             (BTVarParam t', _) -> ('(' : '*' : i ++ ")" , t')
   285             (BTVarParam t', _) -> ('(' : '*' : i ++ ")" , t')
   254             _ -> (i, t)
   286             _ -> (i, t)
   255     modify (\s -> s{currentScope = Map.insertWith (++) n [(i', t')] (currentScope s), lastIdentifier = n})
   287     modify (\s -> s{currentScope = Map.insertWith (++) n [Record i' t' d] (currentScope s), lastIdentifier = n})
   256     return $ text i'
   288     return $ text i'
   257     where
   289     where
   258         n = map toLower i
   290         n = map toLower i
       
   291 
   259 id2C IOLookup i = id2CLookup head i
   292 id2C IOLookup i = id2CLookup head i
   260 id2C IOLookupLast i = id2CLookup last i
   293 id2C IOLookupLast i = id2CLookup last i
   261 id2C (IOLookupFunction params) (Identifier i t) = do
   294 id2C (IOLookupFunction params) (Identifier i t) = do
   262     let i' = map toLower i
   295     let i' = map toLower i
   263     v <- gets $ Map.lookup i' . currentScope
   296     v <- gets $ Map.lookup i' . currentScope
   264     lt <- gets lastType
   297     lt <- gets lastType
   265     if isNothing v then
   298     if isNothing v then
   266         error $ "Not defined: '" ++ i' ++ "'\n" ++ show lt ++ "\nwith num of params = " ++ show params ++ "\n" ++ show v
   299         error $ "Not defined: '" ++ i' ++ "'\n" ++ show lt ++ "\nwith num of params = " ++ show params ++ "\n" ++ show v
   267         else
   300         else
   268         let vv = fromMaybe (head $ fromJust v) . find checkParam $ fromJust v in
   301         let vv = fromMaybe (head $ fromJust v) . find checkParam $ fromJust v in
   269             modify (\s -> s{lastType = snd vv, lastIdentifier = fst vv}) >> (return . text . fst $ vv)
   302             modify (setLastIdValues vv) >> (return . text . lcaseId $ vv)
   270     where
   303     where
   271         checkParam (_, BTFunction _ p _) = p == params
   304         checkParam (Record _ (BTFunction _ p _) _) = p == params
   272         checkParam _ = False
   305         checkParam _ = False
   273 id2C IODeferred (Identifier i t) = do
   306 id2C IODeferred (Identifier i t) = do
   274     let i' = map toLower i
   307     let i' = map toLower i
   275     v <- gets $ Map.lookup i' . currentScope
   308     v <- gets $ Map.lookup i' . currentScope
   276     if (isNothing v) then
   309     if (isNothing v) then
   277         modify (\s -> s{lastType = BTUnknown, lastIdentifier = i}) >> return (text i)
   310         modify (\s -> s{lastType = BTUnknown, lastIdentifier = i}) >> return (text i)
   278         else
   311         else
   279         let vv = head $ fromJust v in modify (\s -> s{lastType = snd vv, lastIdentifier = fst vv}) >> (return . text . fst $ vv)
   312         let vv = head $ fromJust v in modify (setLastIdValues vv) >> (return . text . lcaseId $ vv)
   280 
   313 
   281 id2CLookup :: ([Record] -> Record) -> Identifier -> State RenderState Doc
   314 id2CLookup :: ([Record] -> Record) -> Identifier -> State RenderState Doc
   282 id2CLookup f (Identifier i _) = do
   315 id2CLookup f (Identifier i t) = do
   283     let i' = map toLower i
   316     let i' = map toLower i
   284     v <- gets $ Map.lookup i' . currentScope
   317     v <- gets $ Map.lookup i' . currentScope
   285     lt <- gets lastType
   318     lt <- gets lastType
   286     if isNothing v then
   319     if isNothing v then
   287         error $ "Not defined: '" ++ i' ++ "'\n" ++ show lt
   320         error $ "Not defined: '" ++ i' ++ "'\n" ++ show lt
   288         else
   321         else
   289         let vv = f $ fromJust v in modify (\s -> s{lastType = snd vv, lastIdentifier = fst vv}) >> (return . text . fst $ vv)
   322         let vv = f $ fromJust v in modify (setLastIdValues vv) >> (return . text . lcaseId $ vv)
   290 
   323 
   291 
   324 
   292 id2CTyped :: TypeDecl -> Identifier -> State RenderState Doc
   325 id2CTyped :: TypeDecl -> Identifier -> State RenderState Doc
   293 id2CTyped t (Identifier i _) = do
   326 id2CTyped = id2CTyped2 Nothing
       
   327 
       
   328 id2CTyped2 :: Maybe Doc -> TypeDecl -> Identifier -> State RenderState Doc
       
   329 id2CTyped2 md t (Identifier i _) = do
   294     tb <- resolveType t
   330     tb <- resolveType t
   295     case (t, tb) of
   331     case (t, tb) of
   296         (_, BTUnknown) -> do
   332         (_, BTUnknown) -> do
   297             error $ "id2CTyped: type BTUnknown for " ++ show i ++ "\ntype: " ++ show t
   333             error $ "id2CTyped: type BTUnknown for " ++ show i ++ "\ntype: " ++ show t
   298         (SimpleType {}, BTRecord _ r) -> do
   334         (SimpleType {}, BTRecord _ r) -> do
   299             ts <- type2C t
   335             ts <- type2C t
   300             id2C IOInsert (Identifier i (BTRecord (render $ ts empty) r))
   336             id2C (IOInsertWithType $ ts empty) (Identifier i (BTRecord (render $ ts empty) r))
   301         (_, BTRecord _ r) -> do
   337         (_, BTRecord _ r) -> do
   302             ts <- type2C t
   338             ts <- type2C t
   303             id2C IOInsert (Identifier i (BTRecord i r))
   339             id2C (IOInsertWithType $ ts empty) (Identifier i (BTRecord i r))
   304         _ -> id2C IOInsert (Identifier i tb)
   340         _ -> case md of
   305 
   341                 Nothing -> id2C IOInsert (Identifier i tb)
       
   342                 Just ts -> id2C (IOInsertWithType ts) (Identifier i tb)
   306 
   343 
   307 
   344 
   308 resolveType :: TypeDecl -> State RenderState BaseType
   345 resolveType :: TypeDecl -> State RenderState BaseType
   309 resolveType st@(SimpleType (Identifier i _)) = do
   346 resolveType st@(SimpleType (Identifier i _)) = do
   310     let i' = map toLower i
   347     let i' = map toLower i
   311     v <- gets $ Map.lookup i' . currentScope
   348     v <- gets $ Map.lookup i' . currentScope
   312     if isJust v then return . snd . head $ fromJust v else return $ f i'
   349     if isJust v then return . baseType . head $ fromJust v else return $ f i'
   313     where
   350     where
   314     f "integer" = BTInt
   351     f "integer" = BTInt
   315     f "pointer" = BTPointerTo BTVoid
   352     f "pointer" = BTPointerTo BTVoid
   316     f "boolean" = BTBool
   353     f "boolean" = BTBool
   317     f "float" = BTFloat
   354     f "float" = BTFloat
   350 
   387 
   351 resolve :: String -> BaseType -> State RenderState BaseType
   388 resolve :: String -> BaseType -> State RenderState BaseType
   352 resolve s (BTUnresolved t) = do
   389 resolve s (BTUnresolved t) = do
   353     v <- gets $ Map.lookup t . currentScope
   390     v <- gets $ Map.lookup t . currentScope
   354     if isJust v then
   391     if isJust v then
   355         resolve s . snd . head . fromJust $ v
   392         resolve s . baseType . head . fromJust $ v
   356         else
   393         else
   357         error $ "Unknown type " ++ show t ++ "\n" ++ s
   394         error $ "Unknown type " ++ show t ++ "\n" ++ s
   358 resolve _ t = return t
   395 resolve _ t = return t
   359 
   396 
   360 fromPointer :: String -> BaseType -> State RenderState BaseType
   397 fromPointer :: String -> BaseType -> State RenderState BaseType
   361 fromPointer s (BTPointerTo t) = resolve s t
   398 fromPointer s (BTPointerTo t) = resolve s t
   362 fromPointer s t = do
   399 fromPointer s t = do
   363     error $ "Dereferencing from non-pointer type " ++ show t ++ "\n" ++ s
   400     error $ "Dereferencing from non-pointer type " ++ show t ++ "\n" ++ s
   364 
   401 
   365 
   402 
   366 functionParams2C params = liftM (hcat . punctuate comma . concat) $ mapM (tvar2C False) params
   403 functionParams2C params = liftM (hcat . punctuate comma . concat) $ mapM (tvar2C False False True True) params
   367 
   404 
   368 numberOfDeclarations :: [TypeVarDeclaration] -> Int
   405 numberOfDeclarations :: [TypeVarDeclaration] -> Int
   369 numberOfDeclarations = sum . map cnt
   406 numberOfDeclarations = sum . map cnt
   370     where
   407     where
   371         cnt (VarDeclaration _ _ (ids, _) _) = length ids
   408         cnt (VarDeclaration _ _ (ids, _) _) = length ids
   390         abc = hcat . punctuate comma . map (char . fst) $ ps
   427         abc = hcat . punctuate comma . map (char . fst) $ ps
   391         cparams = hcat . punctuate comma . map (\(c, v) -> if v then char '&' <> parens (char c) else char c) $ ps
   428         cparams = hcat . punctuate comma . map (\(c, v) -> if v then char '&' <> parens (char c) else char c) $ ps
   392         ps = zip ['a'..] (toIsVarList params)
   429         ps = zip ['a'..] (toIsVarList params)
   393 
   430 
   394 fun2C :: Bool -> String -> TypeVarDeclaration -> State RenderState [Doc]
   431 fun2C :: Bool -> String -> TypeVarDeclaration -> State RenderState [Doc]
   395 fun2C _ _ (FunctionDeclaration name returnType params Nothing) = do
   432 fun2C _ _ (FunctionDeclaration name inline returnType params Nothing) = do
   396     t <- type2C returnType
   433     t <- type2C returnType
   397     t'<- gets lastType
   434     t'<- gets lastType
   398     p <- withState' id $ functionParams2C params
   435     p <- withState' id $ functionParams2C params
   399     n <- liftM render . id2C IOInsert $ setBaseType (BTFunction hasVars (numberOfDeclarations params) t') name
   436     n <- liftM render . id2C IOInsert $ setBaseType (BTFunction hasVars (numberOfDeclarations params) t') name
       
   437     let decor = if inline then text "inline" else empty
   400     if hasVars then
   438     if hasVars then
   401         return [funWithVarsToDefine n params $+$ t empty <+> text (n ++ "__vars") <> parens p]
   439         return [funWithVarsToDefine n params $+$ decor <+> t empty <+> text (n ++ "__vars") <> parens p]
   402         else
   440         else
   403         return [t empty <+> text n <> parens p]
   441         return [decor <+> t empty <+> text n <> parens p]
   404     where
   442     where
   405         hasVars = hasPassByReference params
   443         hasVars = hasPassByReference params
   406 
   444 
   407 
   445 
   408 fun2C True rv (FunctionDeclaration name@(Identifier i _) returnType params (Just (tvars, phrase))) = do
   446 fun2C True rv (FunctionDeclaration name@(Identifier i _) inline returnType params (Just (tvars, phrase))) = do
   409     let res = docToLower $ text rv <> text "_result"
   447     let res = docToLower $ text rv <> text "_result"
   410     t <- type2C returnType
   448     t <- type2C returnType
   411     t'<- gets lastType
   449     t'<- gets lastType
   412 
   450 
   413     notDeclared <- liftM isNothing . gets $ Map.lookup (map toLower i) . currentScope
   451     notDeclared <- liftM isNothing . gets $ Map.lookup (map toLower i) . currentScope
   416 
   454 
   417     let isVoid = case returnType of
   455     let isVoid = case returnType of
   418             VoidType -> True
   456             VoidType -> True
   419             _ -> False
   457             _ -> False
   420 
   458 
   421     (p, ph) <- withState' (\st -> st{currentScope = Map.insertWith un (map toLower rv) [(render res, t')] $ currentScope st
   459     (p, ph) <- withState' (\st -> st{currentScope = Map.insertWith un (map toLower rv) [Record (render res) t' empty] $ currentScope st
   422             , currentFunctionResult = if isVoid then [] else render res}) $ do
   460             , currentFunctionResult = if isVoid then [] else render res}) $ do
   423         p <- functionParams2C params
   461         p <- functionParams2C params
   424         ph <- liftM2 ($+$) (typesAndVars2C False tvars) (phrase2C' phrase)
   462         ph <- liftM2 ($+$) (typesAndVars2C False False True tvars) (phrase2C' phrase)
   425         return (p, ph)
   463         return (p, ph)
   426 
   464 
   427     let phrasesBlock = if isVoid then ph else t empty <+> res <> semi $+$ ph $+$ text "return" <+> res <> semi
   465     let phrasesBlock = if isVoid then ph else t empty <+> res <> semi $+$ ph $+$ text "return" <+> res <> semi
   428 
   466     let define = if hasVars then text "#ifndef" <+> text n $+$ funWithVarsToDefine n params $+$ text "#endif" else empty
   429     return [(if notDeclared && hasVars then funWithVarsToDefine n params else empty) $+$
   467     let decor = if inline then text "inline" else empty
   430         t empty <+> text (if hasVars then n ++ "__vars" else n) <> parens p
   468     return [
       
   469         define
       
   470         $+$
       
   471         --(if notDeclared && hasVars then funWithVarsToDefine n params else empty) $+$
       
   472         decor <+> t empty <+> text (if hasVars then n ++ "__vars" else n) <> parens p
   431         $+$
   473         $+$
   432         text "{"
   474         text "{"
   433         $+$
   475         $+$
   434         nest 4 phrasesBlock
   476         nest 4 phrasesBlock
   435         $+$
   477         $+$
   438     phrase2C' (Phrases p) = liftM vcat $ mapM phrase2C p
   480     phrase2C' (Phrases p) = liftM vcat $ mapM phrase2C p
   439     phrase2C' p = phrase2C p
   481     phrase2C' p = phrase2C p
   440     un [a] b = a : b
   482     un [a] b = a : b
   441     hasVars = hasPassByReference params
   483     hasVars = hasPassByReference params
   442 
   484 
   443 fun2C False _ (FunctionDeclaration (Identifier name _) _ _ _) = error $ "nested functions not allowed: " ++ name
   485 fun2C False _ (FunctionDeclaration (Identifier name _) _ _ _ _) = error $ "nested functions not allowed: " ++ name
   444 fun2C _ tv _ = error $ "fun2C: I don't render " ++ show tv
   486 fun2C _ tv _ = error $ "fun2C: I don't render " ++ show tv
   445 
   487 
   446 tvar2C :: Bool -> TypeVarDeclaration -> State RenderState [Doc]
   488 -- the second bool indicates whether declare variable as extern or not
   447 tvar2C b f@(FunctionDeclaration (Identifier name _) _ _ _) =
   489 -- the third bool indicates whether include types or not
   448     fun2C b name f
   490 -- the fourth bool indicates whether ignore initialization or not (basically for dynamic arrays since we cannot do initialization in function params)
   449 tvar2C _ td@(TypeDeclaration i' t) = do
   491 tvar2C :: Bool -> Bool -> Bool -> Bool -> TypeVarDeclaration -> State RenderState [Doc]
       
   492 tvar2C b _ includeType _ f@(FunctionDeclaration (Identifier name _) _ _ _ _) = do
       
   493     t <- fun2C b name f
       
   494     if includeType then return t else return []
       
   495 tvar2C _ _ includeType _ td@(TypeDeclaration i' t) = do
   450     i <- id2CTyped t i'
   496     i <- id2CTyped t i'
   451     tp <- type2C t
   497     tp <- type2C t
   452     return [text "typedef" <+> tp i]
   498     return $ if includeType then [text "typedef" <+> tp i] else []
   453 
   499 
   454 tvar2C _ (VarDeclaration True _ (ids, t) Nothing) = do
   500 tvar2C _ _ _ _ (VarDeclaration True _ (ids, t) Nothing) = do
   455     t' <- liftM ((empty <+>) . ) $ type2C t
   501     t' <- liftM ((empty <+>) . ) $ type2C t
   456     liftM (map(\i -> t' i)) $ mapM (id2CTyped (VarParamType t)) ids
   502     liftM (map(\i -> t' i)) $ mapM (id2CTyped2 (Just $ t' empty) (VarParamType t)) ids
   457 
   503 
   458 tvar2C _ (VarDeclaration _ isConst (ids, t) mInitExpr) = do
   504 tvar2C _ externVar includeType ignoreInit (VarDeclaration _ isConst (ids, t) mInitExpr) = do
   459     t' <- liftM (((if isConst then text "const" else empty) <+>) . ) $ type2C t
   505     t' <- liftM (((if isConst then text "static const" else if externVar 
       
   506                                                                 then text "extern"
       
   507                                                                 else empty)
       
   508                    <+>) . ) $ type2C t
   460     ie <- initExpr mInitExpr
   509     ie <- initExpr mInitExpr
   461     lt <- gets lastType
   510     lt <- gets lastType
   462     case (isConst, lt, ids, mInitExpr) of
   511     case (isConst, lt, ids, mInitExpr) of
   463          (True, BTInt, [i], Just _) -> do
   512          (True, BTInt, [i], Just _) -> do
   464              i' <- id2CTyped t i
   513              i' <- id2CTyped t i
   465              return [text "enum" <> braces (i' <+> ie)]
   514              return $ if includeType then [text "enum" <> braces (i' <+> ie)] else []
   466          (True, BTFloat, [i], Just e) -> do
   515          (True, BTFloat, [i], Just e) -> do
   467              i' <- id2CTyped t i
   516              i' <- id2CTyped t i
   468              ie <- initExpr2C e
   517              ie <- initExpr2C e
   469              return [text "#define" <+> i' <+> parens ie <> text "\n"]
   518              return $ if includeType then [text "#define" <+> i' <+> parens ie <> text "\n"] else []
   470          (_, BTFunction{}, _, Nothing) -> liftM (map(\i -> t' i)) $ mapM (id2CTyped t) ids
   519          (_, BTFunction{}, _, Nothing) -> liftM (map(\i -> t' i)) $ mapM (id2CTyped t) ids
   471          _ -> liftM (map(\i -> t' i <+> ie)) $ mapM (id2CTyped t) ids
   520          (_, BTArray r _ _, [i], _) -> do
       
   521             i' <- id2CTyped t i
       
   522             ie' <- return $ case (r, mInitExpr, ignoreInit) of
       
   523                 (RangeInfinite, Nothing, False) -> text "= NULL" -- force dynamic array to be initialized as NULL if not initialized at all
       
   524                 (_, _, _) -> ie
       
   525             result <- liftM (map(\i -> varDeclDecision isConst includeType (t' i) ie')) $ mapM (id2CTyped t) ids           
       
   526             case (r, ignoreInit) of
       
   527                 (RangeInfinite, False) -> 
       
   528                     -- if the array is dynamic, add dimension info to it
       
   529                     return $ [dimDecl] ++ result
       
   530                     where 
       
   531                         arrayDimStr = show $ arrayDimension t
       
   532                         arrayDimInitExp = text ("={" ++ ".dim = " ++ arrayDimStr ++ ", .a = {0, 0, 0, 0}}")
       
   533                         dimDecl = varDeclDecision isConst includeType (text "fpcrtl_dimension_t" <+>  i' <> text "_dimension_info") arrayDimInitExp
       
   534                     
       
   535                 (_, _) -> return result
       
   536             
       
   537          _ -> liftM (map(\i -> varDeclDecision isConst includeType (t' i) ie)) $ mapM (id2CTyped2 (Just $ t' empty) t) ids
   472     where
   538     where
   473     initExpr Nothing = return $ empty
   539     initExpr Nothing = return $ empty
   474     initExpr (Just e) = liftM (text "=" <+>) (initExpr2C e)
   540     initExpr (Just e) = liftM (text "=" <+>) (initExpr2C e)
   475 
   541     varDeclDecision True True varStr expStr = varStr <+> expStr
   476 tvar2C f (OperatorDeclaration op (Identifier i _) ret params body) = do
   542     varDeclDecision False True varStr expStr = if externVar then varStr else varStr <+> expStr
       
   543     varDeclDecision False False varStr expStr = varStr <+> expStr
       
   544     varDeclDecision True False varStr expStr = empty
       
   545     arrayDimension a = case a of
       
   546         ArrayDecl Nothing t -> let a = arrayDimension t in if a > 3 then error "Dynamic array with dimension > 4 is not supported." else 1 + arrayDimension t
       
   547         ArrayDecl _ _ -> error "Mixed dynamic array and static array are not supported."
       
   548         _ -> 0
       
   549 
       
   550 tvar2C f _ _ _ (OperatorDeclaration op (Identifier i _) inline ret params body) = do
   477     r <- op2CTyped op (extractTypes params)
   551     r <- op2CTyped op (extractTypes params)
   478     fun2C f i (FunctionDeclaration r ret params body)
   552     fun2C f i (FunctionDeclaration r inline ret params body)
   479 
   553 
   480 
   554 
   481 op2CTyped :: String -> [TypeDecl] -> State RenderState Identifier
   555 op2CTyped :: String -> [TypeDecl] -> State RenderState Identifier
   482 op2CTyped op t = do
   556 op2CTyped op t = do
   483     t' <- liftM (render . hcat . punctuate (char '_') . map (\t -> t empty)) $ mapM type2C t
   557     t' <- liftM (render . hcat . punctuate (char '_') . map (\t -> t empty)) $ mapM type2C t
   487     opStr = case op of
   561     opStr = case op of
   488                     "+" -> "add"
   562                     "+" -> "add"
   489                     "-" -> "sub"
   563                     "-" -> "sub"
   490                     "*" -> "mul"
   564                     "*" -> "mul"
   491                     "/" -> "div"
   565                     "/" -> "div"
       
   566                     "/(float)" -> "div"
   492                     "=" -> "eq"
   567                     "=" -> "eq"
   493                     "<" -> "lt"
   568                     "<" -> "lt"
   494                     ">" -> "gt"
   569                     ">" -> "gt"
   495                     "<>" -> "neq"
   570                     "<>" -> "neq"
   496                     _ -> error $ "op2CTyped: unknown op '" ++ op ++ "'"
   571                     _ -> error $ "op2CTyped: unknown op '" ++ op ++ "'"
   589              BTRecord _ _ -> return $ \a -> text "struct __" <> i' <+> text "*" <+> a
   664              BTRecord _ _ -> return $ \a -> text "struct __" <> i' <+> text "*" <+> a
   590              BTUnknown -> return $ \a -> text "struct __" <> i' <+> text "*" <+> a
   665              BTUnknown -> return $ \a -> text "struct __" <> i' <+> text "*" <+> a
   591              _ -> return $ \a -> i' <+> text "*" <+> a
   666              _ -> return $ \a -> i' <+> text "*" <+> a
   592     type2C' (PointerTo t) = liftM (\t a -> t (parens $ text "*" <> a)) $ type2C t
   667     type2C' (PointerTo t) = liftM (\t a -> t (parens $ text "*" <> a)) $ type2C t
   593     type2C' (RecordType tvs union) = do
   668     type2C' (RecordType tvs union) = do
   594         t <- withState' f $ mapM (tvar2C False) tvs
   669         t <- withState' f $ mapM (tvar2C False False True False) tvs
   595         u <- unions
   670         u <- unions
   596         return $ \i -> text "struct __" <> i <+> lbrace $+$ nest 4 ((vcat . map (<> semi) . concat $ t) $$ u) $+$ rbrace <+> i
   671         return $ \i -> text "struct __" <> i <+> lbrace $+$ nest 4 ((vcat . map (<> semi) . concat $ t) $$ u) $+$ rbrace <+> i
   597         where
   672         where
   598             f s = s{currentUnit = ""}
   673             f s = s{currentUnit = ""}
   599             unions = case union of
   674             unions = case union of
   600                      Nothing -> return empty
   675                      Nothing -> return empty
   601                      Just a -> do
   676                      Just a -> do
   602                          structs <- mapM struct2C a
   677                          structs <- mapM struct2C a
   603                          return $ text "union" $+$ braces (nest 4 $ vcat structs) <> semi
   678                          return $ text "union" $+$ braces (nest 4 $ vcat structs) <> semi
   604             struct2C tvs = do
   679             struct2C tvs = do
   605                 t <- withState' f $ mapM (tvar2C False) tvs
   680                 t <- withState' f $ mapM (tvar2C False False True False) tvs
   606                 return $ text "struct" $+$ braces (nest 4 (vcat . map (<> semi) . concat $ t)) <> semi
   681                 return $ text "struct" $+$ braces (nest 4 (vcat . map (<> semi) . concat $ t)) <> semi
   607     type2C' (RangeType r) = return (text "int" <+>)
   682     type2C' (RangeType r) = return (text "int" <+>)
   608     type2C' (Sequence ids) = do
   683     type2C' (Sequence ids) = do
   609         is <- mapM (id2C IOInsert . setBaseType bt) ids
   684         is <- mapM (id2C IOInsert . setBaseType bt) ids
   610         return (text "enum" <+> (braces . vcat . punctuate comma . map (\(a, b) -> a <+> equals <+> text "0x" <> text (showHex b "")) $ zip is [0..]) <+>)
   685         return (text "enum" <+> (braces . vcat . punctuate comma . map (\(a, b) -> a <+> equals <+> text "0x" <> text (showHex b "")) $ zip is [0..]) <+>)
   613     type2C' (ArrayDecl Nothing t) = type2C (PointerTo t)
   688     type2C' (ArrayDecl Nothing t) = type2C (PointerTo t)
   614     type2C' (ArrayDecl (Just r) t) = do
   689     type2C' (ArrayDecl (Just r) t) = do
   615         t' <- type2C t
   690         t' <- type2C t
   616         lt <- gets lastType
   691         lt <- gets lastType
   617         ft <- case lt of
   692         ft <- case lt of
   618                 BTFunction {} -> type2C (PointerTo t)
   693                 -- BTFunction {} -> type2C (PointerTo t)
   619                 _ -> return t'
   694                 _ -> return t'
   620         r' <- initExpr2C (InitRange r)
   695         r' <- initExpr2C (InitRange r)
   621         return $ \i -> ft i <> brackets r'
   696         return $ \i -> ft i <> brackets r'
   622     type2C' (Set t) = return (text "<<set>>" <+>)
   697     type2C' (Set t) = return (text "<<set>>" <+>)
   623     type2C' (FunctionType returnType params) = do
   698     type2C' (FunctionType returnType params) = do
   673                     return $ r <+> text "=" <+> e <> semi
   748                     return $ r <+> text "=" <+> e <> semi
   674                 BTString -> do
   749                 BTString -> do
   675                     e <- expr2C expr
   750                     e <- expr2C expr
   676                     return $ r <+> text "=" <+> e <> semi
   751                     return $ r <+> text "=" <+> e <> semi
   677                 _ -> error $ "Assignment to string from " ++ show lt
   752                 _ -> error $ "Assignment to string from " ++ show lt
   678         (BTArray _ _ _, _) -> phrase2C $
   753         (BTArray _ _ _, _) -> do
   679             ProcCall (FunCall
   754             case expr of
   680                 [
   755                 Reference er -> do
   681                 Reference $ Address ref
   756                     exprRef <- ref2C er
   682                 , Reference $ Address $ RefExpression expr
   757                     exprT <- gets lastType
   683                 , Reference $ FunCall [expr] (SimpleReference (Identifier "sizeof" BTUnknown))
   758                     case exprT of
   684                 ]
   759                         BTArray RangeInfinite _ _ ->
   685                 (SimpleReference (Identifier "memcpy" BTUnknown))
   760                             return $ text "FIXME: assign a dynamic array to an array"
   686                 ) []
   761                         BTArray _ _ _ -> phrase2C $
       
   762                                 ProcCall (FunCall
       
   763                                     [
       
   764                                     Reference $ ref
       
   765                                     , Reference $ RefExpression expr
       
   766                                     , Reference $ FunCall [expr] (SimpleReference (Identifier "sizeof" BTUnknown))
       
   767                                     ]
       
   768                                     (SimpleReference (Identifier "memcpy" BTUnknown))
       
   769                                     ) []
       
   770                         _ -> return $ text "FIXME: assign a non-specific value to an array"
       
   771 
       
   772                 _ -> return $ text "FIXME: dynamic array assignment 2"
   687         _ -> do
   773         _ -> do
   688             e <- expr2C expr
   774             e <- expr2C expr
   689             return $ r <+> text "=" <+> e <> semi
   775             return $ r <+> text "=" <+> e <> semi
   690 phrase2C (WhileCycle expr phrase) = do
   776 phrase2C (WhileCycle expr phrase) = do
   691     e <- expr2C expr
   777     e <- expr2C expr
   702     case2C (e, p) = do
   788     case2C (e, p) = do
   703         ies <- mapM range2C e
   789         ies <- mapM range2C e
   704         ph <- phrase2C p
   790         ph <- phrase2C p
   705         return $
   791         return $
   706              vcat (map (\i -> text "case" <+> i <> colon) . concat $ ies) <> nest 4 (ph $+$ text "break;")
   792              vcat (map (\i -> text "case" <+> i <> colon) . concat $ ies) <> nest 4 (ph $+$ text "break;")
   707     dflt | isNothing mphrase = return []
   793     dflt | isNothing mphrase = return [text "default: break;"] -- avoid compiler warning
   708          | otherwise = do
   794          | otherwise = do
   709              ph <- mapM phrase2C $ fromJust mphrase
   795              ph <- mapM phrase2C $ fromJust mphrase
   710              return [text "default:" <+> nest 4 (vcat ph)]
   796              return [text "default:" <+> nest 4 (vcat ph)]
   711 
   797 
   712 phrase2C wb@(WithBlock ref p) = do
   798 phrase2C wb@(WithBlock ref p) = do
   713     r <- ref2C ref
   799     r <- ref2C ref
   714     t <- gets lastType
   800     t <- gets lastType
   715     case t of
   801     case t of
   716         (BTRecord _ rs) -> withRecordNamespace (render r ++ ".") rs $ phrase2C $ wrapPhrase p
   802         (BTRecord _ rs) -> withRecordNamespace (render r ++ ".") (rec2Records rs) $ phrase2C $ wrapPhrase p
   717         a -> do
   803         a -> do
   718             error $ "'with' block referencing non-record type " ++ show a ++ "\n" ++ show wb
   804             error $ "'with' block referencing non-record type " ++ show a ++ "\n" ++ show wb
   719 phrase2C (ForCycle i' e1' e2' p) = do
   805 phrase2C (ForCycle i' e1' e2' p up) = do
   720     i <- id2C IOLookup i'
   806     i <- id2C IOLookup i'
       
   807     iType <- gets lastIdTypeDecl
   721     e1 <- expr2C e1'
   808     e1 <- expr2C e1'
   722     e2 <- expr2C e2'
   809     e2 <- expr2C e2'
   723     ph <- phrase2C (wrapPhrase p)
   810     let inc = if up then "inc" else "dec"
   724     return $
   811     let add = if up then "+ 1" else "- 1"
   725         text "for" <> (parens . hsep . punctuate (char ';') $ [i <+> text "=" <+> e1, i <+> text "<=" <+> e2, text "++" <> i])
   812     let iEnd = i <> text "__end__"
       
   813     ph <- phrase2C . appendPhrase (BuiltInFunctionCall [Reference $ SimpleReference i'] (SimpleReference (Identifier inc BTUnknown))) $ wrapPhrase p
       
   814     return . braces $
       
   815         i <+> text "=" <+> e1 <> semi
   726         $$
   816         $$
   727         ph
   817         iType <+> iEnd <+> text "=" <+> e2 <> semi
       
   818         $$ 
       
   819         text "if" <+> (parens $ i <+> text "<=" <+> iEnd) <+> text "do" <+> ph <+>
       
   820         text "while" <> parens (i <+> text "!=" <+> iEnd <+> text add) <> semi
       
   821     where
       
   822         appendPhrase p (Phrases ps) = Phrases $ ps ++ [p]
   728 phrase2C (RepeatCycle e' p') = do
   823 phrase2C (RepeatCycle e' p') = do
   729     e <- expr2C e'
   824     e <- expr2C e'
   730     p <- phrase2C (Phrases p')
   825     p <- phrase2C (Phrases p')
   731     return $ text "do" <+> p <+> text "while" <> parens (text "!" <> parens e) <> semi
   826     return $ text "do" <+> p <+> text "while" <> parens (text "!" <> parens e) <> semi
   732 phrase2C NOP = return $ text ";"
   827 phrase2C NOP = return $ text ";"
   775             ref2C $ FunCall [expr1, expr2] (SimpleReference i)
   870             ref2C $ FunCall [expr1, expr2] (SimpleReference i)
   776         ("in", _, _) ->
   871         ("in", _, _) ->
   777             case expr2 of
   872             case expr2 of
   778                  SetExpression set -> do
   873                  SetExpression set -> do
   779                      ids <- mapM (id2C IOLookup) set
   874                      ids <- mapM (id2C IOLookup) set
       
   875                      modify(\s -> s{lastType = BTBool})
   780                      return . parens . hcat . punctuate (text " || ") . map (\i -> parens $ e1 <+> text "==" <+> i) $ ids
   876                      return . parens . hcat . punctuate (text " || ") . map (\i -> parens $ e1 <+> text "==" <+> i) $ ids
   781                  _ -> error "'in' against not set expression"
   877                  _ -> error "'in' against not set expression"
   782         (o, _, _) | o `elem` boolOps -> do
   878         (o, _, _) | o `elem` boolOps -> do
   783                         modify(\s -> s{lastType = BTBool})
   879                         modify(\s -> s{lastType = BTBool})
   784                         return $ parens e1 <+> text o <+> parens e2
   880                         return $ parens e1 <+> text o <+> parens e2
   785                   | otherwise -> return $ parens e1 <+> text o <+> parens e2
   881                   | otherwise -> do
       
   882                         o' <- return $ case o of
       
   883                             "/(float)" -> text "/(float)" -- pascal returns real value
       
   884                             _ -> text o
       
   885                         e1' <- return $ case (o, t1, t2) of
       
   886                                 ("-", BTInt, BTInt) -> parens $ text "(int64_t)" <+> parens e1
       
   887                                 _ -> parens e1
       
   888                         e2' <- return $ case (o, t1, t2) of
       
   889                                 ("-", BTInt, BTInt) -> parens $ text "(int64_t)" <+> parens e2
       
   890                                 _ -> parens e2
       
   891                         return $ e1' <+> o' <+> e2'
   786     where
   892     where
   787         boolOps = ["==", "!=", "<", ">", "<=", ">="]
   893         boolOps = ["==", "!=", "<", ">", "<=", ">="]
   788 expr2C (NumberLiteral s) = do
   894 expr2C (NumberLiteral s) = do
   789     modify(\s -> s{lastType = BTInt})
   895     modify(\s -> s{lastType = BTInt})
   790     return $ text s
   896     return $ text s
   804     lt <- gets lastType
   910     lt <- gets lastType
   805     case lt of
   911     case lt of
   806         BTRecord t _ -> do
   912         BTRecord t _ -> do
   807             i <- op2CTyped op [SimpleType (Identifier t undefined)]
   913             i <- op2CTyped op [SimpleType (Identifier t undefined)]
   808             ref2C $ FunCall [expr] (SimpleReference i)
   914             ref2C $ FunCall [expr] (SimpleReference i)
   809         _ -> return $ text (op2C op) <> e
   915         BTBool -> do
       
   916             o <- return $ case op of
       
   917                      "not" -> text "!"
       
   918                      _ -> text (op2C op)
       
   919             return $ o <> parens e
       
   920         _ -> return $ text (op2C op) <> parens e
   810 expr2C Null = return $ text "NULL"
   921 expr2C Null = return $ text "NULL"
   811 expr2C (CharCode a) = do
   922 expr2C (CharCode a) = do
   812     modify(\s -> s{lastType = BTChar})
   923     modify(\s -> s{lastType = BTChar})
   813     return $ quotes $ text "\\x" <> text (showHex (read a) "")
   924     return $ quotes $ text "\\x" <> text (showHex (read a) "")
   814 expr2C (HexCharCode a) = if length a <= 2 then return $ quotes $ text "\\x" <> text (map toLower a) else expr2C $ HexNumber a
   925 expr2C (HexCharCode a) = if length a <= 2 then return $ quotes $ text "\\x" <> text (map toLower a) else expr2C $ HexNumber a
   833          BTString -> return $ int 255
   944          BTString -> return $ int 255
   834          BTArray (RangeFromTo _ n) _ _ -> initExpr2C n
   945          BTArray (RangeFromTo _ n) _ _ -> initExpr2C n
   835          _ -> error $ "BuiltInFunCall 'high' from " ++ show e ++ "\ntype: " ++ show lt
   946          _ -> error $ "BuiltInFunCall 'high' from " ++ show e ++ "\ntype: " ++ show lt
   836 expr2C (BuiltInFunCall [e] (SimpleReference (Identifier "ord" _))) = liftM parens $ expr2C e
   947 expr2C (BuiltInFunCall [e] (SimpleReference (Identifier "ord" _))) = liftM parens $ expr2C e
   837 expr2C (BuiltInFunCall [e] (SimpleReference (Identifier "succ" _))) = liftM (<> text " + 1") $ expr2C e
   948 expr2C (BuiltInFunCall [e] (SimpleReference (Identifier "succ" _))) = liftM (<> text " + 1") $ expr2C e
   838 expr2C (BuiltInFunCall [e] (SimpleReference (Identifier "pred" _))) = liftM (<> text " - 1") $ expr2C e
   949 expr2C (BuiltInFunCall [e] (SimpleReference (Identifier "pred" _))) = liftM (<> text " - (int64_t)1") $ expr2C e
   839 expr2C (BuiltInFunCall [e] (SimpleReference (Identifier "length" _))) = do
   950 expr2C (BuiltInFunCall [e] (SimpleReference (Identifier "length" _))) = do
   840     e' <- expr2C e
   951     e' <- expr2C e
   841     lt <- gets lastType
   952     lt <- gets lastType
   842     modify (\s -> s{lastType = BTInt})
   953     modify (\s -> s{lastType = BTInt})
   843     case lt of
   954     case lt of
   844          BTString -> return $ text "Length" <> parens e'
   955          BTString -> return $ text "fpcrtl_Length" <> parens e'
   845          BTArray RangeInfinite _ _ -> error $ "length() called on variable size array " ++ show e'
   956          BTArray RangeInfinite _ _ -> error $ "length() called on variable size array " ++ show e'
   846          BTArray (RangeFromTo _ n) _ _ -> initExpr2C (BuiltInFunction "succ" [n])
   957          BTArray (RangeFromTo _ n) _ _ -> initExpr2C (BuiltInFunction "succ" [n])
   847          _ -> error $ "length() called on " ++ show lt
   958          _ -> error $ "length() called on " ++ show lt
   848 expr2C (BuiltInFunCall params ref) = do
   959 expr2C (BuiltInFunCall params ref) = do
   849     r <- ref2C ref
   960     r <- ref2C ref
   862     i <- id2C IOLookup name
   973     i <- id2C IOLookup name
   863     t <- gets lastType
   974     t <- gets lastType
   864     case t of
   975     case t of
   865          BTFunction _ _ rt -> do
   976          BTFunction _ _ rt -> do
   866              modify(\s -> s{lastType = rt})
   977              modify(\s -> s{lastType = rt})
   867              return $ i <> parens empty
   978              return $ i <> parens empty --xymeng: removed parens
   868          _ -> return $ i
   979          _ -> return $ i
   869 ref2CF r@(RecordField (SimpleReference _) (SimpleReference _)) = do
   980 ref2CF r@(RecordField (SimpleReference _) (SimpleReference _)) = do
   870     i <- ref2C r
   981     i <- ref2C r
   871     t <- gets lastType
   982     t <- gets lastType
   872     case t of
   983     case t of
   905 ref2C (SimpleReference name) = id2C IOLookup name
  1016 ref2C (SimpleReference name) = id2C IOLookup name
   906 ref2C rf@(RecordField (Dereference ref1) ref2) = do
  1017 ref2C rf@(RecordField (Dereference ref1) ref2) = do
   907     r1 <- ref2C ref1
  1018     r1 <- ref2C ref1
   908     t <- fromPointer (show ref1) =<< gets lastType
  1019     t <- fromPointer (show ref1) =<< gets lastType
   909     r2 <- case t of
  1020     r2 <- case t of
   910         BTRecord _ rs -> withRecordNamespace "" rs $ ref2C ref2
  1021         BTRecord _ rs -> withRecordNamespace "" (rec2Records rs) $ ref2C ref2
   911         BTUnit -> error "What??"
  1022         BTUnit -> error "What??"
   912         a -> error $ "dereferencing from " ++ show a ++ "\n" ++ show rf
  1023         a -> error $ "dereferencing from " ++ show a ++ "\n" ++ show rf
   913     return $
  1024     return $
   914         r1 <> text "->" <> r2
  1025         r1 <> text "->" <> r2
   915 ref2C rf@(RecordField ref1 ref2) = do
  1026 ref2C rf@(RecordField ref1 ref2) = do
   916     r1 <- ref2C ref1
  1027     r1 <- ref2C ref1
   917     t <- gets lastType
  1028     t <- gets lastType
   918     case t of
  1029     case t of
   919         BTRecord _ rs -> do
  1030         BTRecord _ rs -> do
   920             r2 <- withRecordNamespace "" rs $ ref2C ref2
  1031             r2 <- withRecordNamespace "" (rec2Records rs) $ ref2C ref2
   921             return $ r1 <> text "." <> r2
  1032             return $ r1 <> text "." <> r2
   922         BTUnit -> withLastIdNamespace $ ref2C ref2
  1033         BTUnit -> withLastIdNamespace $ ref2C ref2
   923         a -> error $ "dereferencing from " ++ show a ++ "\n" ++ show rf
  1034         a -> error $ "dereferencing from " ++ show a ++ "\n" ++ show rf
   924 ref2C d@(Dereference ref) = do
  1035 ref2C d@(Dereference ref) = do
   925     r <- ref2C ref
  1036     r <- ref2C ref
   960 
  1071 
   961 
  1072 
   962 op2C :: String -> String
  1073 op2C :: String -> String
   963 op2C "or" = "|"
  1074 op2C "or" = "|"
   964 op2C "and" = "&"
  1075 op2C "and" = "&"
   965 op2C "not" = "!"
  1076 op2C "not" = "~"
   966 op2C "xor" = "^"
  1077 op2C "xor" = "^"
   967 op2C "div" = "/"
  1078 op2C "div" = "/"
   968 op2C "mod" = "%"
  1079 op2C "mod" = "%"
   969 op2C "shl" = "<<"
  1080 op2C "shl" = "<<"
   970 op2C "shr" = ">>"
  1081 op2C "shr" = ">>"
   971 op2C "<>" = "!="
  1082 op2C "<>" = "!="
   972 op2C "=" = "=="
  1083 op2C "=" = "=="
       
  1084 op2C "/" = "/(float)"
   973 op2C a = a
  1085 op2C a = a
   974 
  1086