#drinc:util.g #toy.g #externs.g /* * decl.d: declaration and definition of the various symbols. */ /* * declareVariables - declare a set of variables of the given kind. */ proc declareVariables(SymbolKind_t kind)void: *SymbolEntry_t se; register TokenKind_t tk; ResultType_t typ; while tk := getSimpleToken(); tk = tk_int or tk = tk_bool do typ := if tk = tk_int then rt_int else rt_bool fi; nextToken(); while tk := getToken(&se, nil, nil); tk = tk_id do if se*.se_kind ~= sk_empty then errorHereThree("symbol '", se*.se_name, "' already defined"); else se*.se_kind := kind; se*.se_type := typ; allocateVariable(se); fi; nextToken(); tk := getSimpleToken(); if tk = tk_comma then nextToken(); elif tk ~= tk_semicolon then errorHere("expecting comma between variable names"); while skipToken(); tk := getSimpleToken(); tk ~= tk_id and tk ~= tk_semicolon and tk ~= tk_comma and tk ~= tk_eof and tk ~= tk_int and tk ~= tk_bool do od; if tk = tk_comma then nextToken(); fi; fi; od; if tk = tk_semicolon then nextToken(); else errorHere("expecting semicolon after variable list"); if kind = sk_globalVariable then while skipToken(); tk := getSimpleToken(); tk ~= tk_semicolon and tk ~= tk_proc and tk ~= tk_eof and tk ~= tk_int and tk ~= tk_bool do od; else while skipToken(); tk := getSimpleToken(); tk ~= tk_semicolon and tk ~= tk_corp and tk ~= tk_id and tk ~= tk_if and tk ~= tk_while and tk ~= tk_readln and tk ~= tk_write and tk ~= tk_int and tk ~= tk_bool do od; fi; if tk = tk_semicolon then nextToken(); fi; fi; od; corp; /* * defineProc - the outer part of defining a proc. */ proc defineProc()void: SymbolEntry_t dummyEntry; *SymbolEntry_t procSe, se; register TokenKind_t tk; register uint parCount; ResultType_t functionResult, bodyResult, typ; nextToken(); tk := getToken(&procSe, nil, nil); if tk = tk_id then if procSe*.se_kind ~= sk_empty then errorHereThree("symbol '", procSe*.se_name, "' already defined"); procSe := &dummyEntry; dummyEntry.se_name := " "; else /* put in non-empty kind, to prevent conflict with parameters */ procSe*.se_kind := sk_undefined; fi; nextToken(); else errorHere("expecting identifier as proc name"); procSe := &dummyEntry; dummyEntry.se_name := " "; if tk ~= tk_leftParen then skipToken(); fi; fi; tk := getSimpleToken(); if tk = tk_leftParen then nextToken(); else errorHere("expecting '(' to start parameter list"); fi; procStartParameters(); parCount := 0; while tk := getSimpleToken(); tk = tk_int or tk = tk_bool do typ := if tk = tk_int then rt_int else rt_bool fi; if typ = rt_bool then errorHere("proc parameters can only be 'int'"); fi; nextToken(); while tk := getToken(&se, nil, nil); tk = tk_id do if se*.se_kind ~= sk_empty then errorHereThree("symbol '", se*.se_name, "' already defined"); else se*.se_kind := sk_parameter; se*.se_type := typ; allocateVariable(se); fi; parCount := parCount + 1; nextToken(); tk := getSimpleToken(); if tk = tk_comma then nextToken(); elif tk ~= tk_semicolon and tk ~= tk_rightParen then errorHere("expecting comma between parameter names"); while skipToken(); tk := getSimpleToken(); tk ~= tk_id and tk ~= tk_semicolon and tk ~= tk_comma and tk ~= tk_eof and tk ~= tk_int and tk ~= tk_bool and tk ~= tk_rightParen and tk ~= tk_colon do od; if tk = tk_comma then nextToken(); fi; fi; od; if tk = tk_semicolon then nextToken(); elif tk ~= tk_rightParen then errorHere("expecting semicolon after parameter list"); while skipToken(); tk := getSimpleToken(); tk ~= tk_semicolon and tk ~= tk_eof and tk ~= tk_int and tk ~= tk_bool and tk ~= tk_rightParen and tk ~= tk_colon do od; if tk = tk_semicolon then nextToken(); fi; fi; od; procEndParameters(); if tk = tk_rightParen then nextToken(); tk := getSimpleToken(); else errorHere("expecting ')' after parameter list"); fi; if parCount ~= 0 and CharsEqual(procSe*.se_name, "main") then errorHere("'main' cannot have any parameters"); fi; procSe*.se_kind := sk_procedure; procSe*.se_parCount := parCount; if tk = tk_int or tk = tk_bool then functionResult := if tk = tk_int then rt_int else rt_bool fi; if CharsEqual(procSe*.se_name, "main") then errorHere("'main cannot have a result"); fi; nextToken(); elif tk = tk_void then functionResult := rt_void; nextToken(); else functionResult := rt_error; errorHere("expecting result type for proc"); fi; procSe*.se_type := functionResult; tk := getSimpleToken(); if tk = tk_colon then nextToken(); tk := getSimpleToken(); else errorHere("expecting ':' after proc header"); fi; declareVariables(sk_localVariable); procEndLocals(); codeInit(procSe); while if tk = tk_corp or tk = tk_eof then bodyResult := rt_void; else bodyResult := parseStatementList(); tk := getSimpleToken(); fi; tk ~= tk_corp and tk ~= tk_eof do errorHere("expecting 'corp' to end proc"); findStatement(); od; if functionResult = rt_int or functionResult = rt_bool then if bodyResult = rt_void then errorHere("expecting result expression at end of function"); else if functionResult ~= bodyResult then errorHere("type mismatch for proc result"); fi; procResult(); fi; elif functionResult = rt_void and (bodyResult = rt_int or bodyResult = rt_bool) then errorHere("unwanted result expression at end of procedure"); fi; codeTerm(procSe); symbolPurge(); if tk = tk_corp then nextToken(); else errorHere("missing 'corp' on last proc"); fi; if getSimpleToken() = tk_semicolon then nextToken(); fi; corp;