module N3Parser where import "Utils" import "IO" {-- -- 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) -- 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 -- 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/")] 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.}" -- 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 -- -----------------------------------------------------------------------}