diff options
Diffstat (limited to 'examples')
| -rw-r--r-- | examples/model/Lex.gf | 8 | ||||
| -rw-r--r-- | examples/model/LexEng.gf | 8 | ||||
| -rw-r--r-- | examples/model/LexFre.gf | 8 | ||||
| -rw-r--r-- | examples/model/Makefile | 17 | ||||
| -rw-r--r-- | examples/model/Math.gf | 11 | ||||
| -rw-r--r-- | examples/model/MathEng.gf | 7 | ||||
| -rw-r--r-- | examples/model/MathFre.gf | 7 | ||||
| -rw-r--r-- | examples/model/MathI.gf | 16 | ||||
| -rw-r--r-- | examples/model/Run.hs | 33 | ||||
| -rw-r--r-- | examples/model/model-resource-app.html | 382 | ||||
| -rw-r--r-- | examples/model/model-resource-app.txt | 301 |
11 files changed, 798 insertions, 0 deletions
diff --git a/examples/model/Lex.gf b/examples/model/Lex.gf new file mode 100644 index 000000000..61ba2586c --- /dev/null +++ b/examples/model/Lex.gf @@ -0,0 +1,8 @@ +interface Lex = open Grammar in { + + oper + even_A : A ; + odd_A : A ; + zero_PN : PN ; + +}
\ No newline at end of file diff --git a/examples/model/LexEng.gf b/examples/model/LexEng.gf new file mode 100644 index 000000000..4808557ef --- /dev/null +++ b/examples/model/LexEng.gf @@ -0,0 +1,8 @@ +instance LexEng of Lex = open GrammarEng, ParadigmsEng in { + + oper + even_A = regA "even" ; + odd_A = regA "odd" ; + zero_PN = regPN "zero" ; + +} diff --git a/examples/model/LexFre.gf b/examples/model/LexFre.gf new file mode 100644 index 000000000..6b439f9b8 --- /dev/null +++ b/examples/model/LexFre.gf @@ -0,0 +1,8 @@ +instance LexFre of Lex = open GrammarFre, ParadigmsFre in { + + oper + even_A = regA "pair" ; + odd_A = regA "impair" ; + zero_PN = regPN "zéro" ; + +} diff --git a/examples/model/Makefile b/examples/model/Makefile new file mode 100644 index 000000000..e551142ac --- /dev/null +++ b/examples/model/Makefile @@ -0,0 +1,17 @@ +all: gf hs run + +gf: + echo "pm | wf math.gfcm" | gf MathEng.gf MathFre.gf + +hs: gf + echo "pg -printer=haskell | wf GSyntax.hs" | gf math.gfcm + +run: hs + ghc --make -o math Run.hs + +clean: + rm -f *.gfc *.gfr *.o *.hi + +distclean: + rm -f GSyntax.hs math math.gfcm *.gfc *.gfr *.o *.hi + diff --git a/examples/model/Math.gf b/examples/model/Math.gf new file mode 100644 index 000000000..036cab294 --- /dev/null +++ b/examples/model/Math.gf @@ -0,0 +1,11 @@ +abstract Math = { + + cat Prop ; Elem ; + + fun + And : Prop -> Prop -> Prop ; + Even : Elem -> Prop ; + Odd : Elem -> Prop ; + Zero : Elem ; + +} diff --git a/examples/model/MathEng.gf b/examples/model/MathEng.gf new file mode 100644 index 000000000..fcba8851b --- /dev/null +++ b/examples/model/MathEng.gf @@ -0,0 +1,7 @@ +--# -path=.:api:present:prelude:mathematical + +concrete MathEng of Math = MathI with + (Grammar = GrammarEng), + (Combinators = CombinatorsEng), + (Predication = PredicationEng), + (Lex = LexEng) ; diff --git a/examples/model/MathFre.gf b/examples/model/MathFre.gf new file mode 100644 index 000000000..87575ba06 --- /dev/null +++ b/examples/model/MathFre.gf @@ -0,0 +1,7 @@ +--# -path=.:api:present:prelude:mathematical + +concrete MathFre of Math = MathI with + (Grammar = GrammarFre), + (Combinators = CombinatorsFre), + (Predication = PredicationFre), + (Lex = LexFre) ; diff --git a/examples/model/MathI.gf b/examples/model/MathI.gf new file mode 100644 index 000000000..7acf0f895 --- /dev/null +++ b/examples/model/MathI.gf @@ -0,0 +1,16 @@ +incomplete concrete MathI of Math = + open Grammar, Combinators, Predication, Lex in { + + flags startcat = Prop ; + + lincat + Prop = S ; + Elem = NP ; + + lin + And x y = coord and_Conj x y ; + Even x = PosCl (pred even_A x) ; + Odd x = PosCl (pred odd_A x) ; + Zero = UsePN zero_PN ; + +} diff --git a/examples/model/Run.hs b/examples/model/Run.hs new file mode 100644 index 000000000..fa0cc8792 --- /dev/null +++ b/examples/model/Run.hs @@ -0,0 +1,33 @@ +module Main where + +import GSyntax +import GF.Embed.EmbedAPI + +main :: IO () +main = do + gr <- file2grammar "math.gfcm" + loop gr + +loop :: MultiGrammar -> IO () +loop gr = do + s <- getLine + interpret gr s + loop gr + +interpret :: MultiGrammar -> String -> IO () +interpret gr s = do + let tss = parseAll gr "Prop" s + case (concat tss) of + [] -> putStrLn "no parse" + t:_ -> print $ answer $ fg t + +answer :: GProp -> Bool +answer p = case p of + (GOdd x1) -> odd (value x1) + (GEven x1) -> even (value x1) + (GAnd x1 x2) -> answer x1 && answer x2 + +value :: GElem -> Int +value e = case e of + GZero -> 0 + diff --git a/examples/model/model-resource-app.html b/examples/model/model-resource-app.html new file mode 100644 index 000000000..a9edfc44b --- /dev/null +++ b/examples/model/model-resource-app.html @@ -0,0 +1,382 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> +<HTML> +<HEAD> +<META NAME="generator" CONTENT="http://txt2tags.sf.net"> +<TITLE>A Tutorial on Resource Grammar Applications</TITLE> +</HEAD><BODY BGCOLOR="white" TEXT="black"> +<P ALIGN="center"><CENTER><H1>A Tutorial on Resource Grammar Applications</H1> +<FONT SIZE="4"> +<I>Aarne Ranta</I><BR> +28 February 2007 +</FONT></CENTER> + +<P></P> +<HR NOSHADE SIZE=1> +<P></P> + <UL> + <LI><A HREF="#toc1">Writing GF grammars</A> + <UL> + <LI><A HREF="#toc2">Creating the first grammar</A> + <LI><A HREF="#toc3">Testing</A> + <LI><A HREF="#toc4">Adding a new language</A> + <LI><A HREF="#toc5">Extending the language</A> + </UL> + <LI><A HREF="#toc6">Building a user program</A> + <UL> + <LI><A HREF="#toc7">Producing a compiled grammar package</A> + <LI><A HREF="#toc8">Writing the Haskell application</A> + <LI><A HREF="#toc9">Compiling the Haskell grammar</A> + <LI><A HREF="#toc10">Building a distribution</A> + <LI><A HREF="#toc11">Using a Makefile</A> + </UL> + </UL> + +<P></P> +<HR NOSHADE SIZE=1> +<P></P> +<P> +In this directory, we have a minimal resource grammar +application whose architecture scales up to much +larger applications. The application is run from the +shell by the command +</P> +<PRE> + math +</PRE> +<P> +whereafter it reads user input in English and French. +To each input line, it answers by the truth value of +the sentence. +</P> +<PRE> + ./math + zéro est pair + True + zero is odd + False + zero is even and zero is odd + False +</PRE> +<P> +The source of the application consists of the following +files: +</P> +<PRE> + LexEng.gf -- English instance of Lex + LexFre.gf -- French instance of Lex + Lex.gf -- lexicon interface + Makefile -- a makefile + MathEng.gf -- English instantiation of MathI + MathFre.gf -- French instantiation of MathI + Math.gf -- abstract syntax + MathI.gf -- concrete syntax functor for Math + Run.hs -- Haskell Main module +</PRE> +<P> +The system was built in 22 steps explained below. +</P> +<A NAME="toc1"></A> +<H2>Writing GF grammars</H2> +<A NAME="toc2"></A> +<H3>Creating the first grammar</H3> +<P> +1. Write <CODE>Math.gf</CODE>, which defines what you want to say. +</P> +<PRE> + abstract Math = { + + cat Prop ; Elem ; + + fun + And : Prop -> Prop -> Prop ; + Even : Elem -> Prop ; + Zero : Elem ; + + } +</PRE> +<P> +2. Write <CODE>Lex.gf</CODE>, which defines which language-dependent +parts are needed in the concrete syntax. These are mostly +words (lexicon), but can in fact be any operations. The definitions +only use resource abstract syntax, which is opened. +</P> +<PRE> + interface Lex = open Grammar in { + + oper + even_A : A ; + zero_PN : PN ; + + } +</PRE> +<P> +3. Write <CODE>LexEng.gf</CODE>, the English implementation of <CODE>Lex.gf</CODE> +This module uses English resource libraries. +</P> +<PRE> + instance LexEng of Lex = open GrammarEng, ParadigmsEng in { + + oper + even_A = regA "even" ; + zero_PN = regPN "zero" ; + + } +</PRE> +<P> +4. Write <CODE>MathI.gf</CODE>, a language-independent concrete syntax of +<CODE>Math.gf</CODE>. It opens interfaces can resource abstract syntaxes, +which makes it an incomplete module, aka. parametrized module, aka. +functor. +</P> +<PRE> + incomplete concrete MathI of Math = + open Grammar, Combinators, Predication, Lex in { + + flags startcat = Prop ; + + lincat + Prop = S ; + Elem = NP ; + + lin + And x y = coord and_Conj x y ; + Even x = PosCl (pred even_A x) ; + Zero = UsePN zero_PN ; + } +</PRE> +<P> +5. Write <CODE>MathEng.gf</CODE>, which is just an instatiation of <CODE>MathI.gf</CODE>, +replacing the interfaces by their English instances. This is the module +that will be used as a top module in GF, so it contains a path to +the libraries. +</P> +<PRE> + --# -path=.:api:present:prelude:mathematical + + concrete MathEng of Math = MathI with + (Grammar = GrammarEng), + (Combinators = CombinatorsEng), + (Predication = PredicationEng), + (Lex = LexEng) ; +</PRE> +<P></P> +<A NAME="toc3"></A> +<H3>Testing</H3> +<P> +6. Test the grammar in GF by random generation and parsing. +</P> +<PRE> + $ gf + > i MathEng.gf + > gr -tr | l -tr | p + And (Even Zero) (Even Zero) + zero is evenand zero is even + And (Even Zero) (Even Zero) +</PRE> +<P> +When importing the grammar, you will fail if you haven't +</P> +<UL> +<LI>correctly defined your <CODE>GF_LIB_PATH</CODE> as <CODE>GF/lib</CODE> +<LI>compiled the resourcec by <CODE>make</CODE> in <CODE>GF/lib/resource-1.0</CODE> +</UL> + +<A NAME="toc4"></A> +<H3>Adding a new language</H3> +<P> +7. Now it is time to add a new language. Write a French lexicon <CODE>LexFre.gf</CODE>: +</P> +<PRE> + instance LexFre of Lex = open GrammarFre, ParadigmsFre in { + + oper + even_A = regA "pair" ; + zero_PN = regPN "zéro" ; + } +</PRE> +<P> +8. You also need a French concrete syntax, <CODE>MathFre.gf</CODE>: +</P> +<PRE> + --# -path=.:api:present:prelude:mathematical + + concrete MathFre of Math = MathI with + (Grammar = GrammarFre), + (Combinators = CombinatorsFre), + (Predication = PredicationFre), + (Lex = LexFre) ; +</PRE> +<P> +9. This time, you can test multilingual generation: +</P> +<PRE> + > i MathFre.gf + > gr -tr | l -multi + Even Zero + zéro est pair + zero is even +</PRE> +<P></P> +<A NAME="toc5"></A> +<H3>Extending the language</H3> +<P> +10. You want to add a predicate saying that a number is odd. +It is first added to <CODE>Math.gf</CODE>: +</P> +<PRE> + fun Odd : Elem -> Prop ; +</PRE> +<P> +11. You need a new word in <CODE>Lex.gf</CODE>. +</P> +<PRE> + oper odd_A : A ; +</PRE> +<P> +12. Then you can give a language-independent concrete syntax in +<CODE>MathI.gf</CODE>: +</P> +<PRE> + lin Odd x = PosCl (pred odd_A x) ; +</PRE> +<P> +13. The new word is implemented in <CODE>LexEng.gf</CODE>. +</P> +<PRE> + oper odd_A = regA "odd" ; +</PRE> +<P> +14. The new word is implemented in <CODE>LexFre.gf</CODE>. +</P> +<PRE> + oper odd_A = regA "impair" ; +</PRE> +<P> +15. Now you can test with the extended lexicon. First empty +the environment to get rid of the old abstract syntax, then +import the new versions of the grammars. +</P> +<PRE> + > e + > i MathEng.gf + > i MathFre.gf + > gr -tr | l -multi + And (Odd Zero) (Even Zero) + zéro est impair et zéro est pair + zero is odd and zero is even +</PRE> +<P></P> +<A NAME="toc6"></A> +<H2>Building a user program</H2> +<A NAME="toc7"></A> +<H3>Producing a compiled grammar package</H3> +<P> +16. Your grammar is going to be used by persons wh<CODE>MathEng.gf</CODE>o do not need +to compile it again. They may not have access to the resource library, +either. Therefore it is advisable to produce a multilingual grammar +package in a single file. We call this package <CODE>math.gfcm</CODE> and +produce it, when we have <CODE>MathEng.gf</CODE> and +<CODE>MathEng.gf</CODE> in the GF state, by the command +</P> +<PRE> + > pm | wf math.gfcm +</PRE> +<P></P> +<A NAME="toc8"></A> +<H3>Writing the Haskell application</H3> +<P> +17. Write the Haskell main file <CODE>Run.hs</CODE>. It uses the <CODE>EmbeddedAPI</CODE> +module defining some basic functionalities such as parsing. +The answer is produced by an interpreter of trees returned by the parser. +</P> +<PRE> + module Main where + + import GSyntax + import GF.Embed.EmbedAPI + + main :: IO () + main = do + gr <- file2grammar "math.gfcm" + loop gr + + loop :: MultiGrammar -> IO () + loop gr = do + s <- getLine + interpret gr s + loop gr + + interpret :: MultiGrammar -> String -> IO () + interpret gr s = do + let tss = parseAll gr "Prop" s + case (concat tss) of + [] -> putStrLn "no parse" + t:_ -> print $ answer $ fg t + + answer :: GProp -> Bool + answer p = case p of + (GOdd x1) -> odd (value x1) + (GEven x1) -> even (value x1) + (GAnd x1 x2) -> answer x1 && answer x2 + + value :: GElem -> Int + value e = case e of + GZero -> 0 +</PRE> +<P></P> +<P> +18. The syntax trees manipulated by the interpreter are not raw +GF trees, but objects of the Haskell datatype <CODE>GProp</CODE>. +From any GF grammar, a file <CODE>GFSyntax.hs</CODE> with +datatypes corresponding to its abstract +syntax can be produced by the command +</P> +<PRE> + > pg -printer=haskell | wf GSyntax.hs +</PRE> +<P> +The module also defines the overloaded functions +<CODE>gf</CODE> and <CODE>fg</CODE> for translating from these types to +raw trees and back. +</P> +<A NAME="toc9"></A> +<H3>Compiling the Haskell grammar</H3> +<P> +19. Before compiling <CODE>Run.hs</CODE>, you must check that the +embedded GF modules are found. The easiest way to do this +is by two symbolic links to your GF source directories: +</P> +<PRE> + $ ln -s /home/aarne/GF/src/GF + $ ln -s /home/aarne/GF/src/Transfer/ +</PRE> +<P></P> +<P> +20. Now you can run the GHC Haskell compiler to produce the program. +</P> +<PRE> + $ ghc --make -o math Run.hs +</PRE> +<P> +The program can be tested with the command <CODE>./math</CODE>. +</P> +<A NAME="toc10"></A> +<H3>Building a distribution</H3> +<P> +21. For a stand-alone binary-only distribution, only +the two files <CODE>math</CODE> and <CODE>math.gfcm</CODE> are needed. +For a source distribution, the files mentioned in +the beginning of this documents are needed. +</P> +<A NAME="toc11"></A> +<H3>Using a Makefile</H3> +<P> +22. As a part of the source distribution, a <CODE>Makefile</CODE> is +essential. The <CODE>Makefile</CODE> is also useful when developing the +application. It should always be possible to build an executable +from source by typing <CODE>make</CODE>. +</P> + +<!-- html code generated by txt2tags 2.3 (http://txt2tags.sf.net) --> +<!-- cmdline: txt2tags -thtml -\-toc model-resource-app.txt --> +</BODY></HTML> diff --git a/examples/model/model-resource-app.txt b/examples/model/model-resource-app.txt new file mode 100644 index 000000000..0678950a0 --- /dev/null +++ b/examples/model/model-resource-app.txt @@ -0,0 +1,301 @@ +A Tutorial on Resource Grammar Applications +Aarne Ranta +28 February 2007 + + + +In this directory, we have a minimal resource grammar +application whose architecture scales up to much +larger applications. The application is run from the +shell by the command +``` + math +``` +whereafter it reads user input in English and French. +To each input line, it answers by the truth value of +the sentence. +``` + ./math + zéro est pair + True + zero is odd + False + zero is even and zero is odd + False +``` +The source of the application consists of the following +files: +``` + LexEng.gf -- English instance of Lex + LexFre.gf -- French instance of Lex + Lex.gf -- lexicon interface + Makefile -- a makefile + MathEng.gf -- English instantiation of MathI + MathFre.gf -- French instantiation of MathI + Math.gf -- abstract syntax + MathI.gf -- concrete syntax functor for Math + Run.hs -- Haskell Main module +``` +The system was built in 22 steps explained below. + + + +==Writing GF grammars== + +===Creating the first grammar=== + +1. Write ``Math.gf``, which defines what you want to say. +``` +abstract Math = { + + cat Prop ; Elem ; + + fun + And : Prop -> Prop -> Prop ; + Even : Elem -> Prop ; + Zero : Elem ; + +} +``` +2. Write ``Lex.gf``, which defines which language-dependent +parts are needed in the concrete syntax. These are mostly +words (lexicon), but can in fact be any operations. The definitions +only use resource abstract syntax, which is opened. +``` +interface Lex = open Grammar in { + + oper + even_A : A ; + zero_PN : PN ; + +} +``` +3. Write ``LexEng.gf``, the English implementation of ``Lex.gf`` +This module uses English resource libraries. +``` +instance LexEng of Lex = open GrammarEng, ParadigmsEng in { + + oper + even_A = regA "even" ; + zero_PN = regPN "zero" ; + +} +``` +4. Write ``MathI.gf``, a language-independent concrete syntax of +``Math.gf``. It opens interfaces can resource abstract syntaxes, +which makes it an incomplete module, aka. parametrized module, aka. +functor. +``` +incomplete concrete MathI of Math = + open Grammar, Combinators, Predication, Lex in { + + flags startcat = Prop ; + + lincat + Prop = S ; + Elem = NP ; + + lin + And x y = coord and_Conj x y ; + Even x = PosCl (pred even_A x) ; + Zero = UsePN zero_PN ; +} +``` +5. Write ``MathEng.gf``, which is just an instatiation of ``MathI.gf``, +replacing the interfaces by their English instances. This is the module +that will be used as a top module in GF, so it contains a path to +the libraries. +``` +--# -path=.:api:present:prelude:mathematical + +concrete MathEng of Math = MathI with + (Grammar = GrammarEng), + (Combinators = CombinatorsEng), + (Predication = PredicationEng), + (Lex = LexEng) ; +``` + +===Testing=== + +6. Test the grammar in GF by random generation and parsing. +``` + $ gf + > i MathEng.gf + > gr -tr | l -tr | p + And (Even Zero) (Even Zero) + zero is evenand zero is even + And (Even Zero) (Even Zero) +``` +When importing the grammar, you will fail if you haven't +- correctly defined your ``GF_LIB_PATH`` as ``GF/lib`` +- compiled the resourcec by ``make`` in ``GF/lib/resource-1.0`` + + +===Adding a new language=== + +7. Now it is time to add a new language. Write a French lexicon ``LexFre.gf``: +``` +instance LexFre of Lex = open GrammarFre, ParadigmsFre in { + + oper + even_A = regA "pair" ; + zero_PN = regPN "zéro" ; +} +``` +8. You also need a French concrete syntax, ``MathFre.gf``: +``` +--# -path=.:api:present:prelude:mathematical + +concrete MathFre of Math = MathI with + (Grammar = GrammarFre), + (Combinators = CombinatorsFre), + (Predication = PredicationFre), + (Lex = LexFre) ; +``` +9. This time, you can test multilingual generation: +``` + > i MathFre.gf + > gr -tr | l -multi + Even Zero + zéro est pair + zero is even +``` + +===Extending the language=== + +10. You want to add a predicate saying that a number is odd. +It is first added to ``Math.gf``: +``` + fun Odd : Elem -> Prop ; +``` +11. You need a new word in ``Lex.gf``. +``` + oper odd_A : A ; +``` +12. Then you can give a language-independent concrete syntax in +``MathI.gf``: +``` + lin Odd x = PosCl (pred odd_A x) ; +``` +13. The new word is implemented in ``LexEng.gf``. +``` + oper odd_A = regA "odd" ; +``` +14. The new word is implemented in ``LexFre.gf``. +``` + oper odd_A = regA "impair" ; +``` +15. Now you can test with the extended lexicon. First empty +the environment to get rid of the old abstract syntax, then +import the new versions of the grammars. +``` + > e + > i MathEng.gf + > i MathFre.gf + > gr -tr | l -multi + And (Odd Zero) (Even Zero) + zéro est impair et zéro est pair + zero is odd and zero is even +``` + +==Building a user program== + +===Producing a compiled grammar package=== + +16. Your grammar is going to be used by persons wh``MathEng.gf``o do not need +to compile it again. They may not have access to the resource library, +either. Therefore it is advisable to produce a multilingual grammar +package in a single file. We call this package ``math.gfcm`` and +produce it, when we have ``MathEng.gf`` and +``MathEng.gf`` in the GF state, by the command +``` + > pm | wf math.gfcm +``` + + +===Writing the Haskell application=== + +17. Write the Haskell main file ``Run.hs``. It uses the ``EmbeddedAPI`` +module defining some basic functionalities such as parsing. +The answer is produced by an interpreter of trees returned by the parser. +``` +module Main where + +import GSyntax +import GF.Embed.EmbedAPI + +main :: IO () +main = do + gr <- file2grammar "math.gfcm" + loop gr + +loop :: MultiGrammar -> IO () +loop gr = do + s <- getLine + interpret gr s + loop gr + +interpret :: MultiGrammar -> String -> IO () +interpret gr s = do + let tss = parseAll gr "Prop" s + case (concat tss) of + [] -> putStrLn "no parse" + t:_ -> print $ answer $ fg t + +answer :: GProp -> Bool +answer p = case p of + (GOdd x1) -> odd (value x1) + (GEven x1) -> even (value x1) + (GAnd x1 x2) -> answer x1 && answer x2 + +value :: GElem -> Int +value e = case e of + GZero -> 0 +``` + +18. The syntax trees manipulated by the interpreter are not raw +GF trees, but objects of the Haskell datatype ``GProp``. +From any GF grammar, a file ``GFSyntax.hs`` with +datatypes corresponding to its abstract +syntax can be produced by the command +``` + > pg -printer=haskell | wf GSyntax.hs +``` +The module also defines the overloaded functions +``gf`` and ``fg`` for translating from these types to +raw trees and back. + + +===Compiling the Haskell grammar=== + +19. Before compiling ``Run.hs``, you must check that the +embedded GF modules are found. The easiest way to do this +is by two symbolic links to your GF source directories: +``` + $ ln -s /home/aarne/GF/src/GF + $ ln -s /home/aarne/GF/src/Transfer/ +``` + +20. Now you can run the GHC Haskell compiler to produce the program. +``` + $ ghc --make -o math Run.hs +``` +The program can be tested with the command ``./math``. + + +===Building a distribution=== + +21. For a stand-alone binary-only distribution, only +the two files ``math`` and ``math.gfcm`` are needed. +For a source distribution, the files mentioned in +the beginning of this documents are needed. + + +===Using a Makefile=== + +22. As a part of the source distribution, a ``Makefile`` is +essential. The ``Makefile`` is also useful when developing the +application. It should always be possible to build an executable +from source by typing ``make``. + + |
