const CType* CAstStringConstant::GetType(void) const { CTypeManager *tm = CTypeManager::Get(); // string is array of character. return tm->GetArray(CToken::unescape(GetValueStr()).length()+1, tm->GetChar()); }
CAstStringConstant::CAstStringConstant(CToken t, const string value, CAstScope *s) : CAstOperand(t) { CTypeManager *tm = CTypeManager::Get(); _type = tm->GetArray(strlen(CScanner::unescape(value).c_str())+1, tm->GetChar()); _value = new CDataInitString(value); ostringstream o; o << "_str_" << ++_idx; _sym = new CSymGlobal(o.str(), _type); _sym->SetData(_value); s->GetSymbolTable()->AddSymbol(_sym); }
const CType* CAstSpecialOp::GetType(void) const { CTypeManager *tm = CTypeManager::Get(); EOperation oper = GetOperation(); if(GetOperand()->GetType() == NULL) return NULL; // case '&' if(oper == opAddress) { return tm->GetPointer(GetOperand()->GetType()); } // we don't implement '*' , '(cast)'. else if(oper == opDeref) { return NULL; } else { return NULL; } }
const CType* CAstBinaryOp::GetType(void) const { CTypeManager *tm = CTypeManager::Get(); EOperation oper = GetOperation(); // If lhs or rhs is null, then null. if(_left->GetType() == NULL || _right->GetType() == NULL) return NULL; // case '+', '-', '*', '/' if(oper == opAdd || oper == opSub || oper == opMul || oper == opDiv) { if(_left->GetType()->IsInt() && _right->GetType()->IsInt()) return tm->GetInt(); else return NULL; } // case '&&' , '||' else if(oper == opAnd || oper == opOr) { if(_left->GetType()->IsBoolean() && _right->GetType()->IsBoolean()) return tm->GetBool(); else return NULL; } // case '=', '#' else if(oper == opEqual || oper == opNotEqual) { if(_left->GetType()->IsBoolean() && _right->GetType()->IsBoolean() || _left->GetType()->IsChar() && _right->GetType()->IsChar() || _left->GetType()->IsInt() && _right->GetType()->IsInt()) return tm->GetBool(); else return NULL; } // case '>', '>=', '<', '<=' else { if(_left->GetType()->IsInt() && _right->GetType()->IsInt() || _left->GetType()->IsChar() && _right->GetType()->IsChar()) return tm->GetBool(); else return NULL; } }
const CType* CAstUnaryOp::GetType(void) const { CTypeManager *tm = CTypeManager::Get(); EOperation oper = GetOperation(); CAstExpression *e = GetOperand(); if(e->GetType() == NULL) return NULL; if(oper == opNeg || oper == opPos) { //case '+' || '-' if(e->GetType()->IsInt()) return tm->GetInt(); else return NULL; } else { // case '!' if(e->GetType()->IsBoolean()) return tm->GetBool(); else return NULL; } }
void CParser::InitSymbolTable(CSymtab *s) { CTypeManager *tm = CTypeManager::Get(); CSymProc *fun; // function DIM(array: pointer to array; dim: integer): integer fun = new CSymProc("DIM", tm->GetInt()); fun->AddParam(new CSymParam(0, "arr", tm->GetPointer(tm->GetNull()))); fun->AddParam(new CSymParam(1, "dim", tm->GetInt())); s->AddSymbol(fun); // function DOFS(array: pointer to array): integer; fun = new CSymProc("DOFS", tm->GetInt()); fun->AddParam(new CSymParam(0, "arr", tm->GetPointer(tm->GetNull()))); s->AddSymbol(fun); // function ReadInt() : integer; fun = new CSymProc("ReadInt", tm->GetInt()); s->AddSymbol(fun); // procedure WriteInt(i: integer); fun = new CSymProc("WriteInt", tm->GetNull()); fun->AddParam(new CSymParam(0, "i", tm->GetInt())); s->AddSymbol(fun); // procedure WriteChar(c: char); fun = new CSymProc("WriteChar", tm->GetNull()); fun->AddParam(new CSymParam(0, "c", tm->GetChar())); s->AddSymbol(fun); // procedure WriteStr(string: char[]); fun = new CSymProc("WriteStr", tm->GetNull()); fun->AddParam(new CSymParam(0, "str", tm->GetPointer(tm->GetArray(CArrayType::OPEN, tm->GetChar())))); s->AddSymbol(fun); // procedure WriteLn(); fun = new CSymProc("WriteLn", tm->GetNull()); s->AddSymbol(fun); }
const CType* CParser::type(bool isParam, bool isFunction) { // // type ::= basetype | type "[" [ number ] "]". // basetype ::= "boolean" | "char" | "integer". // CToken t; CToken tk; EToken tt = _scanner->Peek().GetType(); CTypeManager *tm = CTypeManager::Get(); const CType *type; vector<int> nelems; // basetype cases. switch(tt) { case tBoolean: Consume(tBoolean, &t); tk = t; type = dynamic_cast<const CType *>(tm->GetBool()); break; case tChar: Consume(tChar, &t); tk = t; type = dynamic_cast<const CType *>(tm->GetChar()); break; case tInteger: Consume(tInteger, &t); tk = t; type = dynamic_cast<const CType *>(tm->GetInt()); break; default: SetError(_scanner->Peek(), "basetype expected."); break; } assert(type != NULL); // array case. while(_scanner->Peek().GetType() == tLSBrak) { Consume(tLSBrak); CToken nelem; if(_scanner->Peek().GetType() == tNumber) { Consume(tNumber, &nelem); nelems.push_back(atoi(nelem.GetValue().c_str())); } else { // open arrays are allowed only in parameter. if(isParam) nelems.push_back(-1); else SetError(_scanner->Peek(), "expected 'tNumber', got '" + _scanner->Peek().GetName() + "'"); } Consume(tRSBrak); } for(int i = nelems.size()-1; i >= 0; i--) { type = dynamic_cast<const CType *>(tm->GetArray(nelems[i], type)); assert(type != NULL); nelems.pop_back(); // Arrays are addressed in parameter. if(i == 0 && isParam) type = dynamic_cast<const CType *>(tm->GetPointer(type)); } if(isFunction && !type->IsScalar()) { SetError(tk, "invalid composite type for function."); } return type; }
void CParser::subroutineDecl(CAstScope *s) { // // subroutineDecl ::= (procedureDecl | functionDecl) subroutineBody ident ";". // procedureDecl ::= "procedure" ident [ formalParam ] ";". // functionDecl ::= "function" ident [ formalParam ] ":" type ";". // formalParam ::= "(" [ varDeclSequence ] ")". // subroutineBody ::= varDeclaration "begin" statSequence "end". // varDeclSequence ::= varDecl { ";" varDecl }. // varDecl ::= ident { "," ident } ":" type. // CToken subroutine_name; CToken subroutine_name_check; CTypeManager *tm = CTypeManager::Get(); // procedureDecl if(_scanner->Peek().GetType() == tProcedure) { CToken t; CAstStatement *statseq = NULL; Consume(tProcedure); Consume(tIdent, &subroutine_name); // Check duplicate procedure declaration. if(dynamic_cast<CAstModule *>(s)) { if(s->GetSymbolTable()->FindSymbol(subroutine_name.GetValue(), sGlobal) != NULL) SetError(subroutine_name, "duplicate procedure/function declaration '" + subroutine_name.GetValue() + "'."); } else { if(s->GetSymbolTable()->FindSymbol(subroutine_name.GetValue(), sLocal) != NULL) SetError(subroutine_name, "duplicate procedure/function declaration '" + subroutine_name.GetValue() + "'."); } CSymProc *symproc = new CSymProc(subroutine_name.GetValue(), tm->GetNull()); CAstProcedure *procedure = new CAstProcedure(subroutine_name, subroutine_name.GetValue(), s, symproc); // formalParam if(_scanner->Peek().GetType() == tLBrak) { Consume(tLBrak); if(_scanner->Peek().GetType() == tIdent) { varDeclParam(procedure, symproc, 0); while(1) { if(_scanner->Peek().GetType() == tSemicolon) { Consume(tSemicolon); varDeclParam(procedure, symproc, symproc->GetNParams()); } else break; } } Consume(tRBrak); } s->GetSymbolTable()->AddSymbol(symproc); Consume(tSemicolon); // subroutineBody from here. // subroutineBody ::= varDeclaration "begin" statSequence "end". // varDeclaration if(_scanner->Peek().GetType() == tVar) { Consume(tVar); varDecl(procedure); Consume(tSemicolon); while(1) { if(_scanner->Peek().GetType() == tIdent) { varDecl(procedure); Consume(tSemicolon); } else break; } } Consume(tBegin); // statSequence statseq = statSequence(procedure); procedure->SetStatementSequence(statseq); Consume(tEnd); Consume(tIdent, &subroutine_name_check); // Check procedure names are equal. if(subroutine_name.GetValue() != subroutine_name_check.GetValue()) { SetError(subroutine_name_check, "procedure/function identifier mismatch ('" + subroutine_name.GetValue() + "' != '" + subroutine_name_check.GetValue() + "')."); } Consume(tSemicolon); } // functionDecl else { CToken tmp; // Parameters are pushed into params. Then they will be added into symproc later. vector<CSymParam *> params; const CType *func_type; CAstStatement *statseq = NULL; Consume(tFunction); Consume(tIdent, &subroutine_name); // Check duplicate function declaration. if(dynamic_cast<CAstModule *>(s)) { if(s->GetSymbolTable()->FindSymbol(subroutine_name.GetValue(), sGlobal) != NULL) SetError(subroutine_name, "duplicate procedure/function declaration '" + subroutine_name.GetValue() + "'."); } else { if(s->GetSymbolTable()->FindSymbol(subroutine_name.GetValue(), sLocal) != NULL) SetError(subroutine_name, "duplicate procedure/function declaration '" + subroutine_name.GetValue() + "'."); } // formalParam if(_scanner->Peek().GetType() == tLBrak) { int idx = 0; CToken t; vector<string> vars; const CType *var_type; Consume(tLBrak); // Get parameters. if(_scanner->Peek().GetType() == tIdent) { Consume(tIdent, &t); vars.push_back(t.GetValue()); while(_scanner->Peek().GetType() == tComma) { Consume(tComma); Consume(tIdent, &t); // Check duplicate parameter declaration. for(int i = 0; i < vars.size(); i++) { if(vars[i] == t.GetValue()) { SetError(t, "duplicate variable declaration '" + t.GetValue() + "'."); break; } } vars.push_back(t.GetValue()); } Consume(tColon); var_type = type(true); for(int i = vars.size() - 1; i >= 0; i--) { CSymParam *param = new CSymParam(i, vars[i], var_type); params.push_back(param); idx++; } // for multiple parameter declaration. while(1) { if(_scanner->Peek().GetType() == tSemicolon) { Consume(tSemicolon); CToken t_loop; vector<string> vars_loop; const CType *var_type_loop; Consume(tIdent, &t_loop); // Check duplicate parameter declaration. for(int i = 0; i < params.size(); i++) { if(params[i]->GetName() == t_loop.GetValue()) { SetError(t_loop, "duplicate variable declaration '" + t_loop.GetValue() + "'."); break; } } vars_loop.push_back(t_loop.GetValue()); while(_scanner->Peek().GetType() == tComma) { Consume(tComma); Consume(tIdent, &t_loop); for(int i = 0; i < params.size(); i++) { if(params[i]->GetName() == t_loop.GetValue()) { SetError(t_loop, "duplicate variable declaration '" + t_loop.GetValue() + "'."); break; } } // Check duplicate parameter declaration. for(int i = 0; i < vars_loop.size(); i++) { if(vars_loop[i] == t_loop.GetValue()) { SetError(t_loop, "duplicate variable declaration '" + t_loop.GetValue() + "'."); break; } } vars_loop.push_back(t_loop.GetValue()); } Consume(tColon); var_type_loop = type(true); int tmp_idx = idx; // Add parameters into vector 'params'. for(int i = vars_loop.size() - 1; i >= 0; i--) { CSymParam *param_loop = new CSymParam(i+tmp_idx, vars_loop[i], var_type_loop); params.push_back(param_loop); vars_loop.pop_back(); idx++; } } else break; } } Consume(tRBrak); } Consume(tColon); func_type = type(false, true); Consume(tSemicolon); CSymProc *symproc = new CSymProc(subroutine_name.GetValue(), func_type); CAstProcedure *function = new CAstProcedure(subroutine_name, subroutine_name.GetValue(), s, symproc); assert(symproc != NULL); // Add parameters into symproc. for(int i = 0; i < params.size(); i++) { CSymParam *param = params[i]; symproc->AddParam(param); function->GetSymbolTable()->AddSymbol(param); } while(!params.empty()) params.pop_back(); s->GetSymbolTable()->AddSymbol(symproc); // subroutineBody from here. // subroutineBody ::= varDeclaration "begin" statSequence "end". // varDeclaration if(_scanner->Peek().GetType() == tVar) { Consume(tVar); varDecl(function); Consume(tSemicolon); while(1) { if(_scanner->Peek().GetType() == tIdent) { varDecl(function); Consume(tSemicolon); } else break; } } Consume(tBegin); // statSequence statseq = statSequence(function); function->SetStatementSequence(statseq); Consume(tEnd); Consume(tIdent, &subroutine_name_check); // Check function names are equal. if(subroutine_name.GetValue() != subroutine_name_check.GetValue()) { SetError(subroutine_name_check, "procedure/function identifier mismatch ('" + subroutine_name.GetValue() + "' != '" + subroutine_name_check.GetValue() + "')."); } Consume(tSemicolon); } }
CAstExpression* CParser::factor(CAstScope *s) { // // factor ::= qualident | number | boolean | char | string | "(" expression ")" | subroutineCall | "!" factor. // FIRST(factor) = { tIdent, tNumber, tTrue, tFalse, tCharacter, tString, tLBrak, tEMark }. // CToken t; EToken tt = _scanner->Peek().GetType(); CTypeManager *tm = CTypeManager::Get(); CAstExpression *n = NULL; CSymtab *symtab = s->GetSymbolTable(); switch(tt) { case tTrue: Consume(tTrue, &t); n = new CAstConstant(t, tm->GetBool(), 1); break; case tFalse: Consume(tFalse, &t); n = new CAstConstant(t, tm->GetBool(), 0); break; case tNumber: { Consume(tNumber, &t); errno = 0; long long v = strtoll(t.GetValue().c_str(), NULL, 10); if (errno != 0) SetError(t, "invalid number."); // integer range validation check. if(v > 2147483648) SetError(t, "integer constant outside valid range."); n = new CAstConstant(t, tm->GetInt(), v); break; } case tIdent: { Consume(tIdent, &t); if(_scanner->Peek().GetType() == tLBrak) { // subroutineCall Consume(tLBrak); CAstFunctionCall *f; // If subroutineCall calls undefined procedure/function, then set error. if(symtab->FindSymbol(t.GetValue(),sLocal) == NULL && symtab->FindSymbol(t.GetValue(), sGlobal) != NULL) { // Check if symbol is procedure. if(dynamic_cast<const CSymProc *>(symtab->FindSymbol(t.GetValue(), sGlobal)) == NULL) SetError(t, "invalid procedure/function identifier."); f = new CAstFunctionCall(t, dynamic_cast<const CSymProc *>(symtab->FindSymbol(t.GetValue(), sGlobal))); } else if(symtab->FindSymbol(t.GetValue(), sLocal) != NULL) { // Check if symbol is procedure. if(dynamic_cast<const CSymProc *>(symtab->FindSymbol(t.GetValue(), sLocal)) == NULL) SetError(t, "invalid procedure/function identifier."); f = new CAstFunctionCall(t, dynamic_cast<const CSymProc *>(symtab->FindSymbol(t.GetValue(), sLocal))); } else SetError(t, "undefined identifier."); assert(f != NULL); if(isExpr(_scanner->Peek())) { CAstExpression *expr = expression(s); assert(expr != NULL); // If array, then addressed. if(expr->GetType()->IsArray()) expr = new CAstSpecialOp(expr->GetToken(), opAddress, expr, NULL); f->AddArg(expr); while(_scanner->Peek().GetType() == tComma) { Consume(tComma); expr = expression(s); assert(expr != NULL); // If array, then addressed. if(expr->GetType()->IsArray()) expr = new CAstSpecialOp(expr->GetToken(), opAddress, expr, NULL); f->AddArg(expr); } } Consume(tRBrak); n = f; } else { // qualident if(_scanner->Peek().GetType() == tLSBrak) { // It means array CAstArrayDesignator *f; if(symtab->FindSymbol(t.GetValue(), sLocal) == NULL && symtab->FindSymbol(t.GetValue(), sGlobal) != NULL) { // Check if symbol is procedure. if(dynamic_cast<const CSymProc *>(symtab->FindSymbol(t.GetValue(), sGlobal)) != NULL) SetError(t, "designator expected."); f = new CAstArrayDesignator(t, symtab->FindSymbol(t.GetValue(), sGlobal)); } else if(symtab->FindSymbol(t.GetValue(), sLocal) != NULL) { // Check if symbol is procedure. if(dynamic_cast<const CSymProc *>(symtab->FindSymbol(t.GetValue(), sLocal)) != NULL) SetError(t, "designator expected"); f = new CAstArrayDesignator(t, symtab->FindSymbol(t.GetValue(), sLocal)); } else { SetError(t, "undefined identifier."); } while(_scanner->Peek().GetType() == tLSBrak) { Consume(tLSBrak); CAstExpression *expr = expression(s); assert(expr != NULL); f->AddIndex(expr); Consume(tRSBrak); } f->IndicesComplete(); n = f; } // non-array case. else { if(symtab->FindSymbol(t.GetValue(), sLocal) == NULL && symtab->FindSymbol(t.GetValue(), sGlobal) != NULL) { // Check if symbol is procedure. if(dynamic_cast<const CSymProc *>(symtab->FindSymbol(t.GetValue(), sGlobal)) != NULL) { SetError(t, "designator expected."); } n = new CAstDesignator(t, symtab->FindSymbol(t.GetValue(), sGlobal)); } else if(symtab->FindSymbol(t.GetValue(), sLocal) != NULL) { // Check if symbol is procedure. if(dynamic_cast<const CSymProc *>(symtab->FindSymbol(t.GetValue(), sLocal)) != NULL) { SetError(t, "designator expected."); } n = new CAstDesignator(t, symtab->FindSymbol(t.GetValue(), sLocal)); } else SetError(t, "undefined identifier."); } } break; } case tString: Consume(tString, &t); n = new CAstStringConstant(t, t.GetValue(), s); break; case tCharacter: { Consume(tCharacter, &t); char res; // If character length is 0, it means character is '\0' because invalid character cases are handled in scanner. if(t.GetValue().length() == 0) res = '\0'; else if(t.GetValue().length() == 1) { if(t.GetValue().at(0) != '\\') res = t.GetValue().at(0); else SetError(t, "wrong character"); } // unescape. else if(t.GetValue().length() == 2) { if(t.GetValue().at(0) == '\\') { if(t.GetValue().at(1) == 'n') { res = '\n'; } else if(t.GetValue().at(1) == 't') { res = '\t'; } else if(t.GetValue().at(1) == '"') { res = '"'; } else if(t.GetValue().at(1) == '\'') { res = '\''; } else if(t.GetValue().at(1) == '\\') { res = '\\'; } else if(t.GetValue().at(1) == '0') { res = '\0'; } else SetError(t, "wrong character"); } } else SetError(t, "wrong character"); n = new CAstConstant(t, tm->GetChar(), (long long)res); break; } case tLBrak: Consume(tLBrak); n = expression(s); Consume(tRBrak); break; case tEMark: Consume(tEMark, &t); n = new CAstUnaryOp(t, opNot, factor(s)); break; default: // cout << "got " << _scanner->Peek() << endl; SetError(_scanner->Peek(), "factor expected."); break; } return n; }
void CParser::InitSymbolTable(CSymtab *s) { CTypeManager *tm = CTypeManager::Get(); // predefined functions: // - DIM(a: ptr to array; dim: integer): integer // - DOFS(a: ptr to array): integer // - ReadInt(): integer // - WriteInt(i:integer): void // - WriteChar(c:char): void // - WriteStr(str: char[]): void // - WriteLn():void // - DIM(a: ptr to array; dim: integer): integer CSymProc *DIM = new CSymProc("DIM", tm->GetInt()); CSymParam *DIM_a = new CSymParam(0, "a", tm->GetPointer(tm->GetNull())); CSymParam *DIM_dim = new CSymParam(1, "dim", tm->GetInt()); DIM->AddParam(DIM_a); DIM->AddParam(DIM_dim); s->AddSymbol(DIM); // - DOFS(a: ptr to array): integer CSymProc *DOFS = new CSymProc("DOFS", tm->GetInt()); CSymParam *DOFS_a = new CSymParam(0, "a", tm->GetPointer(tm->GetNull())); DOFS->AddParam(DOFS_a); s->AddSymbol(DOFS); // - ReadInt(): integer CSymProc *ReadInt = new CSymProc("ReadInt", tm->GetInt()); s->AddSymbol(ReadInt); // - WriteInt(i:integer): void CSymProc *WriteInt = new CSymProc("WriteInt", tm->GetNull()); CSymParam *WriteInt_i = new CSymParam(0, "i", tm->GetInt()); WriteInt->AddParam(WriteInt_i); s->AddSymbol(WriteInt); // - WriteChar(c:char): void CSymProc *WriteChar = new CSymProc("WriteChar", tm->GetNull()); CSymParam *WriteChar_c = new CSymParam(0, "c", tm->GetChar()); WriteChar->AddParam(WriteChar_c); s->AddSymbol(WriteChar); // - WriteStr(str: char[]): void CSymProc *WriteStr = new CSymProc("WriteStr", tm->GetNull()); CSymParam *WriteStr_str = new CSymParam(0, "str", tm->GetPointer(tm->GetArray(CArrayType::OPEN, tm->GetChar()))); WriteStr->AddParam(WriteStr_str); s->AddSymbol(WriteStr); // - WriteLn():void CSymProc *WriteLn = new CSymProc("WriteLn", tm->GetNull()); s->AddSymbol(WriteLn); }