Commit 7e671b3a authored by Bednárek David RNDr. Ph.D.'s avatar Bednárek David RNDr. Ph.D.
Browse files

new faq items

parent 385fa52b
......@@ -119,3 +119,78 @@ typedef int TF2(const int, const int);
These two typedefs are by definition identical (the const flag on a parameter is simply ignored because it does not affect the caller).
Therefore, it is easier to handle the type descriptors independently of the const flag. The only case where the const flag is a part of a type descriptor is a pointer, i.e. `const X*` is different from `X*`.
A typedef stores a pair of a type descriptor and a const flag, which is exactly the contents of the structure `CKTypeRefPack`. And you may also use the structure in your code, for instance when representing a type specifier list like `T2` or `const int`.
### Is "IRBuilderBase::getCurrentFunctionReturnType" the correct way to retrieve the return type of the actual function?
No, it only returns the LLVM IR type descriptor which is insufficient to correctly check the type rules of Cecko.
`CKContext::current_function_return_type` returns the correct type descriptor.
### What is the underlying type for enums in Cecko?
`int`. The behavior of Cecko is slightly different from the definition of (modern) C. It is wired into the framework because `get_ir` on an enum descriptor returns the LLVM IR descriptor for `i32`, simply because LLVM IR does not recognize enums. Furthermore, `get_type` on enum constants returns the descriptor for `int`, i.e. not their respective enum descriptor. Since `int` and enums are implicitly convertible, there is no consequence of this behavior. (On the other hand, the pointer to `int` is different from the pointer to an enum; therefore, variables must correctly keep their enum type because pointers may point at them.)
### How can I call "enter_block()" at the beginning of the compound_statment?
You have to rewrite the grammar slightly so that you can call enter_block before or immediately after LCUR.
### What is the best way to handle the recursive structure of direct_declarator? Is it better to transform the grammar somehow or to create a temporary data structure representing the actual declarator?
Rewriting the grammar does not help. Logically, you need a list of objects of three different types (representing the array/pointer/function declarators); you will later have to traverse the list in the opposite order with respect to the order of construction. It may be represented by a linked list or a container; in any case, you need to solve the variability of the types. There are three options in C++: Inheritance (the cleanest but the most work-intensive and also the slowest), `std::variant` or just a struct containing all the required data elements (always leaving some of them unused). In addition, functional-programming gurus may use `std::function` and lambdas (creating, in fact, a linked list of functor objects).
Furtheremore, there is (optionally) an identifier buried inside the declarator. It may be represented as a fourth type of objects in the list (providing an ellegant terminator if implemented by a linked list). However, passing the identifier (and its line number) besides the list is probably simpler. In any case, the `%type` for a declarator will be the most complex temporary data structure needed in the semantic analysis of Cecko.
### How to retrieve the enum/struct descriptor for a previously declared enum/struct?
Identifiers occuring after the keyword `struct` or `enum` belong to a special category of identifiers, called _Tags_. The functions `find` and `find_typedef` work with other categories and, thus, they are not usable to find the meaning of a Tag.
Furthermore, every presence of `struct` or `enum` may be a declaration of the Tag. Therefore, the functions `declare_struct_type` and `declare_enum_type` are the only way how to retrieve a struct/enum descriptor - internally, the functions will decide whether to return a previously created descriptor or a new one.
### How to retrieve the "CKFunctionObs" needed for "enter_function()" when the function was already declared?
The correct way is to call `declare_function` (again) - it will not report any error for duplicite declaration if the type is identical to the previous declaration.
### How to represent declarations like "int f(void)"?
The `void` is only a syntactic matter (due to the distant history of C), no parameter representation shall be created for the `void`. The case of a single `void` argument must be specifically detected (in the semantics; handling by grammar adjustment would be too difficult) and `get_function_type` must be called with an empty list of arguments in this case.
### "declare_struct_type" returns the same descriptor pointer for both the global and the local "struct" in this example:
struct mighty_str;
int main(int argc, char** argv)
struct mighty_str;
return 0;
`struct X;` shall create a new struct descriptor only if no previous declaration is in sight. Because of this, you see the same pointer.
On the other hand, `struct X {};` must always create a new descriptor - therefore, you have to call `define_struct_type_open` instead of `declare_struct_type` in this case.
Note that, for simplicity, Cecko rules are slightly different from C: In C, `struct X a;` behaves differently from `struct X;` - the former enforces a new declaration if none is visible while the latter is a declaration if none is in the same scope. In Cecko, the latter case has no special handling.
### What is the required contents of "CKFunctionFormalPackArray" in the call to "enter_function()"? Is it possible to retrieve it from "CKFunctionSafeObs"?
`CKFunctionFormalPackArray` represent exactly the information contained in the function header which is not (by definition) the part if the function type and, therefore, it is not stored in `CKFunctionSafeObs`. You have to collect this information on your own, i.e. to split the information in a parameter list into two groups - parameter types and the rest (const flags and identifiers, if any). The rest goes into the `CKFunctionFormalPackArray`. If the function declarator is not a part of function definition, the rest is silently ignored.
### How to represent the "char" in "int(*pfix)(char)"?
Notice that this a pointer to a function that returns `int` and accepts `char` as an argument. So what you need to do:
1. process function parameters (in this case it is `char`) to list of arguments (`CKTypeObsArray`)
2. call `get_function_type` with return type as `int`, arguments being the list you got from 1, and `variadic` being false.
3. wrap the return value from 2 into `CKTypeRefPack`.
4. pass the pack from 3 to `get_pointer_type`.
5. Wrap what you got from 4 into a `CKTypeRefPack`.
6. Then you can `define_var` with the name `pfix` and the pack that you got from 5.
### How to access struct members when we only have its value (R-value) and not its address (L-value)?
Call `CreateExtractValue` instead of `CreateStructGEP`. The former converts a value to a value, the latter a pointer to a pointer.
Note that the former is needed only in cases like `f().m`.
### What is the result type of (==, !=, <, <=, >, >=, &&, ||, !) - "int" or "_Bool"?
With respect to the language behavior, the question has no real meaning because the results are R-values and there are consistent implicit conversions between `int` and `_Bool` in both directions. In other words, you cannot determine which type the compiler has selected from the behavior of the resulting program.
The pragmatic choice is `_Bool` because the `ICmp` instructions return `i1` which is the LLVM IR representation of Cecko `_Bool`. Choosing `int` would require additional (forth and back) conversion instructions in cases like `_Bool x; x = a < b;`.
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment