15. Des Analyseurs Syntaxiques
1 Exercice 15.5.1
Je vous le laisse... Cela ne devrait pas poser de problème si vous avez étudié le chapitre 14.
2 Exercice 15.5.2
Je me contente de faire un lexeur, puis d’utiliser get-lexeme en boucle... L’exemple est interactif, mais une modification minime l’étendrait à un fichier quelconque f.
#lang racket |
(require parser-tools/lex) |
|
(define-lex-abbrevs |
[digit (char-range "0" "9")] |
[int (repetition 1 +inf.0 digit)] |
[float (concatenation int "." int)] |
[ratio (concatenation int "/" int)] |
[numpos (union int float ratio)] |
[num (union numpos (concatenation "-" numpos))] |
[other (char-range #\u0000 #\u00FF)]) |
|
(define-empty-tokens op-tokens (FINI)) |
|
(define get-lexeme |
(lexer |
[(eof) 'FINI] |
[num (string->number lexeme)] |
[any-char (get-lexeme input-port)])) |
> (call-with-input-string "attaqueau-53.6Nord-Wcontinue!!Les105bateauxdetruitsaux11/20nesontplus" |
(lambda (p-in) |
(do ((x (get-lexeme p-in) (get-lexeme p-in)) (L '() (cons x L))) |
((equal? x 'FINI) (reverse L))))) |
(-53.6 105 11/20) |
3 Exercice 15.5.3
Tout d’abord le lexeur :
#lang racket |
(require parser-tools/lex parser-tools/yacc) |
|
(define-lex-abbrevs |
[espace (union #\newline #\return #\tab #\space)] ; whitespace est prédéfini ! |
[other (char-range #\u0000 #\u00FF)]) |
|
(define-tokens word-tokens (ART NAME ADJ VERB CONJSUB)) |
|
(define-empty-tokens op-tokens (DOT EOF)) |
|
(define get-lexeme |
(lexer |
[(eof) 'EOF] |
["." 'DOT] |
[(repetition 1 +inf.0 espace) (get-lexeme input-port)] |
[(union "le" "la") (token-ART (string->symbol lexeme))] |
[(union "chien" "souris" "chat" "cat") (token-NAME (string->symbol lexeme))] |
[(union "petit" "gentil" "petite") (token-ADJ (string->symbol lexeme))] |
[(union "mange" "aboie" "dort") (token-VERB (string->symbol lexeme))] |
[(union "qui" "que") (token-CONJSUB (string->symbol lexeme))] |
[other (error "Unparseable" (string->symbol lexeme))])) |
Je teste interactivement le lexeur :
> (call-with-input-string "la petite souris mange." |
(lambda (p-in) |
(do ((i 0 (+ i 1)) (x (get-lexeme p-in) (get-lexeme p-in))) |
((equal? x 'EOF) 'fini) |
(printf "~a : ~a~n" i x)))) |
0 : #(struct:token ART la) |
1 : #(struct:token ADJ petite) |
2 : #(struct:token NAME souris) |
3 : #(struct:token VERB mange) |
4 : DOT |
fini |
Au tour du parseur :
(define parse |
(parser |
[start phrase] |
[end EOF] |
[tokens word-tokens op-tokens] |
[error (lambda (a b c) (printf "ERROR with token : ~a~n" b))] ; ? |
[grammar |
(phrase [(grNom grVerb DOT) `(ph ,$1 ,$2)]) |
(grNom [(grNomSimple) $1] |
[(grNomSimple sub) `(grnoms ,$1 ,$2)]) |
(grNomSimple [(ART NAME) `(gn (art ,$1) (nom ,$2))] |
[(ART ADJ NAME) `(gn (art ,$1) (adj ,$2) (nom ,$3))]) |
(sub [(CONJSUB VERB) `(sub (conjsub ,$1) (vb ,$2))]) |
(grVerb [(VERB) `(gv (vb ,$1))] |
[(VERB grNom) `(gv (vb ,$1) ,$2)])])) |
que je teste cette fois en écrivant une fonction d’analyse d’une phrase :
(define (analyser str) |
(call-with-input-string str |
(lambda (p-in) |
(parse (lambda () (get-lexeme p-in)))))) |
|
> (analyser "la souris mange le petit chien qui dort.") |
(ph (gn (art la) (nom souris)) (gv (vb mange) (grnoms (gn (art le) (adj petit) (nom chien)) (sub (conjsub qui) (vb dort))))) |
4 Exercice 15.5.4
Je vous le laisse... Analogue à 15.5.5 ci-dessous sauf que l’on génère du source au lieu de calculer.
5 Exercice 15.5.5
Le fameux exemple mfcalc du manuel Bison... Vous trouverez le lexeur et le parseur dans deux fichiers séparés mfcalc-lexer.rkt et mfcalc-parser.rkt. Je ne saurais trop conseiller de faire soi-même cet exercice, il est très instructif...
6 Exercice 15.5.6
Prendre cet exercice comme un projet personnel, que vous voudrez sans doute élargir...