tools/PascalParser.hs
changeset 6270 0a99f73dd8dd
parent 4353 671d66ba3af6
child 6272 a93cb9ca9fda
equal deleted inserted replaced
6269:57523ab57218 6270:0a99f73dd8dd
     1 module PascalParser where
     1 module PascalParser where
     2 
     2 
     3 import Text.ParserCombinators.Parsec
     3 import Text.ParserCombinators.Parsec
       
     4 import Text.ParserCombinators.Parsec.Expr
       
     5 import Text.ParserCombinators.Parsec.Token
       
     6 import Text.ParserCombinators.Parsec.Language
     4 import Control.Monad
     7 import Control.Monad
       
     8 import Data.Char
     5 
     9 
     6 data PascalUnit =
    10 data PascalUnit =
     7     Program Identificator Implementation FunctionBody
    11     Program Identifier Implementation
     8     | Unit Identificator Interface Implementation (Maybe Initialize) (Maybe Finalize)
    12     | Unit Identifier Interface Implementation (Maybe Initialize) (Maybe Finalize)
     9     deriving Show
    13     deriving Show
    10 
    14 
    11 data Interface = Interface Uses TypesAndVars
    15 data Interface = Interface Uses TypesAndVars
    12     deriving Show
    16     deriving Show
    13 data Implementation = Implementation Uses TypesAndVars Functions
    17 data Implementation = Implementation Uses TypesAndVars
    14     deriving Show
    18     deriving Show
    15 data Functions = Functions [Function]
    19 data Identifier = Identifier String
    16     deriving Show
    20     deriving Show
    17 data Function = Function String
    21 data TypesAndVars = TypesAndVars [TypeVarDeclaration]
    18     deriving Show
    22     deriving Show
    19 data Identificator = Identificator String
    23 data TypeVarDeclaration = TypeDeclaration TypeDecl
    20     deriving Show
    24     | ConstDeclaration String
    21 data FunctionBody = FunctionBody String
    25     | VarDeclaration String
    22     deriving Show
    26     | FunctionDeclaration Identifier Identifier (Maybe Phrase)
    23 data TypesAndVars = TypesAndVars String
    27     deriving Show
    24     deriving Show
    28 data TypeDecl = SimpleType Identifier
    25 data Initialize = Initialize Functions
    29     | RangeType Range
    26     deriving Show
    30     | ArrayDecl Range TypeDecl
    27 data Finalize = Finalize Functions
    31     deriving Show
    28     deriving Show
    32 data Range = Range Identifier    
    29 data Uses = Uses [Identificator]
    33     deriving Show
    30     deriving Show
    34 data Initialize = Initialize String
    31 
    35     deriving Show
    32 parsePascalUnit :: String -> Either ParseError PascalUnit
    36 data Finalize = Finalize String
    33 parsePascalUnit = parse pascalUnit "unit"
    37     deriving Show
    34     where
    38 data Uses = Uses [Identifier]
    35     comments = skipMany (comment >> spaces)
    39     deriving Show
    36     identificator = do
    40 data Phrase = ProcCall Identifier [Expression]
       
    41         | IfThenElse Expression Phrase (Maybe Phrase)
       
    42         | WhileCycle Expression Phrase
       
    43         | RepeatCycle Expression Phrase
       
    44         | ForCycle
       
    45         | Phrases [Phrase]
       
    46         | SwitchCase Expression [(Expression, Phrase)] (Maybe Phrase)
       
    47         | Assignment Identifier Expression
       
    48     deriving Show
       
    49 data Expression = Expression String
       
    50     | FunCall Identifier [Expression]
       
    51     | PrefixOp String Expression
       
    52     | BinOp String Expression Expression
       
    53     deriving Show
       
    54     
       
    55 
       
    56 pascalLanguageDef
       
    57     = emptyDef
       
    58     { commentStart   = "(*"
       
    59     , commentEnd     = "*)"
       
    60     , commentLine    = "//"
       
    61     , nestedComments = False
       
    62     , identStart     = letter <|> oneOf "_"
       
    63     , identLetter    = alphaNum <|> oneOf "_."
       
    64     , reservedNames  = [
       
    65             "begin", "end", "program", "unit", "interface"
       
    66             , "implementation", "and", "or", "xor", "shl"
       
    67             , "shr", "while", "do", "repeat", "until", "case", "of"
       
    68             , "type", "var", "const", "out", "array"
       
    69             , "procedure", "function"
       
    70             ]
       
    71     , reservedOpNames= [] 
       
    72     , caseSensitive  = False   
       
    73     }
       
    74     
       
    75 pas = makeTokenParser pascalLanguageDef
       
    76     
       
    77 comments = do
       
    78     spaces
       
    79     skipMany $ do
       
    80         comment
    37         spaces
    81         spaces
    38         l <- letter <|> oneOf "_"
    82 
    39         ls <- many (alphaNum <|> oneOf "_")
    83 validIdChar = alphaNum <|> oneOf "_"    
    40         spaces
    84 
    41         return $ Identificator (l:ls)
    85 pascalUnit = do
    42 
    86     comments
    43     pascalUnit = do
    87     u <- choice [program, unit]
    44         spaces
    88     comments
    45         comments
    89     return u
    46         u <- choice [program, unit]
    90 
    47         comments
    91 comment = choice [
    48         spaces
    92         char '{' >> manyTill anyChar (try $ char '}')
    49         return u
    93         , (try $ string "(*") >> manyTill anyChar (try $ string "*)")
    50 
    94         , (try $ string "//") >> manyTill anyChar (try newline)
    51     comment = choice [
    95         ]
    52             char '{' >> manyTill anyChar (try $ char '}')
    96 
    53             , string "(*" >> manyTill anyChar (try $ string "*)")
    97 unit = do
    54             , string "//" >> manyTill anyChar (try newline)
    98     name <- liftM Identifier unitName
    55             ]
    99     comments
    56 
   100     int <- interface
    57     unit = do
   101     impl <- implementation
    58         name <- unitName
   102     comments
    59         spaces
   103     return $ Unit name int impl Nothing Nothing
    60         comments
   104     where
    61         int <- string "interface" >> interface
   105         unitName = between (string "unit" >> comments) (char ';') (identifier pas)
    62         manyTill anyChar (try $ string "implementation")
   106 
    63         spaces
   107 varsDecl = do
    64         comments
   108     v <- aVarDecl `sepBy1` (char ';' >> comments)
    65         impl <- implementation
   109     char ';'
    66         return $ Unit name int impl Nothing Nothing
   110     comments
    67         where
   111     return $ VarDeclaration $ show v
    68             unitName = between (string "unit") (char ';') identificator
   112     where
    69 
   113     aVarDecl = do
    70     interface = do
   114         ids <- (try (identifier pas) >>= \i -> comments >> return (Identifier i)) `sepBy1` (char ',' >> comments)
    71         spaces
   115         char ':'
    72         comments
   116         comments
    73         u <- uses
   117         t <- typeDecl
    74         return $ Interface u (TypesAndVars "")
   118         comments
    75 
   119         return (ids, t)
    76     program = do
   120         
    77         name <- programName
   121 typeDecl = choice [
    78         spaces
   122     arrayDecl
    79         comments
   123     , rangeDecl >>= return . RangeType
    80         impl <- implementation
   124     , identifier pas >>= return . SimpleType . Identifier
    81         return $ Program name impl (FunctionBody "")
   125     ] <?> "type declaration"
    82         where
   126     where
    83             programName = between (string "program") (char ';') identificator
   127     arrayDecl = do
    84 
   128         try $ string "array"
    85     implementation = do
   129         comments
    86         u <- uses
   130         char '['
    87         manyTill anyChar (try $ string "end.")
   131         r <- rangeDecl
    88         return $ Implementation u (TypesAndVars "") (Functions [])
   132         char ']'
    89 
   133         comments
    90     uses = liftM Uses (option [] u)
   134         string "of"
    91         where
   135         comments
    92             u = do
   136         t <- typeDecl
    93                 string "uses"
   137         return $ ArrayDecl r t
    94                 spaces
   138 
    95                 u <- (identificator >>= \i -> spaces >> return i) `sepBy1` (char ',' >> spaces)
   139 rangeDecl = choice [
    96                 char ';'
   140     identifier pas >>= return . Range . Identifier
    97                 spaces
   141     ] <?> "range declaration"
    98                 return u
   142 
       
   143 typeVarDeclaration isImpl = choice [
       
   144     varSection,
       
   145     funcDecl,
       
   146     procDecl
       
   147     ]
       
   148     where
       
   149     varSection = do
       
   150         try $ string "var"
       
   151         comments
       
   152         v <- varsDecl
       
   153         return v
       
   154             
       
   155     procDecl = do
       
   156         string "procedure"
       
   157         comments
       
   158         i <- liftM Identifier $ identifier pas
       
   159         optional $ do
       
   160             char '('
       
   161             varsDecl
       
   162             char ')'
       
   163         comments
       
   164         char ';'
       
   165         b <- if isImpl then
       
   166                 do
       
   167                 comments
       
   168                 typeVarDeclaration isImpl
       
   169                 comments
       
   170                 liftM Just functionBody
       
   171                 else
       
   172                 return Nothing
       
   173         comments
       
   174         return $ FunctionDeclaration i (Identifier "") b
       
   175         
       
   176     funcDecl = do
       
   177         string "function"
       
   178         comments
       
   179         char '('
       
   180         b <- manyTill anyChar (try $ char ')')
       
   181         char ')'
       
   182         comments
       
   183         char ':'
       
   184         ret <- identifier pas
       
   185         comments
       
   186         char ';'
       
   187         b <- if isImpl then
       
   188                 do
       
   189                 comments
       
   190                 typeVarDeclaration isImpl
       
   191                 comments
       
   192                 liftM Just functionBody
       
   193                 else
       
   194                 return Nothing
       
   195         return $ FunctionDeclaration (Identifier "function") (Identifier ret) Nothing
       
   196 
       
   197 program = do
       
   198     name <- liftM Identifier programName
       
   199     comments
       
   200     impl <- implementation
       
   201     comments
       
   202     return $ Program name impl
       
   203     where
       
   204         programName = between (string "program") (char ';') (identifier pas)
       
   205 
       
   206 interface = do
       
   207     string "interface"
       
   208     comments
       
   209     u <- uses
       
   210     comments
       
   211     tv <- many (typeVarDeclaration False)
       
   212     comments
       
   213     return $ Interface u (TypesAndVars tv)
       
   214 
       
   215 implementation = do
       
   216     string "implementation"
       
   217     comments
       
   218     u <- uses
       
   219     comments
       
   220     tv <- many (typeVarDeclaration True)
       
   221     string "end."
       
   222     comments
       
   223     return $ Implementation u (TypesAndVars tv)
       
   224 
       
   225 expression = buildExpressionParser table term <?> "expression"
       
   226     where
       
   227     term = comments >> choice [
       
   228         parens pas $ expression 
       
   229         , natural pas >>= return . Expression . show
       
   230         , funCall
       
   231         ] <?> "simple expression"
       
   232 
       
   233     table = [ 
       
   234           [Infix (string "^." >> return (BinOp "^.")) AssocLeft]
       
   235         , [Prefix (string "not" >> return (PrefixOp "not"))]
       
   236         , [  Infix (char '*' >> return (BinOp "*")) AssocLeft
       
   237            , Infix (char '/' >> return (BinOp "/")) AssocLeft
       
   238            ]
       
   239         , [  Infix (char '+' >> return (BinOp "+")) AssocLeft
       
   240            , Infix (char '-' >> return (BinOp "-")) AssocLeft
       
   241            ]
       
   242         , [  Infix (try (string "<>" )>> return (BinOp "<>")) AssocNone
       
   243            , Infix (try (string "<=") >> return (BinOp "<=")) AssocNone
       
   244            , Infix (try (string ">=") >> return (BinOp ">=")) AssocNone
       
   245            , Infix (char '<' >> return (BinOp "<")) AssocNone
       
   246            , Infix (char '>' >> return (BinOp ">")) AssocNone
       
   247            , Infix (char '=' >> return (BinOp "=")) AssocNone
       
   248            ]
       
   249         , [  Infix (try $ string "and" >> return (BinOp "and")) AssocNone
       
   250            , Infix (try $ string "or" >> return (BinOp "or")) AssocNone
       
   251            , Infix (try $ string "xor" >> return (BinOp "xor")) AssocNone
       
   252            ]
       
   253         ]
       
   254     
       
   255 phrasesBlock = do
       
   256     try $ string "begin"
       
   257     comments
       
   258     p <- manyTill phrase (try $ string "end")
       
   259     comments
       
   260     return $ Phrases p
       
   261     
       
   262 phrase = do
       
   263     o <- choice [
       
   264         phrasesBlock
       
   265         , ifBlock
       
   266         , whileCycle
       
   267         , switchCase
       
   268         , try $ identifier pas >>= \i -> string ":=" >> expression >>= return . Assignment (Identifier i)
       
   269         , procCall
       
   270         ]
       
   271     optional $ char ';'
       
   272     comments
       
   273     return o
       
   274 
       
   275 ifBlock = do
       
   276     try $ string "if"
       
   277     comments
       
   278     e <- expression
       
   279     comments
       
   280     string "then"
       
   281     comments
       
   282     o1 <- phrase
       
   283     comments
       
   284     o2 <- optionMaybe $ do
       
   285         try $ string "else"
       
   286         comments
       
   287         o <- phrase
       
   288         comments
       
   289         return o
       
   290     optional $ char ';'
       
   291     return $ IfThenElse e o1 o2
       
   292 
       
   293 whileCycle = do
       
   294     try $ string "while"
       
   295     comments
       
   296     e <- expression
       
   297     comments
       
   298     string "do"
       
   299     comments
       
   300     o <- phrase
       
   301     optional $ char ';'
       
   302     return $ WhileCycle e o
       
   303 
       
   304 switchCase = do
       
   305     try $ string "case"
       
   306     comments
       
   307     e <- expression
       
   308     comments
       
   309     string "of"
       
   310     comments
       
   311     cs <- many1 aCase
       
   312     o2 <- optionMaybe $ do
       
   313         try $ string "else"
       
   314         comments
       
   315         o <- phrase
       
   316         comments
       
   317         return o
       
   318     string "end"
       
   319     optional $ char ';'
       
   320     return $ SwitchCase e cs o2
       
   321     where
       
   322     aCase = do
       
   323         e <- expression
       
   324         comments
       
   325         char ':'
       
   326         comments
       
   327         p <- phrase
       
   328         comments
       
   329         return (e, p)
       
   330     
       
   331 procCall = do
       
   332     i <- liftM Identifier $ identifier pas
       
   333     p <- option [] $ (parens pas) parameters
       
   334     return $ ProcCall i p
       
   335 
       
   336 funCall = do
       
   337     i <- liftM Identifier $ identifier pas
       
   338     p <- option [] $ (parens pas) parameters
       
   339     return $ FunCall i p
       
   340 
       
   341 parameters = expression `sepBy` (char ',' >> comments)
       
   342         
       
   343 functionBody = do
       
   344     p <- phrasesBlock
       
   345     char ';'
       
   346     comments
       
   347     return p
       
   348 
       
   349 uses = liftM Uses (option [] u)
       
   350     where
       
   351         u = do
       
   352             string "uses"
       
   353             comments
       
   354             u <- (identifier pas >>= \i -> comments >> return (Identifier i)) `sepBy1` (char ',' >> comments)
       
   355             char ';'
       
   356             comments
       
   357             return u