# Grammatical Framework Tutorial

3rd Edition, for GF version 2.2 or later

Aarne Ranta

`aarne@cs.chalmers.se`

## GF = Grammatical Framework

The term GF is used for different things:

- a program used for working with grammars
- a programming language in which grammars can be written
- a theory about the concepts of grammars and languages

This tutorial is about the GF program and the GF programming language. It will guide you

- to use the GF program
- to write GF grammars
- to write programs in which GF grammars are used as components

### The GF program

The program is open-source free software, which you can download from the GF Homepage:
`http://www.cs.chalmers.se/~aarne/GF`

There you can download

- ready-made binaries for Linux, Solaris, Macintosh, and Windows
- source code and documentation
- grammar libraries and examples

If you want to compile GF from source, you need Haskell and Java compilers. But normally you don't have to compile, and you don't need to know Haskell or Java to use GF.

To start the GF program, assuming you have installed it, just type

      gf

in the shell. You will see GF's welcome message and the prompt `>`.

## My first grammar

Now you are ready to try out your first grammar. We start with one that is not written in GF language, but in the EBNF notation (Extended Backus Naur Form), which GF can also understand. Type (or copy) the following lines in a file named `paleolithic.ebnf`:

      S   ::= NP VP ;
      VP  ::= V | TV NP | "is" A ;
      NP  ::= ("this" | "that" | "the" | "a") CN ;
      CN  ::= A CN ;
      CN  ::= "boy" | "louse" | "snake" | "worm" ;
      A   ::= "green" | "rotten" | "thick" | "warm" ;
      V   ::= "laughs" | "sleeps" | "swims" ;
      TV  ::= "eats" | "kills" | "washes" ;

### Importing grammars and parsing strings

The first GF command when using a grammar is to import it. The command has a long name, `import`, and a short name, `i`.

      import paleolithic.gf

The GF program now compiles your grammar into an internal representation, and shows a new prompt when it is ready.

You can use GF for parsing:

      > parse "the boy eats a snake"
      Mks_0 (Mks_6 Mks_10) (Mks_2 Mks_23 (Mks_7 Mks_13))

      > parse "the snake eats a boy"
      Mks_0 (Mks_6 Mks_13) (Mks_2 Mks_23 (Mks_7 Mks_10))

The `parse` (= `p`) command takes a string (in double quotes) and returns an abstract syntax tree - the thing with `Mks`s and parentheses. We will see soon how to make sense of the abstract syntax trees - now you should just notice that the tree is different for the two strings.

Strings that return a tree when parsed do so in virtue of the grammar you imported. Try parsing something else, and you fail

###

###

###

###

###

###

####

####

##

###

####

####

####

####

####

####

####

####

      > p "hello world"
      No success in cf parsing
      no tree found

    Generating trees and strings

    You can also use GF for linearizing
    (linearize = l). This is the inverse of
    parsing, taking trees into strings:

      > linearize Mks_0 (Mks_6 Mks_13) (Mks_2 Mks_23 (Mks_7 Mks_10))
      the snake eats a boy

    What is the use of this? Typically not that you type in a tree at
    the GF prompt. The utility of linearization comes from the fact that
    you can obtain a tree from somewhere else. One way to do so is
    random generation (generate_random = gr):

      > generate_random
      Mks_0 (Mks_4 Mks_11) (Mks_3 Mks_15)

    Now you can copy the tree and paste it to the linearize command.
    Or, more efficiently, feed random generation into parsing by using
    a pipe.

      > gr | l
      this man is big

    Some random-generated sentences

    Random generation can be quite amusing. So you may want to
    generate ten strings with one and the same command:

      > gr -number=10 | l
      a snake laughs
      that man laughs
      the man swims
      this man is warm
      a louse is rotten
      that worm washes a man
      a boy swims
      a snake laughs
      a man washes this man
      this louse kills the boy

    Systematic generation

    To generate all sentence that a grammar
    can generate, use the command generate_trees = gt.

      this boy laughs
      this boy sleeps
      this boy swims
      ...
      a worm is rotten
      a worm is thick
      a worm is warm

    You get quite a few trees but not all of them: only up to a given
    depth of trees. To see how you can get more, use the
    help = h command,

      h gr

    Quiz. If the command gt generated all
    trees in your grammar, it would never terminate. Why?

    More on pipes; tracing

    A pipe of GF commands can have any length, but the "output type"
    (either string or tree) of one command must always match the "input type"
    of the next command.

    The intermediate results in a pipe can be observed by putting the
    tracing flag -tr to each command whose output you
    want to see:

      > gr -tr | l -tr | p
      Mks_0 (Mks_6 Mks_13) (Mks_1 Mks_20)
      the snake laughs
      Mks_0 (Mks_6 Mks_13) (Mks_1 Mks_20)

    This facility is good for test purposes: for instance, you
    may want to see if a grammar is ambiguous, i.e.
    contains strings that can be parsed in more than one way.

    Writing and reading files

    To save the outputs of GF commands into a file, you can
    pipe it to the write_file = wf command,

      > gr -number=10 | l | write_file exx.tmp

    You can read the file back to GF with the
    read_file = rf command,

      > read_file exx.tmp | l -tr | p -lines

    Notice the flag -lines given to the parsing
    command. This flag tells GF to parse each line of
    the file separately. Without the flag, the grammar could
    not recognize the string in the file, because it is not
    a sentence but a sequence of ten sentences.

    Labelled context-free grammars

    The syntax trees returned by GF's parser in the previous examples
    are not so nice to look at. The identifiers of form Mks
    are labels of the EBNF rules. To see which label corresponds to
    which rule, you can use the print_grammar = pg command
    with the printer flag set to cf (which means context-free):

      > print_grammar -printer=cf
      Mks_10. CN ::= "boy" ;
      Mks_11. CN ::= "man" ;
      Mks_12. CN ::= "louse" ;
      Mks_13. CN ::= "snake" ;
      Mks_14. CN ::= "worm" ;
      Mks_8.  CN ::= A CN ;
      Mks_9.  CN ::= "bird" ;
      Mks_4.  NP ::= "this" CN ;
      Mks_18. A  ::= "thick" ;

    A syntax tree such as

      Mks_4 (Mks_8 Mks_18 Mks_14)
      this thick worm

    encodes the sequence of grammar rules used for building the
    expression. If you look at this tree, you will notice that Mks_4
    is the label of the rule prefixing this to a common noun,
    Mks_18 is the label of the adjective thick,
    and so on.

    The labelled context-free format

    The labelled context-free grammar format permits user-defined
    labels to each rule. GF recognizes files of this format by the suffix
    .cf. Let us include the following rules in the file
    paleolithic.cf.

      PredVP.  S   ::= NP VP ;
      UseV.    VP  ::= V ;
      ComplTV. VP  ::= TV NP ;
      UseA.    VP  ::= "is" A ;
      This.    NP  ::= "this" CN ;
      That.    NP  ::= "that" CN ;
      Def.     NP  ::= "the" CN ;
      Indef.   NP  ::= "a" CN ;
      ModA.    CN  ::= A CN ;
      Boy.     CN  ::= "boy" ;
      Louse.   CN  ::= "louse" ;
      Snake.   CN  ::= "snake" ;
      Worm.    CN  ::= "worm" ;
      Green.   A   ::= "green" ;
      Rotten.  A   ::= "rotten" ;
      Thick.   A   ::= "thick" ;
      Warm.    A   ::= "warm" ;
      Laugh.   V   ::= "laughs" ;
      Sleep.   V   ::= "sleeps" ;
      Swim.    V   ::= "swims" ;
      Eat.     TV  ::= "eats" ;
      Kill.    TV  ::= "kills"
      Wash.    TV  ::= "washes" ;

    Using the labelled context-free format

    The GF commands for the .cf format are
    exactly the same as for the .ebnf format.
    Just the syntax trees become nicer to read and
    to remember. Notice that before reading in
    a new grammar in GF you often (but not always,
    as we will see later) have first to give the
    command (empty = e), which removes the
    old grammar from the GF shell state.

      > empty

      > i paleolithic.cf

      > p "the boy eats a snake"
      PredVP (Def Boy) (ComplTV Eat (Indef Snake))

      > gr -tr | l
      PredVP (Indef Louse) (UseA Thick)
      a louse is thick

    The GF grammar format

    To see what there really is in GF's shell state when a grammar
    has been imported, you can give the plain command
    print_grammar = pg.

      > print_grammar

    The output is quite unreadable at this stage, and you may feel happy that
    you did not need to write the grammar in that notation, but that the
    GF grammar compiler produced it.

    However, we will now start to show how GF's own notation gives you
    much more expressive power than the .cf and .ebnf
    formats. We will introduce the .gf format by presenting
    one more way of defining the same grammar as in
    paleolithic.cf and paleolithic.ebnf.
    Then we will show how the full GF grammar format enables you
    to do things that are not possible in the weaker formats.

    Abstract and concrete syntax

    A GF grammar consists of two main parts:

     abstract syntax, defining what syntax trees there are
     concrete syntax, defining how trees are linearized into strings

    The EBNF and CF formats fuse these two things together, but it is possible
    to take them apart. For instance, the verb phrase predication rule

      PredVP. S ::= NP VP ;

    is interpreted as the following pair of rules:

      fun PredVP : NP -> VP -> S ;
      lin PredVP x y = {s = x.s ++ y.s} ;

    The former rule, with the keyword fun, belongs to the abstract syntax.
    It defines the function
    PredVP which constructs syntax trees of form
    (PredVP x y).

    The latter rule, with the keyword lin, belongs to the concrete syntax.
    It defines the linearization function for
    syntax trees of form (PredVP x y).

    Judgement forms

    Rules in a GF grammar are called judgements, and the keywords
    fun and lin are used for distinguishing between two
    judgement forms. Here is a summary of the most important
    judgement forms:

       abstract syntax

         cat C
         fun f : A

       concrete syntax

         lincat C = T
         lin f x ... y = t

    We return to the precise meanings of these judgement forms later.
    First we will look at how judgements are grouped into modules, and
    show how the grammar paleolithic.cf is
    expressed by using modules and judgements.

    Module types

    A GF grammar consists of modules,
    into which judgements are grouped. The most important
    module forms are

       abstract A = M, abstract syntax A with judgements in
      the module body M.
       concrete C of A = M, concrete syntax C of the
           abstract syntax A, with judgements in the module body M.

    An abstract syntax example

    Each nonterminal occurring in paleolithic.cf is
    introduced by a cat judgement. Each
    rule label is introduced by a fun judgement.

    abstract Paleolithic = {
    cat
      S ; NP ; VP ; CN ; A ; V ; TV ;
    fun
      PredVP  : NP -> VP -> S ;
      UseV    : V -> VP ;
      ComplTV : TV -> NP -> VP ;
      UseA    : A -> VP ;
      ModA    : A -> CN -> CN ;
      This, That, Def, Indef : CN -> NP ;
      Boy, Louse, Snake, Worm : CN ;
      Green, Rotten, Thick, Warm : A ;
      Laugh, Sleep, Swim : V ;
      Eat, Kill, Wash : TV ;
    }

    Notice the use of shorthands permitting the sharing of
    the keyword in subsequent judgements, and of the type
    in subsequent fun judgements.

    A concrete syntax example

    Each category introduced in Paleolithic.gf is
    given a lincat rule, and each
    function is given a fun rule. Similar shorthands
    apply as in abstract modules.

    concrete PaleolithicEng of Paleolithic = {
    lincat
      S, NP, VP, CN, A, V, TV = {s : Str} ;
    lin
      PredVP np vp  = {s = np.s ++ vp.s} ;
      UseV   v      = v ;
      ComplTV tv np = {s = tv.s ++ np.s} ;
      UseA   a   = {s = "is" ++ a.s} ;
      This  cn   = {s = "this" ++ cn.s} ;
      That  cn   = {s = "that" ++ cn.s} ;
      Def   cn   = {s = "the" ++ cn.s} ;
      Indef cn   = {s = "a" ++ cn.s} ;
      ModA  a cn = {s = a.s ++ cn.s} ;
      Boy    = {s = "boy"} ;
      Louse  = {s = "louse"} ;
      Snake  = {s = "snake"} ;
      Worm   = {s = "worm"} ;
      Green  = {s = "green"} ;
      Rotten = {s = "rotten"} ;
      Thick  = {s = "thick"} ;
      Warm   = {s = "warm"} ;
      Laugh  = {s = "laughs"} ;
      Sleep  = {s = "sleeps"} ;
      Swim   = {s = "swims"} ;
      Eat    = {s = "eats"} ;
      Kill   = {s = "kills"} ;
      Wash   = {s = "washes"} ;
    }

    Modules and files

    Module name + .gf = file name

    Each module is compiled into a .gfc file.

    Import PaleolithicEng.gf and try what happens

    Nothing more than before, except that the GFC files
    are generated.

    An Italian concrete syntax

    concrete PaleolithicIta of Paleolithic = {
    lincat
      S, NP, VP, CN, A, V, TV = {s : Str} ;
    lin
      PredVP np vp  = {s = np.s ++ vp.s} ;
      UseV   v      = v ;
      ComplTV tv np = {s = tv.s ++ np.s} ;
      UseA   a   = {s = "è" ++ a.s} ;
      This  cn   = {s = "questo" ++ cn.s} ;
      That  cn   = {s = "quello" ++ cn.s} ;
      Def   cn   = {s = "il" ++ cn.s} ;
      Indef cn   = {s = "un" ++ cn.s} ;
      ModA  a cn = {s = cn.s ++ a.s} ;
      Boy    = {s = "ragazzo"} ;
      Louse  = {s = "pidocchio"} ;
      Snake  = {s = "serpente"} ;
      Worm   = {s = "verme"} ;
      Green  = {s = "verde"} ;
      Rotten = {s = "marcio"} ;
      Thick  = {s = "grosso"} ;
      Warm   = {s = "caldo"} ;
      Laugh  = {s = "ride"} ;
      Sleep  = {s = "dorme"} ;
      Swim   = {s = "nuota"} ;
      Eat    = {s = "mangia"} ;
      Kill   = {s = "uccide"} ;
      Wash   = {s = "lava"} ;
    }

    Using a multilingual grammar

    Import without first emptying

    Try generation now:

    Translate by using a pipe:

    Inspect the shell state (print_options = po):

      > print_options
      main abstract :     Paleolithic
      main concrete :     PaleolithicIta
      all concretes :     PaleolithicIta PaleolithicEng

    Extending the grammar

    Neolithic