~ubuntu-branches/ubuntu/trusty/happy/trusty-proposed

« back to all changes in this revision

Viewing changes to tests/Test.ly

  • Committer: Bazaar Package Importer
  • Author(s): Ian Lynagh (wibble)
  • Date: 2006-10-26 22:52:14 UTC
  • mfrom: (1.2.2 upstream) (3.1.1 dapper)
  • Revision ID: james.westby@ubuntu.com-20061026225214-6jmf0n3ykkc9elyw
Tags: 1.16~rc2-1
* New upstream (release candidate) version.
* Removed happy/ prefixes from various paths in debian/rules and
  debian/docs.
* doc/configure generated by autoconf is in the Debian diff.
* Build using cabal:
  * Various debian/rules changes.
  * Create debian/get_version.hs for extracting the version from the cabal
    file.
  * Requires ghc6 >= 6.4.2.
  * No longer tries to detect platform. Closes: #340325, #332979.
  * Removed autotool-dev build-dep.
* Add 'XSLTPROC_OPTS = --nonet' to doc/config.mk.in.
* Remove src/Parser.ly and src/AttrGrammarParser.ly before cleaning so
  the generated files don't get cleaned.
* Set Standards-Version to 3.7.2 (no changes needed).
* Removed PS and DVI stanzas from debian/doc-base as we don't build
  the documentation those ways.
* Removed content-free postinst and prerm.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
This is a simple test for happy.
 
2
 
 
3
First thing to declare is the name of your parser,
 
4
and the type of the tokens the parser reads.
 
5
 
 
6
> {
 
7
> import Char
 
8
> }
 
9
 
 
10
> %name calc
 
11
> %tokentype { Token }
 
12
 
 
13
The parser will be of type [Token] -> ?, where ? is determined by the
 
14
production rules.  Now we declare all the possible tokens:
 
15
 
 
16
> %token 
 
17
>       let             { TokenLet }
 
18
>       in              { TokenIn }
 
19
>       int             { TokenInt $$ }
 
20
>       var             { TokenVar $$ }
 
21
>       '='             { TokenEq }
 
22
>       '+'             { TokenPlus }
 
23
>       '-'             { TokenMinus }
 
24
>       '*'             { TokenTimes }
 
25
>       '/'             { TokenDiv }
 
26
>       '('             { TokenOB }
 
27
>       ')'             { TokenCB }
 
28
 
 
29
The *new* system.
 
30
 
 
31
 %token 
 
32
        let             ( let )
 
33
        in              ( in )
 
34
        int             ( digit+ )
 
35
        var             ( {alpha}{alphanum}+ )
 
36
        '='             ( = )
 
37
        '+'             ( + )
 
38
        '-'             ( - )
 
39
        '*'             ( * )
 
40
        '/'             ( / )
 
41
        '('             ( \( )
 
42
        ')'             ( \) )
 
43
 %whitespace            ( {space}|{tab} )
 
44
 %newline               ( {newline} )
 
45
 
 
46
The left hand side are the names of the terminals or tokens,
 
47
and the right hand side is how to pattern match them.
 
48
 
 
49
Like yacc, we include %% here, for no real reason.
 
50
 
 
51
> %%
 
52
 
 
53
Now we have the production rules.
 
54
 
 
55
> Exp :: { Exp }
 
56
> Exp : let var '=' Exp in Exp  { Let $2 $4 $6 }
 
57
>     | Exp1                    { Exp1 $1 }
 
58
 
59
> Exp1 :: { Exp1 }
 
60
> Exp1 : Exp1 '+' Term          { Plus $1 $3 }
 
61
>      | Exp1 '-' Term          { Minus $1 $3 }
 
62
>      | Term                   { Term $1 }
 
63
 
64
> Term :: { Term }
 
65
> Term : Term '*' Factor        { Times $1 $3 }
 
66
>      | Term '/' Factor        { Div $1 $3 }
 
67
>      | Factor                 { Factor $1 }
 
68
 
69
> Factor :: { Factor }
 
70
> Factor : int                  { Int $1 }
 
71
>        | var                  { Var $1 }
 
