Using a Single Type of Semantic Value for










- Slides: 10
Using a Single Type of Semantic Value for Nonterminals and Terminals • Semantic values for nonterminals are constructed from the semantic values of other grammar symbols. – arithmetic_expression : arithmetic_expression '+' term { $$ = new ASTMethod. Call($1, $2, new ASTArg. List. Simple($3)); } • If the type of all semantic values is ASTNode *, then the constructor for ASTMethod. Call must be declared as follows: – ASTNode *ASTMethod. Call(ASTNode *rcvr, ASTNode *op, ASTNode *args) • Alternatively, one could downcast the arguments to the more specific types: – ASTNode *ASTMethod. Call(ASTExpression *rcvr, ASTIdentifier *op, ASTArg. List *args) – $$ = new ASTMethod. Call(dynamic_cast<ASTExpression*>($1), dynamic_cast<ASTIdentifier*>$2, new ASTArg. List. Simple($3));
Using Multiple Types of Semantic Value for Nonterminals and Terminals • To get a better handle on semantic value type, determine the collection of types that can be used as semantic values and use the bison %union construct to list these: – %union { ASTExpression. List *Expression. List; ASTExpression *Expression; ASTAssignment *Assignment; ASTIdentifier *Identifier; . . . } • Declare a bison %type for each nonterminal and terminal in your grammar – %type <Expression> %type <Identifier> • factor; operator; IDENTIFIER_TOKEN; Then each of the semantic values referenced through $1, . . . $n, $$ will be declared to have the appopriate type and type-specific constructors can be used.
Project Questions • What is the relation of Garnet. Objects to ASTNodes? – Your parser actions will create ASTNodes – When you call eval on the whole program AST Node, you will create Garnet. Objects. – start: expression_sequence { $1 ->ASTPrint(cout); // while debugging $1 -> eval(); } // to eval the whole program ; expression_sequence: . . . • Do we have to implement Arrays in our program? – You will need to have Array Garnet. Objects so that you can call methods with multiple arguments. – You do not need to support input of array literals, but it is practically free once you’ve implemented them – factor : . . . | ‘[‘ arglist ‘]’. . .
Project Questions • What is the structure of our referencing environment? – You only need to implement a single global frame. – Your frame must contain some representation of the mapping of variable names to their values. I suggest you use a Standard Template Library map for this purpose. In Garnet, each object has a type (its class), no name has a type. • What methods does each built-in class have to contain? – – – – – Object: print Integer: to_s, +, -, !, *, /, <, >, <=, >=, == Float : to_s, +, -, !, *, /, <, >, <=, >=, == String: to_s Array: get_element, set_element, to_s Method: dispatch, to_s Class: new, superclass, lookup_method, to_s True. Class: to_s, ! False. Class: to_s, ! Nil. Class: to_s, !
Further Project Questions • What about all that stuff Ashish was asking? – Use this grammar rule for your factors (or something similar) and I think you’ll be happy: – factor : identifier | '[' arglist ']' | INTEGER_TOKEN | FLOAT_TOKEN | factor '(' arglist') ' | factor '. ' operator /* make some ASTNode subclass for this */ | factor '[' expression '] ' | '(' expression ')' { $$ = $2; } ; operator: identifier | '+' | '-' | '*' | '/'. . . ;
Garnet Object Representations and the Class Hierarchy Class The Integer 1 Object Integer “+” : String (Class) 1 : superclass myclass slots method_objects method_names instance_slot_names Method (Class) code for +
How do we represent all those Objects? • Here’s my declaration of the Garnet. Object Class: – class Garnet. Object { private: Garnet. Object *myclass; vector<Garnet. Ptr> slotsvec; Garnet. Object(const Garnet. Object& init); public: Garnet. Object(); Garnet. Object(Garnet. Object *cls, vector<Garnet. Ptr> slots); const Garnet. Object& operator= (const Garnet. Object& rhs); static void do_init(); };
What is a Garnet. Ptr? • I’ve relented and am now making the Garnet. Ptr a poor man’s implementation of a discriminated union. Here’s the discriminant type: – typedef enum { d_none, d_gptr, d_strptr, d_intval, d_floatval, d_funcptr } Garnet. Ptr. Discriminator; • Here’s a union type that matches this discriminant – typedef Garnet. Ptr (*Method. Ptr)(Garnet. Ptr, Garnet. Ptr); typedef union { Garnet. Object *gptr; string *strptr; intval; double floatval; Method. Ptr funcptr; } primitive;
This is a Garnet. Ptr • Here’s the Garnet. Ptr class in all its glory: – class Garnet. Ptr { private: Garnet. Ptr. Discriminator d; primitive u; public: Garnet. Ptr(); Garnet. Ptr(const Garnet. Ptr &init); Garnet. Ptr& operator= (const Garnet. Ptr &rhs); Garnet. Ptr(Garnet. Object *arg); Garnet. Ptr(string *arg); Garnet. Ptr(int arg); Garnet. Ptr(double arg); Garnet. Ptr(Method. Ptr arg); }; Garnet. Object *gp() const; string *sp() const; int iv() const; double fv() const; Method. Ptr fp() const;
How about the Garnet. Ptr Constructors and Selectors • The constructors set the discriminant: – Garnet. Ptr: : Garnet. Ptr(string *arg) { d = d_strptr; u. strptr = arg; } • The selectors query the discriminant: – void discriminant_error(Garnet. Ptr. Discriminator d 1, Garnet. Ptr. Discriminator d 2) { cerr << "Discriminant Error: expected " << d 1 << ", got " << d 2 << endl; exit(255); } string * Garnet. Ptr: : sp() const { if (d != d_strptr) { discriminant_error(d_strptr, d); } return u. strptr; }