For consistency with the previous definitions of recursive procedures, let us specify the syntax checker logically, with one judgment per non-terminal.
The Scheme value v denotes a well-formed list of toplevel forms whenever the following judgment holds:
(%toplevel-forms v)
The Scheme value v denotes a well-formed toplevel form whenever the following judgment holds:
(%toplevel-form v)
The Scheme value v denotes a well-formed definition whenever the following judgment holds:
(%definition v)
The Scheme value v denotes a well-formed list of expressions whenever the following judgment holds:
(%expressions v)
The Scheme value v denotes a well-formed variable whenever the following judgment holds:
(%variable v)
The Scheme value v denotes a well-formed expression whenever the following judgment holds:
(%expression v)
The Scheme value v denotes a well-formed else-clause whenever the following judgment holds:
(%else-clause v)
The Scheme value v denotes a well-formed list of cond-clauses whenever the following judgment holds:
(%cond-clauses v)
The Scheme value v denotes a well-formed list of case-clauses whenever the following judgment holds:
(%case-clauses v)
The Scheme value v denotes a well-formed list of let-bindings whenever the following judgment holds:
(%let-bindings v)
The Scheme value v denotes a well-formed list of let*-bindings whenever the following judgment holds:
(%letstar-bindings v)
The Scheme value v denotes a well-formed list of letrec-bindings whenever the following judgment holds:
(%letrec-bindings v xs)
The Scheme value v denotes a well-formed quotation whenever the following judgment holds:
(%quotation v)
The Scheme value v denotes well-formed formal parameters whenever the following judgment holds:
(%lambda-formals v)
These judgments are defined with the following proof rules, where for narrative fluidity we occasionally write “x is blah” instead of “x denotes blah”. Caveat emptor.
The syntax-checking relation for a list of toplevel forms:
| TOPLEVEL_FORMS_NIL | ||
| (%toplevel-forms '()) | ||
| TOPLEVEL_FORMS_CONS | (%toplevel-form tlf) | (%toplevel-forms tlfs) | |
| (%toplevel-forms (cons tlf tlfs)) | |||
Let us review these two rules:
The syntax-checking relation for a toplevel form:
| TOPLEVEL_FORM_DEFINITION | (%variable x) | (%expression e) | |
| (%toplevel-form (list 'define x e)) | |||
| TOPLEVEL_FORM_EXPRESSION | (%expression e) | |
| (%toplevel-form e) |
Let us review these two rules:
The syntax-checking relation for a list of expressions:
| EXPRESSIONS_NIL | ||
| (%expressions '()) | ||
| EXPRESSIONS_CONS | (%expression e) | (%expressions es) | |
| (%expressions (cons e es)) | |||
Let us review these two rules:
The syntax-checking relation for a variable:
| VARIABLE | if x is a symbol that is not a keyword | |
| (%variable x) | ||
This rule says that a symbol that is not a keyword is a well-formed variable.
The syntax-checking relation for an expression:
| EXPRESSION_NUMBER | if n is a number | |
| (%expression n) | ||
| EXPRESSION_BOOLEAN | if b is a number | |
| (%expression b) | ||
| EXPRESSION_CHARACTER | if c is a character | |
| (%expression c) | ||
| EXPRESSION_STRING | if s is a string | |
| (%expression s) | ||
| EXPRESSION_VARIABLE | (%variable x) | |
| (%expression x) |
| EXPRESSION_TIME | (%expression v) | |
| (%expression (list 'time e)) |
| EXPRESSION_IF | (%expression e1) | (%expression e2) | (%expression e3) | |
| (%expression (list 'if e1 e2 e3)) | ||||
| EXPRESSION_AND | (%expressions es) | |
| (%expression (cons 'and es)) |
| EXPRESSION_OR | (%expressions es) | |
| (%expression (cons 'or es)) |
| EXPRESSION_COND | (%cond-clauses cs) | |
| (%expression (cons 'cond cs)) |
| EXPRESSION_CASE | (%expression e) | (%case-clauses cs) | |
| (%expression (cons 'case (cons e cs))) | |||
| EXPRESSION_LET | (%let-bindings let-bindings) | (%expression e) | |
| (%expression (list 'let let-bindings e)) | |||
| EXPRESSION_LETSTAR | (%letstar-bindings letstar-bindings) | (%expression e) | |
| (%expression (list 'letstar letstar-bindings e)) | |||
| EXPRESSION_LETREC | (%letrec-bindings letrec-bindings '()) | (%expression e) | |
| (%expression (list 'letrec letrec-bindings e)) | |||
| EXPRESSION_BEGIN | (%expression e) | (%expressions es) | |
| (%expression (cons 'begin (cons e es))) | |||
| EXPRESSION_QUOTE | (%quotation q) | |
| (%expression (list 'quote q)) |
| EXPRESSION_LAMBDA | (%lambda-formals fs) | (%expression e) | |
| (%expression (list 'lambda fs e)) | |||
| EXPRESSION_TRACE_LAMBDA | (%variable x) | (%lambda-formals fs) | (%expression e) | |
| (%expression (list 'trace-lambda x fs e)) | ||||
| EXPRESSION_APPLICATION | (%expression e) | (%expressions es) | |
| (%expression (cons e es)) | |||
All of these rules are structural.
The syntax-checking relation for a list of cond-clauses:
| COND_CLAUSES_NIL | (%else-clause c) | |
| (%cond-clauses (list c)) |
| COND_CLAUSES_CONS | (%cond-clause c) | (%cond-clauses cs) | |
| (%cond-clauses (cons c cs)) | |||
These two rules are structural.
The syntax-checking relation for an else-clause:
| ELSE_CLAUSE | (%expression e) | |
| (%else-clause (list (list 'else e))) |
This rule is structural.
The syntax-checking relation for a cond-clause:
| COND_CLAUSE_INCONSEQUENTIAL | (%expression e) | |
| (%cond-clause (list e)) |
| COND_CLAUSE_SIMPLE | (%expression e0) | (%expression e1) | |
| (%cond-clause (list e0 e1)) | |||
| COND_CLAUSE_BINDING | (%expression e0) | (%expression e1) | |
| (%cond-clause (list e0 '=> e1)) | |||
These three rules are structural.
The syntax-checking relation for a list of case-clauses:
| CASE_CLAUSES_NIL | (%else-clause c) | |
| (%case-clauses (list c)) |
| CASE_CLAUSES_CONS | (%case-clause c) | (%case-clauses cs) | |
| (%case-clauses (cons c cs)) | |||
These two rules are structural.
The syntax-checking relation for a case-clause:
| CASE_CLAUSE | (%quotations qs) | (%expression e) | |
| (%case-clause (list qs e)) | |||
This rule is structural.
The syntax-checking relation for a list of let-bindings:
| LET_BINDINGS | (%let-bindings_aux bs xs) | |
| (%let-bindings bs) |
This rule uses the auxiliary relation %let-bindings_aux. The judgment (%let-bindings_aux bs xs) holds whenever bs denotes a well-formed list of let-bindings that declare the distinct variables listed in xs.
The rule LET_BINDINGS says that if bs denotes a well-formed list of let-bindings that declare the distinct variables listed in xs, then bs denotes a well-formed let header.
The auxilary syntax-checking relation for a list of let-bindings:
| LET_BINDINGS_AUX_NIL | ||
| (%let-bindings_aux '() '()) | ||
| LET_BINDINGS_AUX_CONS | (%let-bindings_aux bs xs) | (%let-binding b xs x) | |
| (%let-bindings_aux (cons b bs) (cons x xs)) | |||
These two rules are structural:
The first rule, LET_BINDINGS_AUX_NIL, says that the empty list is a well-formed list of let-bindings that declare the vacuously distinct variables listed in the empty list.
The second rule, LET_BINDINGS_AUX_CONS, says that
then the list (cons b bs) denotes a well-formed list of let-bindings that declare the distinct variables listed in (cons x xs).
The syntax-checking relation for a let-binding:
| LET_BINDING | (%variable x) | (%expression e) | if x does not occur in xs |
| (%let-binding (list x e) xs x) | |||
This rule says that if x denotes a well-formed variable and if e denotes a well-formed expression, then (list x e) denotes a well-formed let-binding that declares a variable x that does not occur among the distinct variables listed in xs whenever this variable does not occur among these distinct variables.
The syntax-checking relation for a list of letstar-bindings:
| LETSTAR_BINDINGS_NIL | ||
| (%letstar-bindings '()) | ||
| LETSTAR_BINDINGS_CONS | (%letstar-binding b) | (%letstar-bindings bs) | |
| (%letstar-bindings (cons b bs)) | |||
These two rules are structural.
The syntax-checking relation for a letstar-binding:
| LETSTAR_BINDING | (%variable x) | (%expression e) | |
| (%letstar-binding (list x e)) | |||
This rule is structural.
The syntax-checking relation for a list of letrec-bindings:
| LETREC_BINDINGS | (%letrec-bindings_aux '() bs ys) | |
| (%letrec-bindings bs) |
This rule uses the auxiliary relation %letrec-bindings_aux. The intuition behind it is that for a list of letrec-bindings obtained by concatenating
the judgment (%letrec-bindings_aux xs b2s ys) holds whenever b2s is well-formed and declares the variables listed in ys, all of which are distinct and none of which is listed in xs.
The rule LETREC_BINDINGS says that if bs denotes a well-formed list of letrec-bindings that declare the distinct variables listed in ys, then bs denotes a well-formed letrec header.
The auxiliary syntax-checking relation for a list of letrec-bindings:
| LETREC_BINDINGS_AUX_NIL | ||
| (%letrec-bindings_aux xs '() '()) | ||
| LETREC_BINDINGS_AUX_CONS | (%letrec-binding xs b x) | (%letrec-bindings_aux (cons x xs) bs ys) | if x does not occur in ys |
| (%letrec-bindings_aux xs (cons b bs) (cons x ys)) | |||
Let us review these two rules:
The first rule, LETREC_BINDINGS_AUX_NIL, says that the empty list of letrec-bindings is well formed and declares no variables.
The second rule, LETREC_BINDINGS_AUX_CONS, says that
then (cons b bs) is a well-formed list of letrec bindings that is prefixed by letrec-bindings declaring distinct variables listed in xs and that declares distinct variables listed in (cons x ys) whenever x does not occur in ys.
The auxilary syntax-checking relation for a letrec-binding:
| LETREC_BINDING_LAMBDA | (%variable x) | (%lambda-formals fs) | (%expression e) | if x does not occur in xs |
| (%letrec-binding xs (list x (list 'lambda fs e)) x) | ||||
| LETREC_BINDING_TRACE_LAMBDA | (%variable x) | (%variable v) | (%lambda-formals fs) | (%expression e) | if x does not occur in xs |
| (%letrec-binding xs (list x (list 'trace-lambda v fs e)) x) | |||||
Let us review these two rules:
The syntax-checking relation for a list of quotations:
| QUOTATIONS_NIL | ||
| (%quotations '()) | ||
| QUOTATIONS_CONS | (%quotation q) | (%quotations qs) | |
| (%quotations (cons q qs)) | |||
These two rules are structural.
The syntax-checking relation for a quotation:
| QUOTATION_NUMBER | if n is a number | |
| (%quotation n) | ||
| QUOTATION_BOOLEAN | if b is a boolean | |
| %quotation b) | ||
| QUOTATION_CHARACTER | if c is a character | |
| (%quotation c) | ||
| QUOTATION_STRING | if s is a string | |
| (%quotation s) | ||
| QUOTATION_SYMBOL | if x is a symbol | |
| (%quotation x) | ||
| QUOTATION_NIL | ||
| (%quotation '()) | ||
| QUOTATION_CONS | (%quotation q1) | (%quotation q2) | |
| (%quotation (cons q1 q2)) | |||
These rules are structural.
The syntax-checking relation for formal parameters:
| LAMBDA_FORMALS | (%lambda-formals_aux fs xs) | |
| (%lambda-formals fs) |
This rule uses the auxiliary relation %lambda-formals_aux. The judgment (%lambda-formals_aux fs xs) holds whenever fs denotes well-formed formal parameters whose variables are all distinct and listed in xs.
The rule LAMBDA_FORMALS says that if fs denotes well-formed formal parameters whose variables are all distinct and listed in xs, then fs denotes well-formed formal parameters.
The auxiliary syntax-checking relation for formal parameters:
| LAMBDA_FORMALS_AUX_NIL | ||
| (%lambda-formals_aux '() '()) | ||
| LAMBDA_FORMALS_AUX_VARIABLE | (%variable f) | |
| (%lambda-formals_aux f (list f)) |
| LAMBDA_FORMALS_AUX_CONS | (%variable f) | (%lambda-formals_aux fs xs) | if f does not occur in xs |
| (%lambda-formals_aux (cons f fs) (cons f xs) | |||
Let us review these two rules:
Created [14 Oct 2025]