tools/pas2c/PascalParser.hs
branchsdl2transition
changeset 11362 ed5a6478e710
parent 10924 ed1b6914cac5
child 11366 f1b5f1dc61a3
equal deleted inserted replaced
11361:31570b766315 11362:ed5a6478e710
       
     1 module PascalParser (
       
     2     pascalUnit,
       
     3     mainResultInit
       
     4     )
       
     5     where
       
     6 
       
     7 import Text.Parsec
       
     8 import Text.Parsec.Token
       
     9 import Text.Parsec.Expr
       
    10 import Control.Monad
       
    11 import Data.Maybe
       
    12 import Data.Char
       
    13 
       
    14 import PascalBasics
       
    15 import PascalUnitSyntaxTree
       
    16 
       
    17 
       
    18 mainResultInit :: Phrase
       
    19 mainResultInit = (\(Right a) -> a) $ parse phrase "<built-in>" "main:= 0;"
       
    20 
       
    21 knownTypes :: [String]
       
    22 knownTypes = ["shortstring", "ansistring", "char", "byte"]
       
    23 
       
    24 pascalUnit :: Parsec String u PascalUnit
       
    25 pascalUnit = do
       
    26     comments
       
    27     u <- choice [program, unit, systemUnit, redoUnit]
       
    28     comments
       
    29     return u
       
    30 
       
    31 iD :: Parsec String u Identifier
       
    32 iD = do
       
    33     i <- identifier pas
       
    34     comments
       
    35     when (i == "not") $ unexpected "'not' used as an identifier"
       
    36     return $ Identifier i BTUnknown
       
    37 
       
    38 unit :: Parsec String u PascalUnit
       
    39 unit = do
       
    40     string' "unit" >> comments
       
    41     name <- iD
       
    42     void $ semi pas
       
    43     comments
       
    44     int <- interface
       
    45     impl <- implementation
       
    46     comments
       
    47     return $ Unit name int impl Nothing Nothing
       
    48 
       
    49 
       
    50 reference :: Parsec String u Reference
       
    51 reference = term <?> "reference"
       
    52     where
       
    53     term = comments >> choice [
       
    54         parens pas (liftM RefExpression expression >>= postfixes) >>= postfixes
       
    55         , try $ typeCast >>= postfixes
       
    56         , char' '@' >> liftM Address reference >>= postfixes
       
    57         , liftM SimpleReference iD >>= postfixes
       
    58         ] <?> "simple reference"
       
    59 
       
    60     postfixes r = many postfix >>= return . foldl (flip ($)) r
       
    61     postfix = choice [
       
    62             parens pas (option [] parameters) >>= return . FunCall
       
    63           , char' '^' >> return Dereference
       
    64           , (brackets pas) (commaSep1 pas $ expression) >>= return . ArrayElement
       
    65           , (char' '.' >> notFollowedBy (char' '.')) >> liftM (flip RecordField) reference
       
    66         ]
       
    67 
       
    68     typeCast = do
       
    69         t <- choice $ map (\s -> try $ caseInsensitiveString s >>= \i -> notFollowedBy alphaNum >> return i) knownTypes
       
    70         e <- parens pas expression
       
    71         comments
       
    72         return $ TypeCast (Identifier t BTUnknown) e
       
    73 
       
    74 varsDecl1, varsDecl :: Bool -> Parsec String u [TypeVarDeclaration]
       
    75 varsDecl1 = varsParser sepEndBy1
       
    76 varsDecl = varsParser sepEndBy
       
    77 
       
    78 varsParser ::
       
    79     (Parsec String u TypeVarDeclaration
       
    80         -> Parsec String u String
       
    81         -> Parsec
       
    82             String u [TypeVarDeclaration])
       
    83     -> Bool
       
    84     -> Parsec
       
    85             String u [TypeVarDeclaration]
       
    86 varsParser m endsWithSemi = do
       
    87     vs <- m (aVarDecl endsWithSemi) (semi pas)
       
    88     return vs
       
    89 
       
    90 aVarDecl :: Bool -> Parsec String u TypeVarDeclaration
       
    91 aVarDecl endsWithSemi = do
       
    92     isVar <- liftM (\i -> i == Just "var" || i == Just "out") $
       
    93         if not endsWithSemi then
       
    94             optionMaybe $ choice [
       
    95                 try $ string "var"
       
    96                 , try $ string "const"
       
    97                 , try $ string "out"
       
    98                 ]
       
    99             else
       
   100                 return Nothing
       
   101     comments
       
   102     ids <- do
       
   103         i <- (commaSep1 pas) $ (try iD <?> "variable declaration")
       
   104         char' ':'
       
   105         return i
       
   106     comments
       
   107     t <- typeDecl <?> "variable type declaration"
       
   108     comments
       
   109     initialization <- option Nothing $ do
       
   110         char' '='
       
   111         comments
       
   112         e <- initExpression
       
   113         comments
       
   114         return (Just e)
       
   115     return $ VarDeclaration isVar False (ids, t) initialization
       
   116 
       
   117 constsDecl :: Parsec String u [TypeVarDeclaration]
       
   118 constsDecl = do
       
   119     vs <- many1 (try (aConstDecl >>= \i -> semi pas >> return i) >>= \i -> comments >> return i)
       
   120     comments
       
   121     return vs
       
   122     where
       
   123     aConstDecl = do
       
   124         comments
       
   125         i <- iD
       
   126         t <- optionMaybe $ do
       
   127             char' ':'
       
   128             comments
       
   129             t <- typeDecl
       
   130             comments
       
   131             return t
       
   132         char' '='
       
   133         comments
       
   134         e <- initExpression
       
   135         comments
       
   136         return $ VarDeclaration False (isNothing t) ([i], fromMaybe (DeriveType e) t) (Just e)
       
   137 
       
   138 typeDecl :: Parsec String u TypeDecl
       
   139 typeDecl = choice [
       
   140     char' '^' >> typeDecl >>= return . PointerTo
       
   141     , try (string' "shortstring") >> return String
       
   142     , try (string' "string") >> optionMaybe (brackets pas $ integer pas) >> return String
       
   143     , try (string' "ansistring") >> optionMaybe (brackets pas $ integer pas) >> return AString
       
   144     , arrayDecl
       
   145     , recordDecl
       
   146     , setDecl
       
   147     , functionType
       
   148     , sequenceDecl >>= return . Sequence
       
   149     , try iD >>= return . SimpleType
       
   150     , rangeDecl >>= return . RangeType
       
   151     ] <?> "type declaration"
       
   152     where
       
   153     arrayDecl = do
       
   154         try $ do
       
   155             optional $ (try $ string' "packed") >> comments
       
   156             string' "array"
       
   157         comments
       
   158         r <- option [] $ do
       
   159             char' '['
       
   160             r <- commaSep pas rangeDecl
       
   161             char' ']'
       
   162             comments
       
   163             return r
       
   164         string' "of"
       
   165         comments
       
   166         t <- typeDecl
       
   167         if null r then
       
   168             return $ ArrayDecl Nothing t
       
   169             else
       
   170             return $ foldr (\a b -> ArrayDecl (Just a) b) (ArrayDecl (Just $ head r) t) (tail r)
       
   171     recordDecl = do
       
   172         try $ do
       
   173             optional $ (try $ string' "packed") >> comments
       
   174             string' "record"
       
   175         comments
       
   176         vs <- varsDecl True
       
   177         union <- optionMaybe $ do
       
   178             string' "case"
       
   179             comments
       
   180             void $ iD
       
   181             comments
       
   182             string' "of"
       
   183             comments
       
   184             many unionCase
       
   185         string' "end"
       
   186         return $ RecordType vs union
       
   187     setDecl = do
       
   188         try $ string' "set" >> void space
       
   189         comments
       
   190         string' "of"
       
   191         comments
       
   192         liftM Set typeDecl
       
   193     unionCase = do
       
   194         void $ try $ commaSep pas $ (void $ iD) <|> (void $ integer pas)
       
   195         char' ':'
       
   196         comments
       
   197         u <- parens pas $ varsDecl True
       
   198         char' ';'
       
   199         comments
       
   200         return u
       
   201     sequenceDecl = (parens pas) $ (commaSep pas) (iD >>= \i -> optional (spaces >> char' '=' >> spaces >> integer pas) >> return i)
       
   202     functionType = do
       
   203         fp <- try (string "function") <|> try (string "procedure")
       
   204         comments
       
   205         vs <- option [] $ parens pas $ varsDecl False
       
   206         comments
       
   207         ret <- if (fp == "function") then do
       
   208             char' ':'
       
   209             comments
       
   210             ret <- typeDecl
       
   211             comments
       
   212             return ret
       
   213             else
       
   214             return VoidType
       
   215         optional $ try $ char' ';' >> comments >> string' "cdecl"
       
   216         comments
       
   217         return $ FunctionType ret vs
       
   218 
       
   219 typesDecl :: Parsec String u [TypeVarDeclaration]
       
   220 typesDecl = many (aTypeDecl >>= \t -> comments >> return t)
       
   221     where
       
   222     aTypeDecl = do
       
   223         i <- try $ do
       
   224             i <- iD <?> "type declaration"
       
   225             comments
       
   226             char' '='
       
   227             return i
       
   228         comments
       
   229         t <- typeDecl
       
   230         comments
       
   231         void $ semi pas
       
   232         comments
       
   233         return $ TypeDeclaration i t
       
   234 
       
   235 rangeDecl :: Parsec String u Range
       
   236 rangeDecl = choice [
       
   237     try $ rangeft
       
   238     , iD >>= return . Range
       
   239     ] <?> "range declaration"
       
   240     where
       
   241     rangeft = do
       
   242     e1 <- initExpression
       
   243     string' ".."
       
   244     e2 <- initExpression
       
   245     return $ RangeFromTo e1 e2
       
   246 
       
   247 typeVarDeclaration :: Bool -> Parsec String u [TypeVarDeclaration]
       
   248 typeVarDeclaration isImpl = (liftM concat . many . choice) [
       
   249     varSection,
       
   250     constSection,
       
   251     typeSection,
       
   252     funcDecl,
       
   253     operatorDecl
       
   254     ]
       
   255     where
       
   256 
       
   257     fixInit v = concat $ map (\x -> case x of
       
   258                     VarDeclaration a b (ids, t) c ->
       
   259                         let typeId = (Identifier ((\(Identifier i _) -> i) (head ids) ++ "_tt") BTUnknown) in
       
   260                         let res =  [TypeDeclaration typeId t, VarDeclaration a b (ids, (SimpleType typeId)) c] in
       
   261                         case t of
       
   262                             RecordType _ _ -> res -- create a separated type declaration
       
   263                             ArrayDecl _ _ -> res
       
   264                             _ -> [x]
       
   265                     _ -> error ("checkInit:\n" ++ (show v))) v
       
   266 
       
   267     varSection = do
       
   268         try $ string' "var"
       
   269         comments
       
   270         v <- varsDecl1 True <?> "variable declaration"
       
   271         comments
       
   272         return $ fixInit v
       
   273 
       
   274     constSection = do
       
   275         try $ string' "const"
       
   276         comments
       
   277         c <- constsDecl <?> "const declaration"
       
   278         comments
       
   279         return $ fixInit c
       
   280 
       
   281     typeSection = do
       
   282         try $ string' "type"
       
   283         comments
       
   284         t <- typesDecl <?> "type declaration"
       
   285         comments
       
   286         return t
       
   287 
       
   288     operatorDecl = do
       
   289         try $ string' "operator"
       
   290         comments
       
   291         i <- manyTill anyChar space
       
   292         comments
       
   293         vs <- parens pas $ varsDecl False
       
   294         comments
       
   295         rid <- iD
       
   296         comments
       
   297         char' ':'
       
   298         comments
       
   299         ret <- typeDecl
       
   300         comments
       
   301         -- return ret
       
   302         -- ^^^^^^^^^^ wth was this???
       
   303         char' ';'
       
   304         comments
       
   305         forward <- liftM isJust $ optionMaybe (try (string' "forward;") >> comments)
       
   306         inline <- liftM (any (== "inline;")) $ many functionDecorator
       
   307         b <- if isImpl && (not forward) then
       
   308                 liftM Just functionBody
       
   309                 else
       
   310                 return Nothing
       
   311         return $ [OperatorDeclaration i rid inline ret vs b]
       
   312 
       
   313 
       
   314     funcDecl = do
       
   315         fp <- try (string "function") <|> try (string "procedure")
       
   316         comments
       
   317         i <- iD
       
   318         vs <- option [] $ parens pas $ varsDecl False
       
   319         comments
       
   320         ret <- if (fp == "function") then do
       
   321             char' ':'
       
   322             comments
       
   323             ret <- typeDecl
       
   324             comments
       
   325             return ret
       
   326             else
       
   327             return VoidType
       
   328         char' ';'
       
   329         comments
       
   330         forward <- liftM isJust $ optionMaybe (try (string "forward;") >> comments)
       
   331         decorators <- many functionDecorator
       
   332         let inline = any (== "inline;") decorators
       
   333             overload = any (== "overload;") decorators
       
   334             external = any (== "external;") decorators
       
   335         -- TODO: don't mangle external functions names (and remove fpcrtl.h defines hacks)
       
   336         b <- if isImpl && (not forward) && (not external) then
       
   337                 liftM Just functionBody
       
   338                 else
       
   339                 return Nothing
       
   340         return $ [FunctionDeclaration i inline overload external ret vs b]
       
   341 
       
   342     functionDecorator = do
       
   343         d <- choice [
       
   344             try $ string "inline;"
       
   345             , try $ caseInsensitiveString "cdecl;"
       
   346             , try $ string "overload;"
       
   347             , try $ string "export;"
       
   348             , try $ string "varargs;"
       
   349             , try (string' "external") >> comments >> iD >> comments >>
       
   350                 optional (string' "name" >> comments >> stringLiteral pas) >> string' ";" >> return "external;"
       
   351             ]
       
   352         comments
       
   353         return d
       
   354 
       
   355 
       
   356 program :: Parsec String u PascalUnit
       
   357 program = do
       
   358     string' "program"
       
   359     comments
       
   360     name <- iD
       
   361     (char' ';')
       
   362     comments
       
   363     comments
       
   364     u <- uses
       
   365     comments
       
   366     tv <- typeVarDeclaration True
       
   367     comments
       
   368     p <- phrase
       
   369     comments
       
   370     char' '.'
       
   371     comments
       
   372     return $ Program name (Implementation u (TypesAndVars tv)) p
       
   373 
       
   374 interface :: Parsec String u Interface
       
   375 interface = do
       
   376     string' "interface"
       
   377     comments
       
   378     u <- uses
       
   379     comments
       
   380     tv <- typeVarDeclaration False
       
   381     comments
       
   382     return $ Interface u (TypesAndVars tv)
       
   383 
       
   384 implementation :: Parsec String u Implementation
       
   385 implementation = do
       
   386     string' "implementation"
       
   387     comments
       
   388     u <- uses
       
   389     comments
       
   390     tv <- typeVarDeclaration True
       
   391     string' "end."
       
   392     comments
       
   393     return $ Implementation u (TypesAndVars tv)
       
   394 
       
   395 expression :: Parsec String u Expression
       
   396 expression = do
       
   397     buildExpressionParser table term <?> "expression"
       
   398     where
       
   399     term = comments >> choice [
       
   400         builtInFunction expression >>= \(n, e) -> return $ BuiltInFunCall e (SimpleReference (Identifier n BTUnknown))
       
   401         , try (parens pas expression >>= \e -> notFollowedBy (comments >> char' '.') >> return e)
       
   402         , brackets pas (commaSep pas iD) >>= return . SetExpression
       
   403         , try $ integer pas >>= \i -> notFollowedBy (char' '.') >> (return . NumberLiteral . show) i
       
   404         , float pas >>= return . FloatLiteral . show
       
   405         , try $ integer pas >>= return . NumberLiteral . show
       
   406         , try (string' "_S" >> stringLiteral pas) >>= return . StringLiteral
       
   407         , try (string' "_P" >> stringLiteral pas) >>= return . PCharLiteral
       
   408         , stringLiteral pas >>= return . strOrChar
       
   409         , try (string' "#$") >> many hexDigit >>= \c -> comments >> return (HexCharCode c)
       
   410         , char' '#' >> many digit >>= \c -> comments >> return (CharCode c)
       
   411         , char' '$' >> many hexDigit >>=  \h -> comments >> return (HexNumber h)
       
   412         --, char' '-' >> expression >>= return . PrefixOp "-"
       
   413         , char' '-' >> reference >>= return . PrefixOp "-" . Reference
       
   414         , (try $ string' "not" >> notFollowedBy comments) >> unexpected "'not'"
       
   415         , try $ string' "nil" >> return Null
       
   416         , reference >>= return . Reference
       
   417         ] <?> "simple expression"
       
   418 
       
   419     table = [
       
   420           [  Prefix (reservedOp pas "not">> return (PrefixOp "not"))
       
   421            , Prefix (try (char' '-') >> return (PrefixOp "-"))]
       
   422            ,
       
   423           [  Infix (char' '*' >> return (BinOp "*")) AssocLeft
       
   424            , Infix (char' '/' >> return (BinOp "/")) AssocLeft
       
   425            , Infix (try (string' "div") >> return (BinOp "div")) AssocLeft
       
   426            , Infix (try (string' "mod") >> return (BinOp "mod")) AssocLeft
       
   427            , Infix (try (string' "in") >> return (BinOp "in")) AssocNone
       
   428            , Infix (try $ string' "and" >> return (BinOp "and")) AssocLeft
       
   429            , Infix (try $ string' "shl" >> return (BinOp "shl")) AssocLeft
       
   430            , Infix (try $ string' "shr" >> return (BinOp "shr")) AssocLeft
       
   431           ]
       
   432         , [  Infix (char' '+' >> return (BinOp "+")) AssocLeft
       
   433            , Infix (char' '-' >> return (BinOp "-")) AssocLeft
       
   434            , Infix (try $ string' "or" >> return (BinOp "or")) AssocLeft
       
   435            , Infix (try $ string' "xor" >> return (BinOp "xor")) AssocLeft
       
   436           ]
       
   437         , [  Infix (try (string' "<>") >> return (BinOp "<>")) AssocNone
       
   438            , Infix (try (string' "<=") >> return (BinOp "<=")) AssocNone
       
   439            , Infix (try (string' ">=") >> return (BinOp ">=")) AssocNone
       
   440            , Infix (char' '<' >> return (BinOp "<")) AssocNone
       
   441            , Infix (char' '>' >> return (BinOp ">")) AssocNone
       
   442           ]
       
   443         {-, [  Infix (try $ string' "shl" >> return (BinOp "shl")) AssocNone
       
   444              , Infix (try $ string' "shr" >> return (BinOp "shr")) AssocNone
       
   445           ]
       
   446         , [
       
   447              Infix (try $ string' "or" >> return (BinOp "or")) AssocLeft
       
   448            , Infix (try $ string' "xor" >> return (BinOp "xor")) AssocLeft
       
   449           ]-}
       
   450         , [
       
   451              Infix (char' '=' >> return (BinOp "=")) AssocNone
       
   452           ]
       
   453         ]
       
   454     strOrChar [a] = CharCode . show . ord $ a
       
   455     strOrChar a = StringLiteral a
       
   456 
       
   457 phrasesBlock :: Parsec String u Phrase
       
   458 phrasesBlock = do
       
   459     try $ string' "begin"
       
   460     comments
       
   461     p <- manyTill phrase (try $ string' "end" >> notFollowedBy alphaNum)
       
   462     comments
       
   463     return $ Phrases p
       
   464 
       
   465 phrase :: Parsec String u Phrase
       
   466 phrase = do
       
   467     o <- choice [
       
   468         phrasesBlock
       
   469         , ifBlock
       
   470         , whileCycle
       
   471         , repeatCycle
       
   472         , switchCase
       
   473         , withBlock
       
   474         , forCycle
       
   475         , (try $ reference >>= \r -> string' ":=" >> return r) >>= \r -> comments >> expression >>= return . Assignment r
       
   476         , builtInFunction expression >>= \(n, e) -> return $ BuiltInFunctionCall e (SimpleReference (Identifier n BTUnknown))
       
   477         , procCall
       
   478         , char' ';' >> comments >> return NOP
       
   479         ]
       
   480     optional $ char' ';'
       
   481     comments
       
   482     return o
       
   483 
       
   484 ifBlock :: Parsec String u Phrase
       
   485 ifBlock = do
       
   486     try $ string "if" >> notFollowedBy (alphaNum <|> char '_')
       
   487     comments
       
   488     e <- expression
       
   489     comments
       
   490     string' "then"
       
   491     comments
       
   492     o1 <- phrase
       
   493     comments
       
   494     o2 <- optionMaybe $ do
       
   495         try $ string' "else" >> void space
       
   496         comments
       
   497         o <- option NOP phrase
       
   498         comments
       
   499         return o
       
   500     return $ IfThenElse e o1 o2
       
   501 
       
   502 whileCycle :: Parsec String u Phrase
       
   503 whileCycle = do
       
   504     try $ string' "while"
       
   505     comments
       
   506     e <- expression
       
   507     comments
       
   508     string' "do"
       
   509     comments
       
   510     o <- phrase
       
   511     return $ WhileCycle e o
       
   512 
       
   513 withBlock :: Parsec String u Phrase
       
   514 withBlock = do
       
   515     try $ string' "with" >> void space
       
   516     comments
       
   517     rs <- (commaSep1 pas) reference
       
   518     comments
       
   519     string' "do"
       
   520     comments
       
   521     o <- phrase
       
   522     return $ foldr WithBlock o rs
       
   523 
       
   524 repeatCycle :: Parsec String u Phrase
       
   525 repeatCycle = do
       
   526     try $ string' "repeat" >> void space
       
   527     comments
       
   528     o <- many phrase
       
   529     string' "until"
       
   530     comments
       
   531     e <- expression
       
   532     comments
       
   533     return $ RepeatCycle e o
       
   534 
       
   535 forCycle :: Parsec String u Phrase
       
   536 forCycle = do
       
   537     try $ string' "for" >> void space
       
   538     comments
       
   539     i <- iD
       
   540     comments
       
   541     string' ":="
       
   542     comments
       
   543     e1 <- expression
       
   544     comments
       
   545     up <- liftM (== Just "to") $
       
   546             optionMaybe $ choice [
       
   547                 try $ string "to"
       
   548                 , try $ string "downto"
       
   549                 ]
       
   550     --choice [string' "to", string' "downto"]
       
   551     comments
       
   552     e2 <- expression
       
   553     comments
       
   554     string' "do"
       
   555     comments
       
   556     p <- phrase
       
   557     comments
       
   558     return $ ForCycle i e1 e2 p up
       
   559 
       
   560 switchCase :: Parsec String u Phrase
       
   561 switchCase = do
       
   562     try $ string' "case"
       
   563     comments
       
   564     e <- expression
       
   565     comments
       
   566     string' "of"
       
   567     comments
       
   568     cs <- many1 aCase
       
   569     o2 <- optionMaybe $ do
       
   570         try $ string' "else" >> notFollowedBy alphaNum
       
   571         comments
       
   572         o <- many phrase
       
   573         comments
       
   574         return o
       
   575     string' "end"
       
   576     comments
       
   577     return $ SwitchCase e cs o2
       
   578     where
       
   579     aCase = do
       
   580         e <- (commaSep pas) $ (liftM InitRange rangeDecl <|> initExpression)
       
   581         comments
       
   582         char' ':'
       
   583         comments
       
   584         p <- phrase
       
   585         comments
       
   586         return (e, p)
       
   587 
       
   588 procCall :: Parsec String u Phrase
       
   589 procCall = do
       
   590     r <- reference
       
   591     p <- option [] $ (parens pas) parameters
       
   592     return $ ProcCall r p
       
   593 
       
   594 parameters :: Parsec String u [Expression]
       
   595 parameters = (commaSep pas) expression <?> "parameters"
       
   596 
       
   597 functionBody :: Parsec String u (TypesAndVars, Phrase)
       
   598 functionBody = do
       
   599     tv <- typeVarDeclaration True
       
   600     comments
       
   601     p <- phrasesBlock
       
   602     char' ';'
       
   603     comments
       
   604     return (TypesAndVars tv, p)
       
   605 
       
   606 uses :: Parsec String u Uses
       
   607 uses = liftM Uses (option [] u)
       
   608     where
       
   609         u = do
       
   610             string' "uses"
       
   611             comments
       
   612             ulist <- (iD >>= \i -> comments >> return i) `sepBy1` (char' ',' >> comments)
       
   613             char' ';'
       
   614             comments
       
   615             return ulist
       
   616 
       
   617 initExpression :: Parsec String u InitExpression
       
   618 initExpression = buildExpressionParser table term <?> "initialization expression"
       
   619     where
       
   620     term = comments >> choice [
       
   621         liftM (uncurry BuiltInFunction) $ builtInFunction initExpression
       
   622         , try $ brackets pas (commaSep pas $ initExpression) >>= return . InitSet
       
   623         , try $ parens pas (commaSep pas $ initExpression) >>= \ia -> when ((notRecord $ head ia) && (null $ tail ia)) mzero >> return (InitArray ia)
       
   624         , try $ parens pas (sepEndBy recField (char' ';' >> comments)) >>= return . InitRecord
       
   625         , parens pas initExpression
       
   626         , try $ integer pas >>= \i -> notFollowedBy (char' '.') >> (return . InitNumber . show) i
       
   627         , try $ float pas >>= return . InitFloat . show
       
   628         , try $ integer pas >>= return . InitNumber . show
       
   629         , try (string' "_S" >> stringLiteral pas) >>= return . InitString
       
   630         , try (string' "_P" >> stringLiteral pas) >>= return . InitPChar
       
   631         , stringLiteral pas >>= return . InitString
       
   632         , char' '#' >> many digit >>= \c -> comments >> return (InitChar c)
       
   633         , char' '$' >> many hexDigit >>= \h -> comments >> return (InitHexNumber h)
       
   634         , char' '@' >> initExpression >>= \c -> comments >> return (InitAddress c)
       
   635         , try $ string' "nil" >> return InitNull
       
   636         , try itypeCast
       
   637         , iD >>= return . InitReference
       
   638         ]
       
   639 
       
   640     notRecord (InitRecord _) = False
       
   641     notRecord _ = True
       
   642 
       
   643     recField = do
       
   644         i <- iD
       
   645         spaces
       
   646         char' ':'
       
   647         spaces
       
   648         e <- initExpression
       
   649         spaces
       
   650         return (i ,e)
       
   651 
       
   652     table = [
       
   653           [
       
   654              Prefix (char' '-' >> return (InitPrefixOp "-"))
       
   655             ,Prefix (try (string' "not") >> return (InitPrefixOp "not"))
       
   656           ]
       
   657         , [  Infix (char' '*' >> return (InitBinOp "*")) AssocLeft
       
   658            , Infix (char' '/' >> return (InitBinOp "/")) AssocLeft
       
   659            , Infix (try (string' "div") >> return (InitBinOp "div")) AssocLeft
       
   660            , Infix (try (string' "mod") >> return (InitBinOp "mod")) AssocLeft
       
   661            , Infix (try $ string' "and" >> return (InitBinOp "and")) AssocLeft
       
   662            , Infix (try $ string' "shl" >> return (InitBinOp "shl")) AssocNone
       
   663            , Infix (try $ string' "shr" >> return (InitBinOp "shr")) AssocNone
       
   664           ]
       
   665         , [  Infix (char' '+' >> return (InitBinOp "+")) AssocLeft
       
   666            , Infix (char' '-' >> return (InitBinOp "-")) AssocLeft
       
   667            , Infix (try $ string' "or" >> return (InitBinOp "or")) AssocLeft
       
   668            , Infix (try $ string' "xor" >> return (InitBinOp "xor")) AssocLeft
       
   669           ]
       
   670         , [  Infix (try (string' "<>") >> return (InitBinOp "<>")) AssocNone
       
   671            , Infix (try (string' "<=") >> return (InitBinOp "<=")) AssocNone
       
   672            , Infix (try (string' ">=") >> return (InitBinOp ">=")) AssocNone
       
   673            , Infix (char' '<' >> return (InitBinOp "<")) AssocNone
       
   674            , Infix (char' '>' >> return (InitBinOp ">")) AssocNone
       
   675            , Infix (char' '=' >> return (InitBinOp "=")) AssocNone
       
   676           ]
       
   677         {--, [  Infix (try $ string' "and" >> return (InitBinOp "and")) AssocLeft
       
   678            , Infix (try $ string' "or" >> return (InitBinOp "or")) AssocLeft
       
   679            , Infix (try $ string' "xor" >> return (InitBinOp "xor")) AssocLeft
       
   680           ]
       
   681         , [  Infix (try $ string' "shl" >> return (InitBinOp "shl")) AssocNone
       
   682            , Infix (try $ string' "shr" >> return (InitBinOp "shr")) AssocNone
       
   683           ]--}
       
   684         --, [Prefix (try (string' "not") >> return (InitPrefixOp "not"))]
       
   685         ]
       
   686 
       
   687     itypeCast = do
       
   688         --t <- choice $ map (\s -> try $ caseInsensitiveString s >>= \i -> notFollowedBy alphaNum >> return i) knownTypes
       
   689         t <- iD
       
   690         i <- parens pas initExpression
       
   691         comments
       
   692         return $ InitTypeCast t i
       
   693 
       
   694 builtInFunction :: Parsec String u a -> Parsec String u (String, [a])
       
   695 builtInFunction e = do
       
   696     name <- choice $ map (\s -> try $ caseInsensitiveString s >>= \i -> notFollowedBy alphaNum >> return i) builtin
       
   697     spaces
       
   698     exprs <- option [] $ parens pas $ option [] $ commaSep1 pas $ e
       
   699     spaces
       
   700     return (name, exprs)
       
   701 
       
   702 systemUnit :: Parsec String u PascalUnit
       
   703 systemUnit = do
       
   704     string' "system;"
       
   705     comments
       
   706     string' "type"
       
   707     comments
       
   708     t <- typesDecl
       
   709     string' "var"
       
   710     v <- varsDecl True
       
   711     return $ System (t ++ v)
       
   712 
       
   713 redoUnit :: Parsec String u PascalUnit
       
   714 redoUnit = do
       
   715     string' "redo;"
       
   716     comments
       
   717     string' "type"
       
   718     comments
       
   719     t <- typesDecl
       
   720     string' "var"
       
   721     v <- varsDecl True
       
   722     return $ Redo (t ++ v)
       
   723