module N3Parser where
import "Utils"
import "IO"
import "Interact"
{--
-- N3 parser
--------------------------------------
--
-- Author : G.Naudts E-mail : naudts_vannoten@yahoo.com
-- Address : Secretarisdreef 5 2288 Bouwel Belgium
-- The parser is based on the grammar at the back and has been token from :
-- http://2001/blindfold/sample/n3.bnf
-- and the parser uses also the structures defined in N3 primer :
-- http://www.w3.org/200/10/swap/Primer.htm
-- The output data structure consists basically of pairs
-- (id,short value, full value) . The full value gives the complete URI.
-- The tree structure of N3 is kept intact, but dummy subjects and verbs
-- are introduced where these are missing (_subject and _verb)
-- Anonymous nodes get an anonymous subject value = _T1 ... _Tn where
-- n is the index of the last anonymous node .
-- The parser is a look-ahead parser .
-- The prelude used is standard.pre .
-- When an error occurs the stream is synchronized on the next point .
-- With thanks to Mark P.Jones for his inspiring prolog interpreter .
-- Download hugs at : http://www.haskell.org/hugs
--
-- I give here a bnf of the output :
--
-- ParserOutput ::= ParsedString "End"
--
-- ParsedString ::= Triple (ParserOutput)*|
-- TripleSet (ParserOutput)*
--
-- Triple ::= "Triple" Sep Subject Verb Object
--
-- AnonTriple ::= AnonSubject Verb Object
--
-- TripleSet ::= Sep Triple* "EndOfSet" Sep
--
-- AnonSet ::= Sep AnonTriple* "EndOfSet" Sep
--
-- Subject ::= "Subject" Sep String Sep|
-- "Set" Sep TripleSet|
-- "AnonSet" Sep AnonSet
--
-- AnonSubject ::= "AnonSubject" Sep "_T" n Sep
--
-- Verb ::= "Verb" Sep String Sep|
-- "Set" Sep TripleList|
-- "AnonSet" Sep AnonSet
--
-- Object ::= "Object" Sep String Sep|
-- "ObjectSet" Sep TripleSet|
-- "AnonSet" Sep AnonSet
--
-- n ::= (digit)*
--
-- Sep ::= Separator
--
-- Prefix ::= "Prefix" Sep String Sep
--
-- The separator is defined in the source code; might be : /@/
-- The output is defined by constants that are defined in a section
-- indicated by the header : Constants .
-- _subject and _verb refer to the latest subject and verb.
-}
-- read extern permits using the parser from another module.
-- a function with type String -> IO () is passed in the call.
-- This function will be called with the parsed string as a parameter.
readExternN3 :: String -> (String -> IO ()) -> IO ()
readExternN3 fileName function =
do {s <- readFile fileName; function (n3Parser s)}
-- readN3 reads and parses a N3 file and puts the output on sysout
readN3 :: String -> IO ()
readN3 fileName = do {s <- readFile fileName; putStr (n3Parser s)}
-- saveN3 reads and parses a N3 file and saves the output in a file
-- with suffix ps
saveN3 :: String -> IO ()
saveN3 fileName = do {s <- readFile fileName;
(n3ParseAndSave s (fileName ++ ".ps"))}
-- n3ParseAndSave get an input string and starts the parsing proces with the
-- global list; first spaces are skipped; the output is put in the file
-- indicated by the second parameter.
n3ParseAndSave :: String -> String -> IO ()
n3ParseAndSave s fileName = stringToFile (filterSep
(getSecond (parseN3 (g, "", skipBlancs s)))) fileName
-- n3Parser get an input string and starts the parsing proces with the
-- global list; first spaces are skipped
n3Parser :: String -> String
n3Parser s = --filterSep (tripleToString (parseN3 (g, "", skipBlancs s)))
getSecond (parseN3 (g, "", skipBlancs s))
filterSep :: String -> String
filterSep [] = []
filterSep s@(x:xs)
| startsWith s sep = " || " ++ filterSep s1
| otherwise = x:filterSep xs
where s1 = drop 3 s
-- getsecond gets the second element from a triple
getSecond :: (a, b, c) -> b
getSecond (a, b, c) = b
-- testResult gets a parsed item; checks for errors ;
-- if error skips till the next point and
-- continues parsing ; returns the global list and the rest string
testResult :: (Globals, String, String, String) -> (Globals, String)
testResult (g, s1, s2, s3)
| startsWith s1 "Error" = (g, skipTillCharacter '.' s3)
| otherwise = (g, s3)
--main :: IO ()
--main = do interpreter p4
--interpreter :: String -> IO ()
interpreter s = do is <- getContents
putStr ((loop g1 s) is)
--loop :: Globals -> String -> String -> String
--loop g "" = end
loop g s = readLine "> " (exec g s)
--exec :: Globals -> String -> String -> Interact
exec g [] _ = writeStr "Bye" end
exec g _ [] = writeStr "Bye" end
exec g s "q" = writeStr "Bye" end
exec g s "c" = writeStr ("result: " ++ out ++ "\n") (loop g1 s1)
where (g1, out, s1) = parseSingle (g, "", s)
-- function parseSingle : top level of the parser
-- Takes the global list and a string (without leading spaces)
-- and returns a string consisting of a list of identifier-value pairs
-- separated by the separator
-- e.g. "Subject :a Verb :b Object :c"
-- parses only a single prefix definition or a triple
-- for testing !!!
parseSingle :: ParserData -> ParserData
parseSingle (g, out, "") = (g, out, "")
parseSingle (g, out, s)
| (skipBlancs s) == "" = (g, out, "")
-- skip pint
| y == '.' = parseSingle (g, out, ys)
-- parse a prefix -- no output
| y == '@' = (g2, out ++ s1 ++ sep ++ s2 ++ sep, skipBlancs s4)
-- must be a triple parse triple
| otherwise = (parseSingleTriple (g, out, sd))
where (g1, s1, s2, s3) = parsePrefix g sd
(g2, s4) = testResult (g1, s1, s2, s3)
sd@(y:ys) = skipBlancs s
-- function parseN3 : top level of the parser
-- Takes the global list and a string (without leading spaces)
-- and returns a string consisting of a list of identifier-value pairs
-- separated by the separator
-- e.g. "Subject :a Verb :b Object :c"
parseN3 :: ParserData -> ParserData
parseN3 (g, out, "") = (g, out, "")
parseN3 (g, out, s)
| (skipBlancs s) == "" = (g, out, "")
-- parse a prefix -- no output
| y == '@' = parseN3 (g2, out ++ s1 ++ sep ++ s2 ++ sep, skipBlancs s4)
-- must be a triple parse triple
| otherwise = parseN3 (parseTriple (g, out, sd))
where (g1, s1, s2, s3) = parsePrefix g sd
(g2, s4) = testResult (g1, s1, s2, s3)
sd@(y:ys) = skipBlancs s
-- test the function parseTripleSet
-- testParseTripleSet :: [ParserData]
testParseTripleSet =
stringToFile
(composedTriple testList)
"testParseTripleSet.tst"
where testList = [(g2, "", "{:a :b :c.}"),
(g2, "", "{{:a :b :c. :d :d :f} :g" ++
" {:h :i :j. :k :l :m}}"),
(g2, "", "{{:a :b :c} :d :e}"),
(g2, "", "{:a :b :c}"),
(g2, "", "{:a :b :c. :d :e :f.}"),
(g2, "", "{:: :b :c. :d :e :f."),
(g2, "", ":a :b :c."),
(g2, "", ":a is :b of :c."),
(g2, "", ":a has :b of :c."),
(g2, "", ":a :b :c")]
-- compose the output list
composedTriple [] = []
composedTriple (x:xs) = "\n\nInput:" ++ tripleToString x ++
"\n\nOutput" ++ tripleToString (parseTripleSet x)
++ composedTriple xs
-- parse a set of triples : insert "Set " and call parsePropertyList
-- Then call recusively parseTripelSet ; then insert "EndOfSet "
parseTripleSet :: ParserData -> ParserData
parseTripleSet (g, out, "") = (g, out, "")
parseTripleSet p@(g, out, s@(x:xs))
-- begin of set detected; check for end of set and call recursively
| y == '{' && bv1 = parseTripleSet (parseTriple
(g, out ++ "Set" ++ sep, skipBlancs ys))
-- '}' found - insert "EndOfSet " and return
| y == '}' = (g, out ++ "EndOfSet" ++ sep, skipBlancs ys)
-- '}' not found ==> synchronize on next point.
| y == '{' && not bv1 =
(g, "Error Missing }" ++ sep, skipTillCharacter '.' (skipBlancs ys))
-- no point found -- last statement without point or
-- something is fundamentally wrong -- return empty rest string
| y == '{' && not bv1 && not bv3 = (g, "Error Missing Point" ++ sep, "")
-- must be the next triple : parseSubject and call parsePropertyList
| otherwise = parseTripleSet (parseTriple p)
where bv1 = checkCharacter '}' ys
bv3 = checkCharacter '.' ys
s1@(y:ys) = skipBlancs s
-- parseTriple parses a singel triple
parseTriple :: ParserData -> ParserData
parseTriple (g, out, "") = (g, out, "")
parseTriple (g, out, s)
| y == '}' = (g, out, s1)
| y == '.' = (g, out, ys)
| otherwise = parseTriple (parsePropertyList (parseSubject (g, out, s1)))
where s1@(y:ys) = skipBlancs s
-- parseSingleTriple parses a singel triple -- for testing !!!
parseSingleTriple :: ParserData -> ParserData
parseSingleTriple (g, out, "") = (g, out, "")
parseSingleTriple (g, out, s)
| y == '}' = (g, out, s1)
| y == '.' = (g, out, ys)
| otherwise = (parsePropertyList (parseSubject (g, out, s1)))
where s1@(y:ys) = skipBlancs s
-- test the function parseAnonSet
-- testParseAnonSet :: [ParserData]
testParseAnonSet =
stringToFile
(composedAnon testList)
"testParseAnonSet.tst"
where testList = [(g2, "", "[:b :c.]."),
(g2, "", "[ :b :c; :e :f; :g :h, :i, :p]"),
(g2, "", "[ :b :c; :d [:e :f]; :g :h]")]
-- compose the output list
composedAnon [] = []
composedAnon (x:xs) = "\n\nInput:" ++ tripleToString x ++
"\n\nOutput" ++ tripleToString (parseAnonSet x)
++ composedAnon xs
-- parse a set of anonymous triples : insert "AnonSet "
-- and call parsePropertyList
-- Then call recusively parseAnon ; then insert "EndOfSet "
parseAnonSet :: ParserData -> ParserData
parseAnonSet (g, out, "") = (g, out, "")
parseAnonSet (g, out, s@(x:xs))
-- . found recall parsePropertyList
| x == '.' = parseAnonSet (parsePropertyList (g3, out, skipBlancs xs))
-- parse a set of anonymous triples: assign a subject
-- and then call parsePropertyList
| x == '[' && bv2 = parseAnonSet (parsePropertyList (g3, out ++
"AnonSet" ++ sep ++ "Subject" ++ sep ++ s5 ++ sep, skipBlancs xs))
-- ']' found - insert "EndOfSet " and return
| x == ']' = (g, out ++ "EndOfSet" ++ sep, skipBlancs xs)
-- '{' found call parseTripleSet
| x == '{' = parseTripleSet (g, out, s)
-- ']' not found ==> synchronize on next point.
| x == '[' && not bv2 && bv3 =
(g, "Error Missing ]", skipTillCharacter '.' (skipBlancs xs))
-- no point found -- last statement without point or
-- something is fundamentally wrong -- return empty rest string
| x == '[' && not bv2 && not bv3 = (g, "Error Missing Point", "")
-- nothing appropriate return
| otherwise = (g, out, s)
where bv2 = checkCharacter ']' xs
bv3 = checkCharacter '.' xs
(g3, s5) = createAnonSubject g
-- test the function parsePropertyList
-- testParsePropertyList :: [ParserData]
testParsePropertyList =
stringToFile
(composedProperty testList)
"testParsePropertyList.tst"
where testList = [(g2, "", ":b :c; :d :e; :f :g."),
(g2, "", ":b :c.")] --,
-- (g2, "", ":b :c; :d :e; :f :g:"),
-- (g2, "", ":a, :b,:c")]
-- compose the output list
composedProperty [] = []
composedProperty (x:xs) = "\n\nInput:" ++ tripleToString x ++
"\n\nOutput" ++ tripleToString (parsePropertyList x)
++ composedProperty xs
-- parses a verb and then calls parseNodeList
-- accumulates in second parameter
--parsePropertyList :: ParserData -> ParserData
parsePropertyList (g, out, "") = (g, out, "")
parsePropertyList (g, out, s)
-- end of propertyList
| y == '}' = (g, out, s1)
-- end of propertyList
| y == '.' = (g, out, s1)
-- end of anonymous set
| y == ']' = (g, out, s1)
-- propertylist with subject already defined
| y == ';' = parsePropertyList (parseProperty (g, out
++ "_subject" ++ sep, ys))
| otherwise = parsePropertyList (parseProperty (g, out, s1))
where s1@(y:ys) = skipBlancs s
-- parse a single property
--parseProperty :: ParserData -> ParserData
parseProperty (g, out, "") = (g, out, "")
parseProperty (g, out, s)
-- end of property
| y == '}' = (g, out, s1)
| y == ']' = (g, out, s1)
-- end of property
| y == '.' = (g, out, s1)
| otherwise = (parseNodeList (parseVerb (g, out, (skipBlancs s1))))
where s1@(y:ys) = skipBlancs s
-- test the function parseNodeList
-- testParseNodeList :: [ParserData]
testParseNodeList =
stringToFile
(composed testList)
"testParseNodeList.tst"
where testList = [(g2, "", ":a, :b,:c."),
(g2, "", ":a.")] --,
-- (g2, "", ":a"),
-- (g2, "", ":a, :b,:c")]
-- compose the output list
composed [] = []
composed (x:xs) = "\n\nInput:" ++ tripleToString x ++
"\n\nOutput" ++ tripleToString (parseNodeList x) ++ composed xs
-- display ParserData in a more or less readable format
displayTriple :: ParserData -> IO ()
displayTriple (g, out, rest) =
putStr ("\n" ++ show g ++ "\n" ++ "out: " ++ out ++ "\n" ++ "rest: " ++ rest)
-- display a list of ParserData
displayTripleList :: [ParserData] -> IO ()
displayTripleList [] = putStr "Empty list"
displayTripleList triple = putStr (tripleListToString triple)
-- transforms ParserData in string format
tripleToString :: ParserData -> String
tripleToString (g, out, rest) =
"\n\n" ++ show g ++ "\n" ++ "out: " ++ out ++ "\n" ++ "rest: " ++ rest
-- transform a list of ParserData to String
tripleListToString :: [ParserData] -> String
tripleListToString [] = []
tripleListToString (x:xs) = tripleToString x ++ tripleListToString xs
-- save a string to a file of which the name is indicated
-- by the second string
stringToFile :: String -> String -> IO ()
stringToFile s fileName = do toHandle <- openFile fileName WriteMode
hPutStr toHandle s
hClose toHandle
putStr "Done."
-- open a file for reading
openRead fileName = openFile fileName ReadMode
-- close a file
closeFile fileHandle = hClose fileHandle
-- read a complete file
readFileContents fromHandle = hGetContents fromHandle
-- parses nodes separated by , .
-- Subject and verb are retrieved from the globals .
-- parseNodeList :: ParserData -> ParserData
parseNodeList (g, out, "") = (g, out, "")
parseNodeList (g, out, s)
| y == '.' = (g, out, sd)
| y == ';' = (g, out, sd)
| y == '}' = (g, out, sd)
| y == ']' = (g, out, sd)
| y == '{' = parseNodeList (parseTripleSet (g, out, sd))
| y == '[' = parseNodeList (parseAnonSet (g, out, sd))
| y == ',' = parseNodeList (g3, out ++ "_subject" ++ sep ++ "_verb"
++ sep ++ s5 ++ sep ++ s6 ++ sep, skipBlancs s7)
| otherwise = parseNodeList (parseObject (g, out, sd))
where sd@(y:ys) = skipBlancs s
(g3, s5, s6, s7) = parseNode g ys
-- parse a subject .
--parseSubject :: ParserData -> ParserData
parseSubject (g, out, "") = (g, out, "")
parseSubject (g, out, s)
| y == '{' = parseTripleSet (g, out, sd)
| y == '[' = parseAnonSet (g, out, sd)
| otherwise = (g2, out ++ s1 ++ sep ++ s2 ++ sep, skipBlancs s4)
where (g1, s1, s2, s3) = saveSubject (parseNode g (skipBlancs sd))
(g2, s4) = testResult (g1, s1, s2, s3)
sd@(y:ys) = skipBlancs s
-- parse a verb
--parseVerb :: ParserData -> ParserData
parseVerb (g, out, "") = (g, out, "")
parseVerb (g, out, s)
| y == '{' = parseTripleSet (g,out, sd)
| y == '[' = parseAnonSet (g, out, sd)
| otherwise = (g2, out ++ "Verb" ++ sep ++ s2 ++ sep, skipBlancs s4)
where (g1, s1, s2, s3) = parseNode g (skipBlancs sd)
(g2, s4) = testResult (g1, s1, s2, s3)
sd@(y:ys) = skipBlancs s
-- parse an object
--parseObject :: ParserData -> ParserData
parseObject (g, out, "") = (g, out, "")
parseObject (g, out, s)
| y == '{' = parseTripleSet (g,out, sd)
| y == '[' = parseAnonSet (g, out, sd)
| otherwise = (g2, out ++ s1 ++ sep ++ s2 ++ sep, skipBlancs s4)
where (g1, s1, s2, s3) = saveObject (parseNode g (skipBlancs sd))
(g2, s4) = testResult (g1, s1, s2, s3)
sd@(y:ys) = skipBlancs s
-- save a subject in the global list
saveSubject :: (Globals, String, String, String) -> (Globals, String, String, String)
saveSubject (g, s1, s2, s3) = (g1, "Subject", s2, s3)
where g1 = setStringParam g "LastSubject" s2
-- save a verb in the global list
saveVerb :: (Globals, String, String, String) -> (Globals, String, String, String)
saveVerb (g, s1, s2, s3) = (g1, "Verb", s2, s3)
where g1 = setStringParam g "LastVerb" s2
-- save an object in the global list
saveObject :: (Globals, String, String, String) -> (Globals, String, String, String)
saveObject (g, s1, s2, s3) = (g1, "Object", s2, s3)
where g1 = setStringParam g "LastObject" s2
createAnonSubject :: Globals -> (Globals, String)
createAnonSubject g = (g1, s1)
where i = getIntParam g "AnonCounter"
g1 = setIntParam g "AnonCounter" (i+1)
s = "_T$$$" ++ intToString (i+1)
s1 = s ++ "/@/" ++ s
-- test the function parseNode
-- testParseNode ::
testParseNode =
stringToFile
(composeNodes testList)
"testParseNode.tst"
where testList = [ "<> :a :b",
":a :b :c .",
"@prefix dc: .",
"dc:a dc:b dc:c . { dc:ho \"oke\".}",
" dc:b dc:c . { dc:ho \"oke\".}",
";<#pat> :a :b.",
-- "<#pat> :a :b",
"\"Hallo\" dc:b dc:c . { dc:ho \"oke\".}"]
-- compose the output list
composeNodes [] = []
composeNodes (x:xs) = "\n\nInput: " ++ x ++
"\n\nOutput " ++ quadToString (parseNode g1 x)
++ composeNodes xs
-- transforms output of parseNode in string format
quadToString :: (Globals, String, String, String) -> String
quadToString (g, s1, s2, s3) =
"\n\n" ++ show g ++ "\n" ++ "item: " ++ s1 ++ " value: " ++ s2 ++
" rest: " ++ s3
-- transforms a pair (g, s) to String
pairToString :: (Globals, String) -> String
pairToString (g, s) =
"\n\n" ++ show g ++ "\n" ++ "input: " ++ s
-- function for parsing nodes
-- input are the global data and the string to be parsed
-- returns a multiple that exists of global list, a node, the value and
-- the rest string .
-- Formats of a node (=URI):
-- <#...>
-- <>
-- :...
-- prefix:...
--
-- ".." (constant)
parseNode :: Globals -> String -> (Globals, String, String, String)
parseNode g "" = (g, "", "", "")
parseNode g s
-- node in a node list
| y == ';' = parseNode g ys
-- starts with '<' Three cases : <> <#..>
| y == '<' = parseNodeLesser g ys
-- starts with '"' Constant
| y == '"' = parseConstant g ys
-- starts with ':' This refers to the parsed document
| y == ':' = parseNodeThis g ys
-- the verb is "a"
| bv1 = (g, "Object" ,"a" ++ sep ++ "rdf:type", skipBlancs ys)
-- skip "of"
| bv2 = parseNode g (skipBlancs (drop 2 sd))
-- "is" detected, insert "Inverse"
| bv3 = (g1, s1, "Inverse" ++ sep ++ s2, skipBlancs (s3))
-- "has" detected skip this
| bv4 = parseNode g (skipBlancs (drop 3 sd))
-- lonely : detected
| bv5 = (g, "Object",":" ++ sep ++ (getStringParam g ":"),
(skipBlancs (drop 1 sd)))
-- must be format : prefix:postfix The prefix must be known
| otherwise = parseNodePrefix g s
-- first skip all blancs
where sd@(y:ys) = skipBlancs s
bv1 = startsWith sd "a "
bv2 = startsWith sd "of "
bv3 = startsWith sd "is "
bv4 = startsWith sd "has "
bv5 = startsWith sd ": " -- abbreviation :
(g1, s1, s2, s3) = parseNode g (skipBlancs (drop 2 sd))
-- parse a constant
parseConstant :: Globals -> String -> (Globals, String, String, String)
parseConstant g "" = (g, "", "", "")
parseConstant g s
| bv1 = (g, "Constant", const, skipBlancs post1)
| otherwise = (g, "Error parsing constant:", "", sd)
where (bv1, const, post1) = parseUntil '"' sd
sd@(y:ys) = skipBlancs s
-- parse a node that starts with :
parseNodeThis :: Globals -> String -> (Globals, String, String, String)
parseNodeThis g "" = (g, "", "", "")
parseNodeThis g s
| bv1 = (g, "Object", ":" ++ node ++ sep ++
"<" ++ (getStringParam g "BaseURI") ++ "#" ++ node
++ ">", skipBlancs post1)
| otherwise = (g, "Error parsing :node :", "", s)
where (bv1, node, post1) = parseUntilDelim delimNode s
-- parse a node that starts with <
parseNodeLesser :: Globals -> String -> (Globals, String, String, String)
parseNodeLesser g "" = (g, "", "", "")
parseNodeLesser g s
-- case <> = the parsed document
| bv1 = (g, "Object", "<>" ++ sep ++
getStringParam g "BaseURI", post1)
-- case <#...>
| bv2 && bv3 = (g, "Object", "<#" ++ node ++ ">" ++ sep
++ getStringParam g "BaseURI" ++ "#"
++ node, post3)
-- case
| bv4 = (g, "Object", "<" ++ node1 ++ ">" ++ sep ++ node1, post4)
-- missing >
| otherwise = (g, "Error missing > :", "", s)
where (bv1, post1) = takec '>' (skipBlancs s)
(bv2, post2) = takec '#' (skipBlancs s)
(bv3, node, post3) = parseUntil '>' (skipBlancs post2)
(bv4, node1, post4) = parseUntil '>' (skipBlancs s)
-- parse a node with format prefix:postfix
parseNodePrefix :: Globals -> String -> (Globals, String, String, String)
parseNodePrefix g "" = (g, "", "", "")
parseNodePrefix g s
| bv1 && bv2 && bv3 = (g, "Object", prefix ++ ":" ++ postfix ++
sep ++ pre ++ postfix, post2)
| otherwise = (g, "Error parsing prefix:postfix : ", "", s)
where (bv1, prefix, post1) = parseUntil ':' (skipBlancs s)
(bv2, postfix, post2) = parseUntilDelim delimNode (skipBlancs post1)
pre = getStringParam g (prefix ++ ":")
bv3 = pre /= "Error"
-- function for parsing prefixes
-- input are the global data and the string to be parsed
-- returns a multiple that exists of an identifier, the value
-- the rest string and the global list.
-- format of a prefix :
-- @prefix ...:
-- the prefix is added in the global list as ("prefix","value-of-prefix");
-- the returned value = ""
parsePrefix :: Globals -> String -> (Globals, String, String, String)
parsePrefix g "" = (g, "", "", "")
parsePrefix g s
|bv1 && bv2 && bv2a && bv3 && bv4 =
(g', "Prefix", "@prefix " ++ prefix ++ ":" ++ " " ++
"<" ++ uri ++ ">.", post4)
|otherwise = (g, "Error" ++ sep, "", sd )
where (bv1, post1) = parseString "@prefix" sd
(bv2, prefix, post2 ) = parseUntil ':' (skipBlancs post1)
(bv2a, post2a) = takec '<' (skipBlancs post2)
(bv3, uri, post3) = parseUntil '>' (skipBlancs post2a)
(bv4, post4) = takec '.' (skipBlancs post3)
g' = setStringParam g (prefix ++ ":") uri -- add the prefix
-- to the global list
sd = skipBlancs s
-- ************* basic constants **************
--
g = [("BaseURI", baseURI),("AnonCounter", "0"), ("LastSubject", ""),
("LastVerb", "")]
sep = "/@/"
-- ************* --------------- **************
-- globals for testing
g2 = [("BaseURI", baseURI),("AnonCounter", "1"), ("LastSubject", "last_subject"),
("LastVerb", "last_verb")]
-- test of node parsing 1
baseURI = "http://www/w3.org"
g1 = [("BaseURI", baseURI),("dc:","http://gn.org/"),("AnonCounter", "1")]
p = "<#pat> :a :b" -- test with parseAtom g p
-- test of node parsing 2
p1 = "<> :a :b" -- test with parseAtom g p1
-- test of prefix parsing
p2 = "@prefix dc: ."
-- test of comment parseing
p2a = "# blabla \r\n @prefix dc: ."
-- test of node with :...
p3 = ":a :b :c . { dc:ho \"oke\".}"
p3a = "{ dc:ho \"oke\".}"
-- test of node with prefix:...
p4 = "dc:a dc:b dc:c . { dc:ho \"oke\".}"
-- test of node with
p5 = " dc:b dc:c . { dc:ho \"oke\".}"
-- test of node with ".." (constant)
p6 = "\"Hallo\" dc:b dc:c . { dc:ho \"oke\".}"
-- test of comment
p7 = "# ddddddd \r\n :a :b :c"
-- test of parseNodeList
p8 = ":a, :b, :c."
-- test of parsePropertyList
p9 = ":a :b; :c :d; :e :f."
-- test of tripleset
p10 = "{:a :b :c. :d :e :f.}"
p10a = ":a :b :c . :d :e :f ."
-- test of embedded triplesets
p11 = "{{:person :member :institution. " ++
":institution :w3cmember ." ++
":institution :subscribed :mailinglist} :implies "++
"{:person :authenticated :mailinglist}} a :Truth; :forAll :person, :mailinglist, :institution."
-- test of embedded aonymous sets
p11a = "[[[:member :institution; " ++
":w3cmember .]" ++
":institution [:subscribed :mailinglist]] :implies "++
"[:authenticated :mailinglist]] a :Truth."
p12 =
"# $Id: authen.axiom.n3,v 1.2 2001/10/01 00:12:34 amdus Exp $\n" ++
" \n" ++
"@prefix log: .\n" ++
"@prefix : .\n" ++
" \n" ++
" :member .\n" ++
" :w3cmember .\n" ++
" :subscribed .\n" ++
" \n" ++
"{{:person :member :institution.\n" ++
":institution :w3cmember .\n" ++
":institution :subscribed :mailinglist} log:implies\n" ++
"{:person :authenticated :mailinglist}} a log:Truth; log:forAll :person, :mailinglist, :institution.\n"
p13 =
" :member .\n" ++
" :w3cmember .\n" ++
" :subscribed .\n" ++
" \n"
p14 = "@prefix : ."
{-
-- The bnf grammar
----------------------
--#
--# Taken from
--# on 2001-08-03 (version of 2001-04-10)
--#
--# Modifications:
--#
--# $Log: n3.bnf,v $
--# Revision 1.4 2001/08/06 20:56:21 sandro
--# added space* and space+ in several places
--# removed "#" from forbidden chars in URI_Reference
--# handles comments
--# made directives actually part of the grammar (!)
--# allowed nprefix to be zero-length
--#
--# Revision 1.3 2001/08/03 13:44:43 sandro
--# filled in remaining non-terminals
--#
--# Revision 1.2 2001/08/03 13:02:48 sandro
--# standardized BNF so blindfold can compile it
--# added ::= for each rule
--# added | for branches
--# added ; at end of rule
--# added # before comments
--# put quotes around literals
--# turn hypen into underscore in identifiers
--# rename prefix to nprefix (hack around blindfold keyword for now)
--#
--# Revision 1.1 2001/08/03 12:34:38 sandro
--# added opening comments
--#
--
--
--document ::= void
-- | statementlist;
--
--space ::= " " | "\n" | "\r" | comment;
--
--comment ::= "#" [^\r\n]*;
--
--statement ::= subject space+ property_list
-- | directive
-- ;
--
--statementlist ::= (statement space* ("." space*)?)* ;
--
--subject ::= node;
--
--verb ::= ">-" prop "->" # has xxx of
-- | "<-" prop "<-" # is xxx of
-- # | operator # has operator:xxx of??? NOT IMPLMENTED
-- | prop # has xxx of -- shorthand
-- | "has" prop # has xxx of
-- | "is" prop "of" # is xxx of
-- | "a" # has rdf:type of
-- | "=" # has daml:equivaent of
-- ;
--
--prop ::= node;
--
--node ::= uri_ref2
-- | anonnode
-- | "this"
-- | node
-- ;
--
--nodelist ::= void # (used in lists)
-- | node
-- | node nodelist
-- ;
--
--anonnode ::= "[" property_list "]" # something which ...
-- | "{" statementlist "}" # the statementlist itself as a resource
-- | "(" nodelist ")" # short for eg [ n3:first node1; n3:rest [ n3:first node2; n3:rest: n3:null ]]
-- ;
--
--property_list ::= void # to allow [...].
-- | verb space+ object_list
-- | verb space+ object_list space+ ";" space+ property_list
-- | ":-" anonnode #to allow two anonymous forms to be given eg [ a :Truth; :- { :sky :color :blue } ] )
-- | ":-" anonnode ";" property_list
-- ;
--
--object_list ::= object
-- | object "," object_list
-- ;
--
--uri_ref2 ::= qname
-- | "<" URI_Reference ">"
-- ;
--
--qname ::= nprefix ":" localname; # ??? Allow omit colon when prefix void - keyword clash
--
--object ::= subject
-- | string1 # " constant-value-with-escaping "
-- | string2 # """ constant value with escaping including single or double occurences of quotes and/or newlines """
-- # well-formed-xml-element ???? legacy or structured stuff - not implemented or distinguished
-- ;
--
--directive ::= "bind" space+ nprefix ":" uri_ref2 # Namespace declartion. Trailing "#" is omitted & assumed. Obsolete.
-- | "@prefix" space+ nprefix ":" space+ uri_ref2 # Namespace declaration
-- ;
--
--# operator ::= (Not implemented)
--# + >- operator:plus ->
--# - >- operator:minus ->
--# / >- operator:slash->
--# * >- operator:star-> (etc? @@)
--
--fragid ::= alpha alphanumeric* ;
--
--alpha ::= [a-zA-Z];
--
--alphanumeric ::= alpha | [0-9] | "_";
--
--void ::= "" ; # nothing
--
--URI_Reference ::= [^{}<>]*; # short version
--
--nprefix ::= "" | ((alpha | "_") alphanumeric*);
--
--localname ::= fragid;
--
--string1 ::= '"' string1_char* '"';
--
--string1_char ::= '\\"' | [^\"] ; # should disallow some other characters, etc.
--
--string2 ::= '"""' string2_char* '"""';
--
--string2_char ::= [^"] | ([^] [^] [^"]); # something like this; need to think about it some more
--
-----------------------------------------------------------------------}