Syntax-Directed Translation Scheme for Typechecking PSub

program
  --> program id {curr_scope <- AddEntry(id.lexval, Nil);
                  UpdateType(curr_scope, Program, False)} ;
        var_decls subprogram_decls compound_statement .

var_decls
  --> var decl_list
    | epsilon

decl_list
  --> decl_list declaration
    | declaration

declaration
  --> identifier_list : type ;
        {UpdateTypeList(identifier_list.l, type.t, True)}

identifier_list
  --> identifier_list1 , id
        {identifier_list.l <-
         Cons(AddEntry(id.lexval, curr_scope), identifier_list1.l)}
    | id {identifier_list.l <- Cons(AddEntry(id.lexval, curr_scope), Nil)}

type
  --> standard_type {type.t <- standard_type.t}
    | array [ num .. num1 ] of standard_type
        {type.t <- Array(num.lexval, num1.lexval, standard_type.t)}

standard_type
  --> integer {standard_type.t <- Integer}
    | real {standard_type.t <- Real}
    | boolean {standard_type.t <- Boolean}

subprogram_decls
  --> subprogram_decls subprogram_declaration
    | epsilon

subprogram_declaration
  --> subprogram_head var_decls compound_statement ;
        {curr_scope <- Delete(curr_scope)}

subprogram_head
  --> function id {curr_scope <- AddEntry(id.lexval, curr_scope)}
        arguments : standard_type ;
        {UpdateType(curr_scope, Func(arguments.t, standard_type.t), False)}
    | procedure id {curr_scope <- AddEntry(id.lexval, curr_scope)}
        arguments ;
        {UpdateType(curr_scope, Proc(arguments.t), False)}

arguments
  --> ( parameter_list ) {arguments.t <- parameter_list.t}
    | epsilon {arguments.t <- Nil}

parameter_list
  --> parameter_list1 ; parameter
        {parameter_list.t <- Append(parameter.t, parameter_list1.t)}
    | parameter {parameter_list.t <- parameter.t}

parameter
  --> identifier_list : standard_type
        {parameter.t <-
         UpdateTypeList(identifier_list.l, standard_type.t, True)}
    | var identifier_list : standard_type
        {parameter.t <-
         UpdateTypeList(identifier_list.l, Var(standard_type.t), True)}

compound_statement
  --> begin statement_list end

statement_list
  --> statement_list ; statement
    | statement

statement
  --> variable := expression
        {if not Compat(variable.t, expression.t) then Error}
    | procedure_statement
    | compound_statement
    | if expression then statement else statement
        {if not Compat(Boolean, expression.t) then Error}
    | while expression do statement
        {if not Compat(Boolean, expression.t) then Error}
    | repeat statement_list until expression
        {if not Compat(Boolean, expression.t) then Error}
    | epsilon

variable
  --> id [ expression ]
        {if LookupType(id.lexval) = Array(m,n,s)
           and Compat(Integer, expression.t)
         then variable.t <- s
         else Error}
    | id {variable.t <- LookupType(id.lexval)}

procedure_statement
  --> id ( expression_list ) 
        {MatchProcArgs(LookupType(id.lexval), expression_list.t)}
    | id {MatchProcArgs(LookupType(id.lexval), Nil)}

expression_list
  --> expression_list1 , expression
        {expression_list.t <- Cons(expression.t, expression_list1.t)}
    | expression {expression_list.t <- Cons(expression.t, Nil)}

expression
  --> simple_expression relop simple_expression1
        {expression.t <-
         MatchBinOp(relop.lexval, simple_expression.t, simple_expression1.t)}
    | simple_expression {expression.t <- simple_expression.t}

simple_expression
  --> simple_expression1 add_operator term
        {simple_expression.t <-
         MatchBinOp(add_operator.lexval, simple_expression1.t, term.t)}
    | addop term {simple_expression.t <- MatchUnOp(addop.lexval, term.t)}
    | term {simple_expression.t <- term.t}

add_operator
  --> addop {add_operator.lexval <- addop.lexval}
    | or {add_operator.lexval <- or.lexval}

term
  --> term1 mul_operator factor
        {term.t <- MatchBinOp(mul_operator.lexval, term1.t, factor.t)}
    | factor {term.t <- factor.t}

mul_operator
  --> mulop {mul_operator.lexval <- mulop.lexval}
    | and {mul_operator.lexval <- and.lexval}
    | div {mul_operator.lexval <- div.lexval}
    | mod {mul_operator.lexval <- mod.lexval}

factor
  --> variable
        {if variable.t = Func(l,r) or variable.t = Over(l)
         then factor.t <- MatchFuncArgs(variable.t, Nil)
         else factor.t <- variable.t}
    | id ( expression_list )
        {factor.t <- MatchFuncArgs(LookupType(id.lexval), expression_list.t)}
    | num {factor.t <- TypeOf(num.lexval)}
    | ( expression ) {factor.t <- expression.t}
    | not factor1 {factor.t <- MatchUnOp(not.lexval, factor1.t)}

Notes

This translation scheme uses two global variables, symbol_table and curr_scope, as discussed in class. It assumes that the following types have been declared: Entry and Type, as well as the list types EntryList and TypeList. For the list types we have the empty list constant Nil:List and the cons and append operations Cons: T x TList -> TList and Append: TList x TList -> TList. For the type Type there are the following constructor functions:

  Integer, Real, Boolean, Program: Type
  Array: int x int x Type -> Type
  Func: TypeList x Type -> Type
  Proc, Over: TypeList -> Type
as well as the function Var: Type -> Type which sets a flag in the type structure to indicate that it is the type of a variable parameter (there is also a flag to indicate an lvalue; these will need to be distinguished for the code generation phase). There is also a procedure Error which terminates the compiler with an appropriate error message.

We assume the following functions for interacting with the symbol table and checking types: