--                            -*- Mode: Haskell -*- 
-- Copyright 1994 by Peter Thiemann
-- EbnfGrammar.hs --- a simple combinator parser for a grammar in EBNF 
-- Author          : Peter Thiemann
-- Created On      : Tue Aug  3 10:30:03 1993
-- Last Modified By: Peter Thiemann
-- Last Modified On: Mon Dec 27 17:41:17 1993
-- Update Count    : 13
-- Status          : Unknown, Use with caution!
-- 
--------------------------------------------------
-- $Log: EbnfGrammar.hs,v $
-- Revision 1.1  2004/08/05 11:11:57  malcolm
-- Add a regression testsuite for the nhc98 compiler.  It isn't very good,
-- but it is better than nothing.  I've been using it for about four years
-- on nightly builds, so it's about time it entered the repository!  It
-- includes a slightly altered version of the nofib suite.
-- Instructions are in the README.
--
-- Revision 1.1  1996/01/08 20:02:34  partain
-- Initial revision
--
-- Revision 1.3  1994/03/15  15:34:53  thiemann
-- added full color support, XColorDB based
--
--Revision 1.2  1993/08/31  12:31:32  thiemann
--reflect changes in type FONT
--
--Revision 1.1  1993/08/17  12:34:29  thiemann
--Initial revision
--
-- $Locker:  $
--------------------------------------------------

module EbnfGrammar (parseAll) where

import Parsers
import Lexer
import AbstractSyntax

parseAll s = [ prod | (prod, []) <- parseFile (lexer (uncomment s)) ]

-- This is the grammar for EBNF
--	File		= {Production}.
--	Production	= Nonterminal [ String ] "=" Term "." .
--	Term		= Factor / "|" .		# alternative
--	Factor		= ExtAtom + .			# sequence
--	ExtAtom		= Atom
--			| Atom "/" Atom			# repetion through Atom
--			| Atom "+".			# at least one repetion
--	Atom		= Nonterminal
--			| String			# terminal string
--			| "(" Term ")"
--			| "[" Term "]"			# an optional Term
--			| "{" Term "}"			# zero or more repetions
--			.
--	String		= "\"" { character } "\"" .
--	Nonterminal	= letter { letter | digit | "_" } .
--	character	= "\\" charesc.

parseFile =		rpt parseProduction		    -- no longer `using` ProdFile

parseProduction =	(satisfy isIdent `thn`
			opt (satisfy isString) `thn`
			expectSymbol "=" `xthn`
			parseTerm `thnx`
			expectSymbol ".") `using`
			\(nt, (ntNames, term)) -> ProdProduction (getIdent nt) (map getString ntNames) term 

parseTerm =		(parseFactor `thn`
			rpt (expectSymbol "|" `xthn` parseFactor))
			`using2` (:) `using` ProdTerm

parseFactor =		(parseExtendedAtom `thn` rpt parseExtendedAtom)
			`using2` (:) `using` ProdFactor

parseExtendedAtom =     parseAtom `thn`
			opt ((expectSymbol "+" `using` \ _ -> ProdPlus)
			     `alt`
			     (expectSymbol "/" `xthn` parseAtom `using` ProdSlash))
				`using2` helper
			where
			helper term [] = term
			helper term [ProdPlus] = ProdRepeat1 term
			helper term [ProdSlash atom] = ProdRepeatWithAtom term atom

parseAtom =		(expectSymbol "(" `xthn`
			parseTerm `thnx`
			expectSymbol ")")
			`alt`
			((expectSymbol "[" `xthn` parseTerm `thnx` expectSymbol "]")
				`using` ProdOption)
			`alt`
			((expectSymbol "{" `xthn` parseTerm `thnx` expectSymbol "}")
				`using` ProdRepeat)
			`alt`
			(satisfy isIdent `using` (ProdNonterminal . getIdent))
			`alt`
			(satisfy isString `using` (ProdTerminal . getString))

expectSymbol c = satisfy test
	where test (Symbol x) = c == x
	      test _ = False
