Semantic Analysis Rules for 488/2107

Spring 1998

Comments

Semantic actions can be executed during parsing or in a separate pass, after the abstract syntax tree has been built. We will choose the second alternative.

We will be using a symbol table to keep track of declared symbols and help typechecking. As scopes get nested, we have to use a stack of scopes, and use static scoping rules to access non-local variables. You may choose to implement this as a stack of symbol tables.

Recursive procedures are allowed. Mutually-recursive procedures are not. To facilitate this, first store all declarations in the scope, and then process function bodies.

For extra credit (5 bonus marks), implement a check on correct returns from functions and procedures:

Data structures:

Scope stack. Symbol table. Other data structures.

Types:

There are four basic types in our programming language: INT, BOOL, VOID and STRING. No type-casting is allowed (i.e., 1 AND TRUE is illegal). Every language construct has a type associated with it. In what follows, we will give some semantic rules to the language constructs. Your job is to extend them to all constructs and implement them. t(a) means type of a.

Semantic Analysis Operators

program : scope

scope   : 'begin' decls stmts 'end'  
            /* First start a new scope for decls and stmts.         */
            /* Upon exit, optionally print symbol table for current */
            /* scope and remove current scope off the stack         */

decl    : type ':' id
             /* If id is not already declared in current scope,     */
             /* insert (id,type) into table.                        */
          type ':' id '[' exp ']' 
             /* Same as above but also check that t(exp)=integer.   */
             /* Insert exp as a parameter to (id,type).             */
          fundecl
          procdecl

fundecl : type 'function' id scope   
             /* make new entry in symbol table for function, with   */
             /* return of type type, name id and no params          */ 
             /* start new scope                                     */
             /* give errors if duplicate name                       */
          type 'function' id '(' parms ')' scope
             /* make new entry in symbol table for function, with   */
             /* return of type type, name id and parameters params. */
             /* Make sure there are no duplicate names of params    */
             /* give errors if duplicate name                       */

procdecl : 'procedure' id scope
           'procedure' id '(' parms ')' scope
                   /* same as fundecl, but return is VOID           */

morestmts : stmt              /* t(morestmts) = t(stmt)       */
            stmt morestmts1   /* t(morestmts) = t(morestmts1) */

/* make sure that type of all statements is VOID */
stmt :  var '<-' exp          
           /* check that var has an lvalue and t(var) = t(exp)   */
        ifstmt
        wstmt
        lpstmt
        'exit'
        rtstmt
        'put' outputs
        'get' outputs
        scope
        prcstmt

prcstmt : id     /* make sure id is declared as procedure        */         
          id '(' args ')'
                 /* same as above and that args match in number  */
                 /* and type                                     */

ifstmt	: 'if' exp 'then' stmts1 'else' stmts2 'end'
                 /* check t(exp)=bool                            */
	  'if' exp 'then' stmts 'end'
                 /* check that t(exp)=bool                       */

rtstmt  : 'return' '(' exp ')' /* make sure that t(exp) =        */
                               /*   t(return(current scope))     */
          'return' 

wstmt	: 'while' exp 'do' stmts 'end'  /* check t(exp) = boolean */

exp	: '-' exp1         /* if t(exp1) = int then t(exp) = int  */
          'not' exp1       /* if t(exp) = bool then t(exp) = bool */
          exp1 '+' exp2		
          exp1 '-' exp2		
	  exp1 '*' exp2		
	  exp1 '/' exp2 		
          exp1 '^' exp2
                 /* if t(exp1) = int and t(exp2) = int then t(exp) = int */
	  exp1 'and' exp2		
	  exp1 'or' exp2		
                 /* if t(exp1) = bool and t(exp2) = bool then t(exp) = bool */
	  exp1 '>=' exp2	
	  exp1 '>' exp2	
	  exp1 '<' exp2	
	  exp1 '<=' exp2
                 /* if t(exp1) = int and t(exp2) = int then t(exp) = bool */
	  exp1 '=' exp2	
	  exp1 'not=' exp2	
          /* if t(exp1) = t(exp2) then t(exp) = bool */	
          '(' exp ')'
          '{' decls stmts 'yields' exp '}'
                /* start new scope for unnamed function returning t(exp), */
                /* with decls and stmts.                                  */ 
          var             
          id '(' args ')'  
               /* lookup function id and check type of args */
	  constant

var     : id              /* check that id has been defined                */
          id '[' exp ']'  /* check that id has been defined and t(exp)=int */

parms   : parm
          parms ',' parm  /* make sure parameters have unique names        */

Marsha Chechik
Back to csc488 homepage
Last modified on January 27, 1998