"Digestion of type names" is the digestion of types. The type name is represented by the TypeRef object, and the type is represented by the types object. The digestion of a type name is the conversion of a TypeRef object to a type object.
The processing of the Typeresolver class simply iterates through the abstract syntax tree, and when it finds TypeRef, it starts from the leaf node and converts it to type. The difference between a type and a variable is that there is no scope nesting (scope unique), so no
It is necessary to use stacks.
The correspondence between the TypeRef object and the type object is saved in the Typetable object. 】
Where type is the definition of a type. struct point {int x; int y;}; Is the definition of a type.
TypeRef is the name of the type. Struct point is the name of a type and is deliberately separate from the type class and the TypeRef class because code that uses that type can be written before the type definition. That is, you can write code like the following, which is not written in C:
struct S var;struct s {int memb;};
Digest entry for type name:
/* Portal * *//#@ @range/resolveprogram{public void Resolve (AST AST) {/* * First calls the Definetypes method, generates a type object based on the type defined in the code, and saves it to the Typetable object. The type definitions imported through import are also handled here. */Definetypes (Ast.types ()); /* Type and traversal of the abstract syntax tree. * But the Definetypes method does not handle TypeRef objects such as types of struct members. The processing of converting an existing typeref in an abstract syntax tree to a type is performed in the following foreach statement. If the two-part processing is not separated, the program will fall into a dead loop when dealing with recursive type definitions. Ast.types ()--type definition inside and outside the source file *//#@ @range/resolveprogram_core{for (typedefinition t:ast.types ()) { T.accept (this); }/* * The 2nd foreach statement converts all remaining typeref, such as definitions, global variables, and functions, from the outside of the file to a type using import. Ast.entities ()--declaration of variables and functions imported with import, and definitions of variables and functions within the source file */for (Entity e:ast.entities ()) {E.ACCEP T (this); }/* Above two for loops traverse all types, variables, and functions defined inside and outside the source file, converting all of the TypeRef objects contained therein to the type object. */ // #@@} }
The
performs definetypes first for ast.types (), i.e. structnode (struct definition), Unionnode (Union definition), typedefnode (user type definition):
/* Declaration of type. * Definetypes is a way to add a type definition to a typetable object *//#@ @range/definetypes{private void Definetypes (List<typedefiniti On> deftypes) {/* * Use a foreach statement to remove the Typedefinition object from the Deftypes one by one, associating Def.typeref () and Def.definingtype () in pairs, using Ty The Petable.put method is added to the typetable. Def.typeref () returns the TypeRef (type name) of the type to be defined for the Typedefinition object. Def.definingtype () returns the type (s) to be defined for the Typedefinition object. */for (typedefinition def:deftypes) {/* * but if typetable.isdefined () is true, this typeref already exists and this Add processing and output an error message. */if (typetable.isdefined (Def.typeref ())) {error (Def, "duplicated type definition:" + Def.typ Eref ()); The else {/* * * Typedefinition class is an abstract class, and the actual generated instance is typedefinition subclass Structnode, Unionnode, Typed Efnode. Structnode represents the definition of a struct, unionnode represents the definition of a union, and Typedefnode represents a typedef statement. Structnode#definingtype:public Type Definingtype () {return new Structtype (name (), members (), location ());} Call TypetThe Able#put method adds the resulting Strcuttype object to the Typetable object. The Typetable object is internally saved with HashMap objects, so the Typetable#put method simply calls Hashmap#put. */Typetable.put (Def.typeref (), Def.definingtype ()); } } }
Keep the names and types of the above three types in typetable, and note that when Typetable is initialized, all basic types are automatically put in. Then the first for loop of the three visit methods:
#@ @range/structnode{public Void visit (structnode struct) { resolvecompositetype (struct); return null; } #@@} //#@ @range/unionnode{public Void visit (Unionnode Union) { Resolvecompositetype (union); return null; } #@@} //#@ @range/typedefnode{public Void visit (typedefnode typedef) { Bindtype (Typedef.typenode () ); Bindtype (Typedef.realtypenode ()); return null; } // #@@}
Then:
public void Resolvecompositetype (Compositetypedefinition def) { Compositetype ct = (compositetype) typetable.get ( Def.typenode (). TYPEREF ()); if (ct = = null) { throw new Error ("Cannot intern struct/union:" + def.name ()); } For (Slot s:ct.members ()) { Bindtype (S.typenode ()); } } / * * First, use the Typenode#isresolved method to check if the conversion has been completed, and if it is completed, immediately end processing with return. If not, remove the typeRef from the Typenode with N.typeref (), convert the Typetable.get to the type object, and then set the type Object N.settype to Typenode. * ///#@ @range/bindtype{ private void Bindtype (Typenode n) { if (n.isresolved ()) return; N.settype (Typetable.get (N.typeref ())); }
Also very simple, resolvecompositetype is a type check for each type of member, the key class is Typenode, from which TypeRef (the name of the type) is obtained, and the definition of the existing type is obtained from typetable by the name of the type. It then gets all the member variables of the current type, and then binds the name and definition of the type of the member variable through the Bindtype method. Typetable is actually the role of a transit station.
The second for loop is to convert all remaining TypeRef except the above three types to type. Like what:
/ * * variable-defined type digestion. * ///#@ @range/definedvariable{public Void visit (definedvariable var) {/ * * TYPEREF Objects are basically stored in the Typenode object. Typenode is an object that stores TypeRef and type in pairs to simplify the code of the Typeresolver class. * /Bindtype (Var.typenode ()); if (Var.hasinitializer ()) { visitexpr (Var.initializer ()); } return null; }
There are also important types of functions:
/* * function-defined type digestion. *///#@ @range/definedfunction{public Void visit (definedfunction func) {/* * in function definition, there are typeref in these places. 1. Type 2 of the return value. The type of the formal parameter 3. The code of the function body */Resolvefunctionheader (func); Visitstmt (Func.body ()); return null; The 1th line of the private void Resolvefunctionheader (Function func) {/* * Resolvefunctionheader method is used to process the type of the return value. Func.typenode () returns the Typenode object that holds the return value type, and then calls the Bindtype method to convert the type of the return value from TypeRef to type. */Bindtype (Func.typenode ()); /* * The Resolvefunctionheader method is the processing of the formal parameter starting from line 2nd. The Func.parameters () is traversed with a foreach statement, and the Parameter object representing the formal parameter is taken out. Then use Param.typenode () to remove the Typenode object from the Parameter object and convert the TypeRef to type. */For (Parameter param:func.parameters ()) {//arrays must is converted to pointers in a function par Ameter. /* * The GetParamType method of the Typetable class is used only when the TypeRef of the formal parameter is converted to type. The difference between it and the usual get method is that the TypeRef of the array is converted to the type of the pointer. The C language (c?) parameter type is identical to the pointer type in the case of an array, so it is unified here as a pointer type. */ Type t = Typetable.getparamtype (Param.typenode (). TYPEREF ()); Param.typenode (). SetType (t); } }
First call the Resolvefunctionheader method, where the first line is the return type of the binding function, and then a for loop binds all the parameter types of the function. Then call Visitstmt (Func.body ()); All types of binding function bodies:
Public Void Visit (blocknode node) {in (definedvariable var:node.variables ()) { var.accept (this); } Visitstmts (Node.stmts ()); return null; }
Compiler Development Series--ocelot Language 3. Digestion of type names