Download presentation
Presentation is loading. Please wait.
1
Symbol table lookup & install
Kei Hasegawa
2
Variables and literals in program text
struct scope { ... map<string, vector<usr*> > usrs; // Accessible symbol infomation form name };
3
map<string, vector<usr*> >
// Outside of function int i = 1; int i; // ok extern int i; // Of cause ok That's because chosing map<string, vector<usr*> > not map<string, usr*>
4
How backend deal with symbol table?
int i = 1; // (1) int i; // (2) extern int i; // (3) For these delarations, backend shall allocate 4 (=sizeof(int)) bytes with initial value `1' for `i'. For (2) declaration, it is not correct to allocate 4 bytes for `i' because multiple definition of `i'.
5
frontend function lookup()
// For string, return lexical kind by searching symbol table lex::kind_t lookup(string name, scope* ptr) { const map<string, vector<usr*> >& usrs = ptr->usrs; map<string, vector<usr*> >::const_iterator p = usrs.find(name); if ( p != usrs.end() ) { const vector<usr*>& v = p->second; usr* u = v.back(); // POINT : Reference to the last one ... } int i = 1; // (1) int i; // (2) extern int i; // (3) void f(void){ ... use i ... } // Reference to (3) declaration
6
How backend deal with symbol table?(2)
In function `gen' For (1), generate `i' space code with initial value For (2), generate `i' space code with no initial value For (3), just skip because of `extern' These are not correct because of multipe definition of `i' find_if(v.begin(), v.end(), gen); may works roughly. int i = 1; // (1) int i; // (2) extern int i; // (3) Implementation of backend const map<string, vector<usr*> >& usrs = ... for_each(usrs.begin(), usrs.end(), usr); void usr(const pair<string vector<usr*> >& p) { const vector<usr*>& v = p.second; for_each(v.begin(), v.end(), gen); }
7
How backend deal with symbol table?(3)
int i = 1; // (1) int i; // (2) void f(void){ ... use i ... } // Reference to not (1) but to (2). So backend have to decide address descriptor of (2) `i' declaration extern int i; void g(void){ ... use i ... } // Reference to (3) neither (1) or (2). Instad of code generation for some declarations, backend has to decide address descriptor for the last one. i.e: const vector<usr*>& v = p.second; find_if(v.begin(), v.end(), gen); decide_address_descriptor(v.back());
8
Install to the symbol table
void install(usr* curr, scope* ptr) { string name = curr->m_name; map<string, vector<usr*> >& usrs = ptr->m_usrs; map<string, vector<usr*> >::iterator p = usrs.find(name); if ( p != usrs.end() ) { vector<usr*>& v = p->second; usr* prev = v.back(); // Just compare with the last one if (!prev->m_type->compaitble(curr->m_type) || ... ) { // Eror. redeclaration. } else { curr->m_type = prev->m_type->composite(curr->m_type); usrs[name].push_back(curr);
9
Example void f(); // Register as void (...) void g() { }
f(1,2,3); // ok } void f(int); // ok. void (...) is compatible with void (int) // Register as composite type void (int) void h() { f(3); f(1,2,3); // error. void f(); // Once again! void (int) is compatible with void (...) // Register as composite type void (int) not void (...) void i() { f(1,2,3); // error
Similar presentations
© 2024 SlidePlayer.com. Inc.
All rights reserved.