###### tags: `MP` # Parsowanie ciąg dalszy Na ćwiczenia parser był zrobiony brzydko lub tak,że trudno było go powiększać. Były też jakieś błędy w stylu, że nie sprawdzaliśmy, czy liczba argumentów była dobra, po prostu braliśmy pierwsze 2 i ignorowaliśmy resztę. ## Jak to zrobić trochę prościej / ładniej? `s-exp-match?` bierze dwa s-wyrażenia i sprawdza czy pasują. ```plait (s-exp-match? `(ANY ANY ANY) `(1 2 3)) ;#t (s-exp-match? `(ANY NUMBER ANY) `(1 2 3)) ;#t (s-exp-match? `(lambda ANY ANY) `(1 2 3)) ;#f ``` Teraz sprawdzanie, czy wyrażenie jest dobrego kształtu jest znacznie prostsze: ```plait (define (parse-Exp s) (cond [(s-exp-match? 'NUMBER s) (exp-number (s-exp->number s))] [(s-exp-match? '(SYMBOL ANY ANY) s) (let ([xs (s-exp->list s)]) (exp-op (parse-op (first xs)) (parse-Exp (second xs)) (parse-Exp (third xs))))])) ``` ### Napiszmy w rackecie własny match ```racket ;sytnax.rkt (define (match-sexp pat s) (match pat [`ANY #t] [`SYMBOL (symbol? s)] [`NUMBER (number? s)] [`() (null? s)] [(cons p1 p2) (and (pair? s) (match-sexp p1 (car s)) (match-sexp p2 (cdr s)))])) (require (only-in plait s-exp-content)) (provide (my-match-sexp?)) (define (my-match-sexp? pat s) ;pat jest plaitowym wyrazeniem (match-sexp (s-exp-content pat) (s-exp-content s))) ``` ### Jak tego użyć w plaicie? ```plait (require "syntax.rkt") (require (typed-in "parser.rkt" (my-match-sexp? : (S-Exp S-Exp -> Boolean)))) ;potrzebujemy cos, co otypuje (nie sprawdza tego ale to nie problem) (define (parse-Exp s) (cond [(my-match-sexp? 'NUMBER s) (exp-number (s-exp->number s))] [(my-match-sexp? '(SYMBOL ANY ANY) s) (let ([xs (s-exp->list s)]) (exp-op (parse-op (first xs)) (parse-Exp (second xs)) (parse-Exp (third xs))))])) ``` Najważniejsze - jak mamy dużo powtarzającego się kodu to można wyrzucić to do osobnego języka i napisać interpreter. **Coś było dalej ale nie słuchałam** ## Piszemy jakieś nowe rzeczy ```racket (define (my-match-sexp? pat s) (match-sexp pat s)) ``` ```racket (define (parse-Op ) cond [] [] [] [] []) ``` Na ten moment każdy parser jest wielkim `cond`-em i wszystko w środku się powtarza, można to uprościć: ```racket (define op-parser `((+ ,opp-add) (- ,opp-sub) (* ,opp-mul) (/ ,opp-div))) (define exp-parser `((NUMBER ,exp-number) (SYMBOL ANY ANY ,(lambda (op e1 e2) (exp-op (parse-Op op) (parse-Exp e1) (parse-Exp e2)))))) (define run-parser) ```