72
>        | '(' Exp ')'          { Brack $2 }
 
73
 
 
74
We are simply returning the parsed data structure !
 
75
Now we need some extra code, to support this parser,
 
76
and make in complete:
 
77
 
 
78
> {
 
79
 
 
80
All parsers must declair this function, 
 
81
which is called when an error is detected.
 
82
Note that currently we do no error recovery.
 
83
 
 
84
> happyError tks = error "Parse error"
 
85
 
 
86
Now we declare the datastructure that we are parsing.
 
87
 
 
88
> data Exp  = Let String Exp Exp | Exp1 Exp1 
 
89
> data Exp1 = Plus Exp1 Term | Minus Exp1 Term | Term Term 
 
90
> data Term = Times Term Factor | Div Term Factor | Factor Factor 
 
91
> data Factor = Int Int | Var String | Brack Exp 
 
92
 
 
93
The datastructure for the tokens...
 
94
 
 
95
> data Token
 
96
>       = TokenLet
 
97
>       | TokenIn
 
98
>       | TokenInt Int
 
99
>       | TokenVar String
 
100
>       | TokenEq
 
101
>       | TokenPlus
 
102
>       | TokenMinus
 
103
>       | TokenTimes
 
104
>       | TokenDiv
 
105
>       | TokenOB
 
106
>       | TokenCB
 
107
 
 
108
.. and a simple lexer that returns this datastructure.
 
109
 
 
110
> lexer :: String -> [Token]
 
111
> lexer [] = []
 
112
> lexer (c:cs) 
 
113
>       | isSpace c = lexer cs
 
114
>       | isAlpha c = lexVar (c:cs)
 
115
>       | isDigit c = lexNum (c:cs)
 
116
> lexer ('=':cs) = TokenEq : lexer cs
 
117
> lexer ('+':cs) = TokenPlus : lexer cs
 
118
> lexer ('-':cs) = TokenMinus : lexer cs
 
119
> lexer ('*':cs) = TokenTimes : lexer cs
 
120
> lexer ('/':cs) = TokenDiv : lexer cs
 
121
> lexer ('(':cs) = TokenOB : lexer cs
 
122
> lexer (')':cs) = TokenCB : lexer cs
 
123
 
 
124
> lexNum cs = TokenInt (read num) : lexer rest
 
125
>       where (num,rest) = span isDigit cs
 
126
 
 
127
> lexVar cs =
 
128
>    case span isAlpha cs of
 
129
>       ("let",rest) -> TokenLet : lexer rest
 
130
>       ("in",rest)  -> TokenIn : lexer rest
 
131
>       (var,rest)   -> TokenVar var : lexer rest
 
132
 
 
133
To run the program, call this in gofer, or use some code
 
134
to print it.
 
135
 
 
136
> runCalc :: String -> Exp
 
137
> runCalc = calc . lexer
 
138
 
 
139
Here we test our parser.
 
140
 
 
141
> main = case runCalc "1 + 2 + 3" of {
 
142
>       (Exp1 (Plus (Plus (Term (Factor (Int 1))) (Factor (Int 2))) (Factor (Int 3))))  ->
 
143
>       case runCalc "1 * 2 + 3" of {
 
144
>       (Exp1 (Plus (Term (Times (Factor (Int 1)) (Int 2))) (Factor (Int 3)))) ->
 
145
>       case runCalc "1 + 2 * 3" of {
 
146
>       (Exp1 (Plus (Term (Factor (Int 1))) (Times (Factor (Int 2)) (Int 3)))) ->
 
147
>       case runCalc "let x = 2 in x * (x - 2)" of {
 
148
>       (Let "x" (Exp1 (Term (Factor (Int 2)))) (Exp1 (Term (Times (Factor (Var "x")) (Brack (Exp1 (Minus (Term (Factor (Var "x"))) (Factor (Int 2))))))))) -> print "Test works\n"; 
 
149
>       _ -> quit } ; _ -> quit } ; _ -> quit } ; _ -> quit }
 
150
> quit = print "Test failed\n"
 
151
 
 
152
> }