Interface between frontend and backend Kei Hasegawa 2019.03.08
The least functions needed for code generation (1) int generator_seed(); For confirmation that the same compiler compiles frontend and backend. And also for getting rid of using backend for C++, which is compiled as a C backend. Please copy other working backend code. int generator_open_file(const char* fn); For opening a file which is for writing code generation reult. If the file can be opended normally, return 0. Otherwise return none-zero.
The least functions needed for code generation (2) struct interface_t { const scope* m_root; // symbol table fundef* m_func; // function(name、type etc) and parameter scope vector<tac*> m_code; // 3 address code of the function }; void generator_generate(const interface_t* info); This function is called when it needed to generate function code. Or at the end of file, this function is called if symbol table must be reflected code generation. In this case, this function is called with interface_t::m_func = 0. If m_func is not equal to 0, frontend garantees m_root->m_children.back() == m_func->m_param. m_root->m_children.size() == 1 is not true at C++ Compiler
The least functions needed for code generation (3) int generator_close_file(); For closing file which is opened by generator_open_file. If the file can be closed normally, return 0. Otherwise, return none-zero.
Optional functions for code generation (1) void generator_option(int argc, const char** argv, int* error); For passing option to backend. argv[0] is set path of backend generator. Option strings are set to argv[1], argv[2], ..., argv[argc-1]. error[0], ..., error[argc-1] are for notification frontend that error occured while dealing with options if none-zero is set.
Optional functions for code generation (2) void generator_spell(void*); This function is used for different purpose in days gone by. Reference to source files which could be build by VC++6.0. Now, the pointer to the function which dumps 3 address code, is passed to backend. int generator_sizeof(int id); For asking size of type denoted by `id'. This fuction calls are repeatedly done before code generation. `id' is one of bellow: type::SHORT, type::INT, type::LONG, type::LONGLONG, type::FLOAT, type::DOUBLE, type::LONG_DOUBLE and type::POINTER If this function is not defined, size of type is the same with compiler size of type, where the compiler is used for compiling frontend.
Optional functions for code generation (3) int generator_sizeof_type() For deciding the result type of sizeof operator, return one of type::UINT, type::ULONG or type::ULONGLONG. If this function is not defined, the result type of sizeof operator is unsigned int. This function is called at once before code generation like generator_sizeof. int generator_wchar_type() For deciding the type of wchar_t, return one of type::SHORT, type::USHORT, type::INT, type::UINT, type::LONG or type::ULONG. If this function is not defined, wchar_t type will be unsigned short int. This function is called at once before code generation like generator_sizeof. int generator_ptrdiff_type() For decidign the type of ptrdiff_t, return one of type::INT, type::LONG or type::LONGLONG. If this function is not defined, ptrdiff_t type will be long. This function is called at once before code generation like generator_sizeof. bool require_align(); When frontend decides layout of structure, if alignment is not necessary, define this function and return false. If you don't define this function, or define this function which return true, frontend does alignment.
Optional functions for code generation (4) struct long_double_t { void (*bit)(unsigned char* res, const char* str); void (*add)(unsigned char* x, const unsigned char* y); // x := x + y void (*sub)(unsigned char* x, const unsigned char* y); // x := x - y void (*mul)(unsigned char* x, const unsigned char* y); // x := x * y void (*div)(unsigned char* x, const unsigned char* y); // x := x / y void (*minus)(unsigned char* x, const unsigned char* y); // x := -y bool (*zero)(const unsigned char*); double (*to_double)(const unsigned char*); void (*from_double)(unsigned char*, double); bool (*cmp)(goto3ac::op, const unsigned char*, const unsigned char*); }; long_double_t* generator_long_double(); For executing runtime evalation for long double at bakend not frontend. long_double_t::bit is called for getting long double bit expression according to literal ( ex "1.5L"). は
Other struct last_interface_t { }; scope* m_root; // symbol table vector<pair<const fundef*, vector<tac*> >* m_funcs; // whole of function and its 3 address code }; void generator_last(last_interface_t* info); This function is called when frontend compile all of a file. Backend can whole of symbol table and functions. If this function is defined, frontend doesn't free heap area which is freed originally. Use generator_generate for code generation. As far as C Compiler, m_root->children.size() == m_funcs->size() && for each i , m_root->children[i] == m_funcs[i].first->m_param
x := y Type of x is not incomplete type and not function. If unqualified version of type of x is not pointer type, the type is compatible with unqualified version of type of y. If unqualified version of type of x is pointer to T1, y is 0 or unqualified version of type of y is pointer to T2, unqualified version of T1 is compatible with unqualified version of T2.
x := y + z Both y and z are promoted. If both type of y and type of z are arithmetic type, arithmetic conversions are already performed. Unqualified version of type of x is the same with unqualified version of type of y. If unqualified version of type of y is pointer type, type of z is integer type. Conversely if unqualified version of type of z is pointer type, type of y is integer type. In former case, condition 3.2 of x := y is hold between type of x and type of y.
x := y - z Same with 1, 2 of x := y + z If both unqualified version of type of y and unqualified version of type of z are pointer type, condition 3.2 of x := y is hold between type of y and type of z. Type of x is ptrdiff_t. If unqualified version of type of y is pointer type and type of z is integer type, condition 3.2 of x := y is hold between type of x and type of y.
x := y * z Same with 1, 2 of x := y + z Both type of y and type of z shall be arithmetic type.
x := y % z Same with 1, 2 of x := y + z Both type of y and type of z shall be integer type.
x := y << z, x := y >> z Both y and z are promoted. Both type of y and type of z shall be integer type. Unqualified version of type of x is the same with unqualified version of type of y.
x := y & z, x := y ^ z, x := y | z Same with 1, 2 of x := y + z Both type of y and type of z shall be integer type.
x := -y y is promoted. Type of y is arithmetic type. Unqualified version of type of x is the same with unqualified version of type of y.
x := ~y y is promoted. Type of y shall be integer type. Unqualified version of type of x is the same with unqualified version of type of y.
x := (T)y Both type of x and type of y shall be scalar type. Unqualified version of type of x is the same with T.
param y Type of y is not function type. Type of y may be incomplete type. Backend can know the size of y like bellow: const type* T = y->m_type; T = T->complete_type(); int size = T->size(); `param's can only exist until following `call'. i.e: param y1 param y2 ... param yn x := call f
x := call y, call y Type of y is function type or pointer to function type. Unqualified version of type of x is compatible with the function return type. Type of x is not incomplete type. call y may be generated instead of x := call y even if return type is not void.
return y, return If return y is one of 3 address code of some function, type of y is compatible with return type of the function and is complete type.
goto to, to `to' is one of 3 address code. If a `to' is referenced by a goto, the `to' must be in 3 address code of the same function.
if y op z goto to op is one of ==, !=, <, >, <=, >= One of the bellow conditions holds: y and z are performed arithmetic conversion. If unqualified version of type of y is pointer type, condition 3.2 of x := y is hold between type of y and type of z. If op is == or != and unqualified version of type of y is pointer type, z can be 0. Conversely, y can be 0 if op is == or != and unqualified version of type of z is pointer type.
x := &y y is not constant. Condition 3.2 of x := y is hold between type of x and pointer type to type of y. y may be compiler medium variable.
*y := z, x := *y Type of z and type of x are complete type except for function type. Describe this type as T, type of y is pointer to T or pointer to qualified T.
x[y] := z (1) x := y[z] (2) Type of y of (1) and Type of z of (2) are integer type. Type of x of (1) and type of y of (2) are one of: complete array type incomplete array type complete structure type or union type incomplete structure type or union type Type of z of (1) and type of x of (2) are complete type except for function type.
x := alloca y Tyep of x is variable length array type. x is used afer x := alloca y. Type of y is integer type.
X := asm string, Y, R X is the set of possibly modified variables. Y is the set of possibly referenced variables. R is the set of possibly used registers.
x := va_start y, x := va_arg y, T, va_end y These are correspond to va_start(x,y), x = va_arg(y,T) and va_end(y).