Parse_AS_Basic.hs revision 10b02b2343246df6773585636fe3ddbefa3b6a1b
{- |
Module : $Header$
Description : Parser for basic specs
Copyright : (c) Dominik Dietrich, DFKI Bremen 2010
License : similar to LGPL, see HetCATS/LICENSE.txt or LIZENZ.txt
Maintainer : dominik.dietrich@dfki.de
Stability : experimental
Portability : portable
Parser for abstract syntax for reduce computer algebra system
-}
module Reduce.Parse_AS_Basic
where
import qualified Common.AnnoState as AnnoState
import Common.Id as Id
import Common.Keywords as Keywords
import Common.Lexer as Lexer
import Common.Parsec
import Control.Monad
import Reduce.AS_BASIC_Reduce
import Reduce.Keywords
import Text.ParserCombinators.Parsec
-- the basic lexer, test using e.g. runParser identifier 0 "" "asda2_3"
-----------------------------------------------------------------------------
--------------------------- Parser for Expressions --------------------------
-----------------------------------------------------------------------------
{- | parsing of identifiers. an identifier is a letter followed by
letters, numbers, or _, but not a keyword -}
identifier :: CharParser st Id.Token
identifier = Lexer.pToken $ reserved allKeywords Lexer.scanAnyWords
-- | parser for numbers (both integers and floats) without signs
number :: CharParser st Id.Token
number = Lexer.pToken Lexer.scanFloat
expression :: CharParser st EXPRESSION
expression = do
exp1 <- factor
exps <- many $ pair (Lexer.keySign $ string "+" <|> string "-") factor
if null exps then return exp1
else return $ foldr (\ a b -> Op (fst a) [b, snd a] nullRange) exp1 exps
<|>
listexp
-- | parse a product of basic expressions
factor :: CharParser st EXPRESSION
factor = do
exp1 <- expexp
exps <- many $ pair (Lexer.keySign $ string "*" <|> string "/") factor
if null exps then return exp1
else return $ foldr (\ a b -> Op (fst a) [b, snd a] nullRange) exp1 exps
-- | parse a sequence of exponentiations
expexp :: CharParser st EXPRESSION
expexp = do
exp1 <- expatom
exps <- many $ pair (Lexer.keySign $ tryString "**" <|> string "^") expexp
if null exps then return exp1
else return $ foldr (\ a b -> Op (fst a) [b, snd a] nullRange) exp1 exps
-- | parse a basic expression
expatom :: CharParser st EXPRESSION
expatom = do
nr <- number
if isFloating nr then return (Double (read (tokStr nr)) (tokPos nr))
else return (Int (read (tokStr nr)) (tokPos nr))
<|>
do
ident <- identifier
return (Var ident)
<|>
do
oParenT
expr <- expression
cParenT
return expr
-- | parses a list expression
listexp :: CharParser st EXPRESSION
listexp = do
(Lexer.keySign (string "{"))
elems <- Lexer.separatedBy expression (Lexer.keySign (string ","))
(Lexer.keySign (string "}"))
return (List (fst elems) nullRange)
-----------------------------------------------------------------------------
---------------------------- parser for formulas ----------------------------
-----------------------------------------------------------------------------
-- | parser for atoms
truefalseFormula :: CharParser st EXPRESSION
truefalseFormula =
do
lexemeParser (Lexer.keyWord (tryString "true"))
return (Op "True" [] nullRange)
<|>
do
lexemeParser (Lexer.keyWord (tryString "false"))
return (Op "False" [] nullRange)
-- | parser for predicates
predFormula :: CharParser st EXPRESSION
predFormula =
do
exp1 <- expression
op <- Lexer.keySign $ tryString "<=" <|> tryString ">="
<|> single (oneOf "=<>")
exp2 <- expression
return (Op op [exp1,exp2] nullRange)
atomicFormula :: CharParser st EXPRESSION
atomicFormula = truefalseFormula <|> predFormula <|> parenFormula
-- | parser for formulas
aFormula :: CharParser st EXPRESSION
aFormula = try negFormula <|> impOrFormula
-- | parser for symbols followed by whitechars
lexemeParser :: CharParser st a -> CharParser st a
lexemeParser = (<< skip)
negFormula :: CharParser st EXPRESSION
negFormula = do
lexemeParser (Lexer.keyWord (tryString "not"))
f <- atomicFormula
return (Op "Not" [f] nullRange)
-- | parses a formula within brackets
parenFormula :: CharParser st EXPRESSION
parenFormula = do
oParenT
f <- aFormula
cParenT
return f
-- | parser for implications and ors (same precedence)
impOrFormula :: CharParser st EXPRESSION
impOrFormula = do
f1 <- andFormula
opfs <- many $ pair (lexemeParser $ Lexer.keyWord
$ tryString "or" <|> tryString "impl") impOrFormula
if null opfs then return f1
else return $ foldr (\ (a1,a2) b -> Op (case a1 of
"or" -> "Or"
"impl" -> "Impl"
_ -> error "impl or or expected")
[b,a2] nullRange
) f1 opfs
-- | a parser for and sequence of and formulas
andFormula :: CharParser st EXPRESSION
andFormula = do
f1 <- atomicFormula
opfs <- many $ pair (lexemeParser $ keyWord $ tryString "and") atomicFormula
if null opfs then return f1
else return $ foldr (\ a b -> (Op "And" [b, snd a] nullRange)) f1 opfs
-----------------------------------------------------------------------------
---------------------------- Parser for Commands ----------------------------
-----------------------------------------------------------------------------
formulaorexpression :: CharParser st EXPRESSION
formulaorexpression = try aFormula <|> expression
-- | parser for commands
command :: CharParser st CMD
command = do
cmd <- lexemeParser $ Lexer.keyWord $ choice $ map tryString
["solve", "simplify", "remainder", "gcd", "int", "qelim"]
oParenT
arg1 <- formulaorexpression
args <- many $ pair (lexemeParser $ string ",") formulaorexpression
cParenT
return (Cmd cmd (arg1 : map snd args))
-----------------------------------------------------------------------------
--------------------------- parser spec entries. ----------------------------
-----------------------------------------------------------------------------
-- | parser for operator declarations: example: operator a,b,c
opItem :: CharParser st OP_ITEM
opItem = do
Lexer.keySign (lexemeParser (tryString "operator"))
var1 <- identifier
vars <- many $ pair (lexemeParser $ string ",") identifier
return (Op_item (var1 : map snd vars) nullRange)
-- | Toplevel parser for basic specs
basicSpec :: AnnoState.AParser st BASIC_SPEC
basicSpec =
fmap Basic_spec (AnnoState.annosParser parseBasicItems)
<|> (Lexer.oBraceT >> Lexer.cBraceT >> return (Basic_spec []))
-- | Parser for basic items
parseBasicItems :: AnnoState.AParser st BASIC_ITEMS
parseBasicItems = parseOpDecl <|> parseAxItems
-- | parser for predicate declarations
parseOpDecl :: AnnoState.AParser st BASIC_ITEMS
parseOpDecl = fmap Op_decl opItem
-- | parser for Axiom_item
parseAxItems :: AnnoState.AParser st BASIC_ITEMS
parseAxItems = do
AnnoState.dotT
cmd <- (AnnoState.allAnnoParser command)
return $ Axiom_item cmd
-----------------------------------------------------------------------------
------------------------ parser for symbol maps etc. ------------------------
-----------------------------------------------------------------------------
-- | parsing a prop symbol
symb :: GenParser Char st SYMB
symb = fmap Symb_id identifier
-- | parsing one symbol or a mapping of one to a second symbol
symbMap :: GenParser Char st SYMB_OR_MAP
symbMap = do
s <- symb
do f <- pToken $ toKey mapsTo
t <- symb
return (Symb_map s t $ tokPos f)
<|> return (Symb s)
-- | Parse a list of comma separated symbols.
symbItems :: GenParser Char st SYMB_ITEMS
symbItems = do
(is, ps) <- symbs
return (Symb_items is $ catRange ps)
-- | parse a comma separated list of symbols
symbs :: GenParser Char st ([SYMB], [Token])
symbs = do
s <- symb
do c <- commaT `followedWith` symb
(is, ps) <- symbs
return (s:is, c:ps)
<|> return ([s], [])
-- | parse a list of symbol mappings
symbMapItems :: GenParser Char st SYMB_MAP_ITEMS
symbMapItems = do
(is, ps) <- symbMaps
return (Symb_map_items is $ catRange ps)
-- | parse a comma separated list of symbol mappings
symbMaps :: GenParser Char st ([SYMB_OR_MAP], [Token])
symbMaps = do
s <- symbMap
do c <- commaT `followedWith` symb
(is, ps) <- symbMaps
return (s:is, c:ps)
<|> return ([s], [])