zzJinux/2019-spring-compiler

플젝3 체크리스트

Closed this issue · 7 comments

  • symbol table creation
    • 선언되지 않은 변수나 함수는 사용 불가
    • 변수나 함수, 함수 파라미터 선언 시 중복된 이름 check
    • 변수나 parameter 선언 시 void type으로 선언할 수 없음
    • 변수나 parameter 선언 시 array type 확인
    • scoping error check
  • type error check
    • operand type check (l-value, assignment, array subscripting)
      • a = b: is a lvalue?, 양변 타입 일치
      • a[b]: is a array?, is b integer?
      • a(b, c): is a function?
    • while/if statement condition type
  • function call check
    • 함수 호출 시 parameter의 개수와 type이 일치하는지 check
    • 함수의 return 값과 return type이 일치하는지 check
    • 함수의 return type이 void일 경우 return statement 자체가 없음 (?)
    • main함수는 가장 마지막에 선언되어야 함
    • main함수는 반드시 void로 선언되어야 함
    • main함수는 반드시 parameter가 존재하지 않는다.

edited

  • stack offset 계산 모호함
    • 시작주소는 0부터? -4 부터?
    • 내가 내린 결정: -4 (lower address)
  • global variable memory offset 계산 모호함
    • lower address? upper address?
    • 내가 내린 결정: lower address

에러메시지 줄번호

zero-sized array(variable declaration) ?
-> emit error!

<global context> {
  an AST: TreeNode *
  a list of scopes (ref. AST): Scope *
  a stack of scopes of upper blocks (w/ size counter): Scope *
  a flag for handling the function body block presence (function flag): int
    # if set, indicates that you are analyzing a function
  a flag for "main function" declaration ("main" flag): int
    # if set, indicates that you are in the middle of, or done with analyzing the main function
  scope id counter: int
  function loc counter: int
      
}

struct Scope {
  scope id: int
  stack counter: int
  symbol table: BucketList *
}

((added attributes))
struct TreeNode {
  Scope ref (for compount stmt)
}



func buildSymtab(TreeNode *tnode):
  initialize:
    [a list of scope] := empty list
    [a stack of scopes of upper blocks] := empty stack
    [a flag for handling the function body block presence] := 0
    [a flag for "main function" declaration ("main" flag)] := 0
    [scope id counter] := 0
    [function loc counter] := 0

  enterScope()
  [current scope stack counter] := 0
  # static variable loc counter
  
  traverse(tnode, pre, post)

  exitScope()

  if "main" flag is clear
    error(MAIN_FUNCTION_NOT_EXISTS)

func buildSymtab_pre(TreeNode *tnode):
  ######## WORKING WITH SCOPES #########
  if TNODE is of a compound statement(block):
    if function flag is set:
      unmark it
    else:
      enterScope()

    set the current scope's stack counter to -4 (pointer width)

  elif TNODE is of a function declaration:
    if "main" flag is set:
      error(MAIN_FUNCTION_MUST_APPEAR_LAST)

    mark the function flag
    enterScope()
    set the current scope's stack counter to 4 (pointer width)

    if it's the main function:
      if its parameter is not void
        error(MAIN_FUNCTION_PAARM_TYPE_IS_NON_VOID)
      if its return type is not void:
        error(MAIN_FUNCTION_RETURN_TYPE_IS_NON_VOID)
      mark the "main" flag


  ######## INSERT SYMBOLS #########
  if TNODE is of a var/func declaration or parameter
    get the name of it
    if the name is already present in the current scope:
      error(REDIFINITION)

    if it's a function decl:
      insert new symbol (function, loc = [function loc counter])
      ++[function loc counter]
    elif: # a variable decl:
      if the type is void:
        error(VARIABLE_HAS_INCOMPLETE_TYPE)

      # how to check if we are in global scope?
      # just check if current scope id!

      if not global scope
        # check array
        [stack counter of current scope] -= 4 * sz (int width)
        insert new symbol (variable, loc = [stack counter])
      else:
        insert new symbol (variable, loc = [stack counter])
        [stack counter of current scope] += 4 * sz (int width)
      
    else: # TNODE is of a parameter
      if the parameter does not exist (null param):
        skip current function
      if the type is void:
        error(PARAMETER_HAS_INCOMPLETE_TYPE)

      # check array
      insert new symbol (parameter, loc = [stack counter])
      [current stack counter] += 4 (int width)



void buildSymtab_post (TreeNode *tnode)
  if TNODE is of a compound statement(block):
    exitScope()
  elif TNODE is of a var-expression/call-expression
    lookup the name on the whole stack of scopes
    if found:
      add a line number to the lineList of the symbol record
    else:
      error(IDENTIFIER_NOT_FOUND)


enterScope(void):
  create a scope for the function
  push the scope
  append the scope (to list)

exitScope(void):
  store the scope object to current ast node
  pop the scope

void typeCheck(TreeNode *tnode)
  // TODO
