Com S 342 meeting -*- Outline -*- * abstract syntax (3.4.3) ------------------------------------------ ABSTRACT SYNTAX (3.4.3) idea: identify each rule in the grammar with a record that a. b. def: *abstract syntax* ignores details of def: *concrete syntax* gives details needed for humans to write and read. CONCRETE SYNTAX OF LAMBDA CALCULUS ::= (lambda () ) | ( ) | | AN ABSTRACT SYNTAX (define-record lambda (formal body)) ------------------------------------------ a... identifies the rule (a tag) b... provides access to components ... the characters used to write programs (parenthesis, etc.) ... (define-record app (rator rand)) ... (define-record varref (var)) ... (define-record lit (datum)) Q: Can you define an abstract syntax for if expressions? literals? ------------------------------------------ PARSING AND UNPARSING parse concrete ---------> abstract ^ / \----------/ unparse Examples of parse (parse 'x) = (make-varref 'x) ==> #(varref x) (parse '(f x)) = (make-app (make-varref 'f) (make-varref 'x)) ==> #(app #(varref f) #(varref x)) ------------------------------------------ ------------------------------------------ CODE FOR PARSE (define parse ;; TYPE: (-> (datum) ;; lambda-1+number-exp) (lambda (exp) (cond ((number? exp) (make-lit exp)) ((symbol? exp) (make-varref exp)) ((and (list? exp) (= (length exp) 3) (eq? (car exp) 'lambda)) (make-lambda (caadr exp) (parse (caddr exp)))) ((and (list? exp) (= (length exp) 2)) (make-app (parse (car exp)) (parse (cadr exp)))) (else (error "parse: bad syntax in expression:" exp))))) (define parse-lambda-1+number-exp parse) ------------------------------------------ Q: why is the error case there? does that catch all errors? defensive, no Use the following to *explain variant-case* ------------------------------------------ SYNTAX OF VARIANT-CASE ::= (variant-case { ( ) }+ (else )) ::= ::= ( {}* ) ::= ------------------------------------------ Note: is the name of the record type and is the name of the field within that record type. Explain the variant-case syntax and semantics point out the possible confusion with the lambda (:-( unparse is a convenience in displaying output of transformations. ------------------------------------------ UNPARSE USING VARIANT-CASE (define unparse ; p. 85 ;; TYPE: (-> (lambda-1+number-exp) ;; datum) (lambda (exp) (variant-case exp (lit (datum) datum) (else (error "unparse: Invalid abstract syntax" exp))))) ------------------------------------------ ... (varref (var) var) (lambda (formal body) (list 'lambda (list formal) (unparse body))) (app (rator rand) (list (unparse rator) (unparse rand))) (else (error "unparse: Invalid abstract syntax" exp))))) (define unparse-lambda-1+number-exp unparse) ------------------------------------------ EQUIVALENT USING COND (don't do this) (define unparse ; p. 85 ;; TYPE: (-> (lambda-1+number-exp) ;; datum) (lambda (exp) (cond exp ((lit? exp) (lit->datum exp)) ((varref? exp) (varref->var exp)) ((lambda? exp) (list 'lambda (list (lambda->formal exp)) (unparse (lambda->body exp)))) ((app? exp) (list (unparse (app->rator exp)) (unparse (app->rand exp)))) (else (error "unparse: Invalid abstract syntax" exp))))) ------------------------------------------ ------------------------------------------ DETAILS OF THE DESUGARING (variant-case e_0 (name_1 (f_11 ... f_1k) e_1) ... (name_n (f_n1 ... f_nm) e_n) (else e_n+1)) ==> (let ((*record* e_0) (cond ((name_1? *record*) (let ((f_11 (name_1->f_11 *record*)) ... (f_1k (name_1->f_1k *record*))) e_1)) ... ((name_n? *record*) (let ((f_n1 (name_1->f_n1 *record*)) ... (f_nm (name_1->f_nm *record*))) e_n)) (else e_n+1)))) ------------------------------------------ Now can write free-vars over the parsed, abstract syntax ------------------------------------------ WORKING WITH ABSTRACT SYNTAX USING VARIANT-CASE (free-vars (parse '(lambda (x) (car x)))) ==> (car) FOR YOU TO DO ;;; fill in the rest of this ;;; (define free-vars ;; TYPE: (-> (lambda-1+number-exp) ;; (set symbol)) (lambda (exp) (variant-case exp (lit (datum) the-empty-set) (varref (var) use set-of, set-remove, and set-union ------------------------------------------ ... (set-of var)) (lambda (formal body) (set-remove formal (free-vars body))) (app (rator rand) (set-union (free-vars rator) (free-vars rand)))))) ** handling Kleene star or plus (p. 86, bottom) ------------------------------------------ ABSTRACT SYNTAX FOR KLEENE STAR Use a list ::= | | (lambda ({}*) ) | (if ) | ( {}*) (define-record lit (datum)) (define-record varref (var)) (define-record lambda (formals body)) (define-record if (test-exp then-exp else-exp)) (define-record app (rator rands)) (define free-vars ;; TYPE: (-> (lambda+if-exp) ;; (set symbol)) (lambda (exp) (variant-case exp (lit (datum) the-empty-set) (varref (var) (set-of var)) (lambda (formals body) ------------------------------------------ ... (set-minus (free-vars body) formals)) (app (rator rands) (set-union (free-vars rator) (set-union-list (map free-vars rands)))))))