<global context> {
  an AST: TreeNode *
  a list of scopes (ref. AST): Scope *
  a stack of scopes of upper blocks (w/ size counter): Scope *
  a flag for handling the function body block presence (function flag): int
    # if set, indicates that you are analyzing a function
  a flag for "main function" declaration ("main" flag): int
    # if set, indicates that you are in the middle of, or done with analyzing the main function
  scope id counter: int
  function loc counter: int
      
}

struct Scope {
  scope id: int
  stack counter: int
  symbol table: BucketList *
}

((added attributes))
struct TreeNode {
  Scope ref (for compount stmt)
}



func buildSymtab(TreeNode *tnode):
  initialize:
    [a list of scope] := empty list
    [a stack of scopes of upper blocks] := empty stack
    [a flag for handling the function body block presence] := 0
    [a flag for "main function" declaration ("main" flag)] := 0
    [scope id counter] := 0
    [function loc counter] := 0

  enterScope()
  traverse(tnode, pre, post)
  exitScope()

  if "main" flag is clear
    error(MAIN_FUNCTION_NOT_EXISTS)

func buildSymtab_pre(TreeNode *tnode):
  if TNODE is of a compound statement(block):
    if function flag is set:
      unmark it
    else:
      enterScope()

    set the current scope's stack counter to -4 (pointer width)

  elif TNODE is of a function declaration:
    if "main" flag is set:
      error(MAIN_FUNCTION_MUST_APPEAR_LAST)

    mark the function flag
    enterScope()
    set the current scope's stack counter to 4 (pointer width)

    if it's the main function:
      if its parameter is not void
        error(MAIN_FUNCTION_PAARM_TYPE_IS_NON_VOID)
      if its return type is not void:
        error(MAIN_FUNCTION_RETURN_TYPE_IS_NON_VOID)
      mark the "main" flag


void buildSymtab_post (TreeNode *tnode)
  if TNODE is of a compound statement(block):
    exitScope()
  elif TNODE is of a var/func declaration or parameter
    get the name of it
    if the name is already present in the current scope:
      error(REDIFINITION)

    if it's a function decl:
      insert new symbol (function, loc = [function loc counter])
      ++[function loc counter]
    elif: # a variable decl:
      if the type is void:
        error(VARIABLE_HAS_INCOMPLETE_TYPE)

      # check array
      [stack counter of current scope] -= 4 (int width)
      insert new symbol (variable, loc = [stack counter])
      
    else: # TNODE is of a parameter
      if the parameter does not exist (null param):
        skip current function
      if the type is void:
        error(PARAMETER_HAS_INCOMPLETE_TYPE)

      # check array
      insert new symbol (parameter, loc = [stack counter])
      [current stack counter] += 4 (int width)

  elif TNODE is of a var-expression/call-expression
    lookup the name on the whole stack of scopes
    if found:
      add a line number to the lineList of the symbol record
    else:
      error(IDENTIFIER_NOT_FOUND)


enterScope(void):
  create a scope for the function
  push the scope
  append the scope (to list)

exitScope(void):
  store the scope object to current ast node
  pop the scope

void typeCheck_pre(TreeNode *tnode) {
  if StmtK:
    if CompdK:
        scope_push()
}

void typeCheck_post(TreeNode *tnode) {
    if ExprK:
        if opExprK:
            if array:
                if index is not integer:	
                    error()
            else if ASSIGN:
                if tnode->child[0] == void: 
                    error()
                else if lhs is array and k is VOID:
                    error()
                //if tnode->child[0]==array:
                //    typeError(“array cannot assign”)
                else if tnode->child[1]==void:
                    typeError(“cannot assign void variable”)
                else:
                    tnode->type = tnode->child[1]->type
            else:
                left = tnode->child[0]
                right = tnode->child[1]
                if left is void or right is void:
                    typeError()
                // TODO (anything else?)
                else 
                    tnode->type = int;
        else if constK:
            tnode->type = int;
        else if varK:
            sym = st_lookup()
            if !sym
                error(undefined var)
            tnode->type = sym->type;
        else if callK:
            sym = st_lookup()  
            if !sym
                error(undefined func)
            if sym is not func:
                error()
            
            declParam = sym->child[]
            nowParam = tnode->child[]
            while(nowParam) {
                if !declParam
                    error(“argument count not same”)
                if nowParam is void type:
                    error()
                else{
                    nowParam = nowParam->sibling;
                    declParam = declParam->sibling; 
                }
            }
            if declParam
                error(“argument count not same”)
    else if StmtK:
        if CompdK:
            scope_pop()
        else if SelectK:
            if tnode->child[0] is void:
                error()
        else if IterK:
            if tnode->child[0] is void:
                error()
        else if RetK:
            funcSym = st_lookup()
            if tnode->nChildren > 0 && tnode->child[0] != void:
                nowType = int;
            else:
                nowType = void;

            if funcSym->type != nowType:
                error()
}

void typeCheck(TreeNode *tnode)
  // TODO
  enterScope()
  traverse(tnode, pre, post)
  exitScope()

void returning void function

void vovovo() {}
void func() {
  return vovovo();
}
int main() {
  func();
  return 0;
}