MSDN Magazine - February 2008 - (Page 66) Figure 6 ParseExpr Performs Parsing of Expression Nodes // := // | // | private Expr ParseExpr() { if (this.tokens[this.index] is StringBuilder) { string value = ((StringBuilder)this.tokens[this.index++]).ToString(); StringLiteral stringLiteral = new StringLiteral(); stringLiteral.Value = value; return stringLiteral; } else if (this.tokens[this.index] is int) { int intValue = (int)this.tokens[this.index++]; IntLiteral intLiteral = new IntLiteral(); intLiteral.Value = intValue; return intLiteral; } else if (this.tokens[this.index] is string) { string ident = (string)this.tokens[this.index++]; Variable var = new Variable(); var.Ident = ident; return var; } } For string statements that satisfy the “ ; ” language syntax definition, the sequence AST node is used. This sequence node contains two pointers to stmt nodes and forms the basis of the AST tree structure. The following details the code used to deal with the sequence case: if (this.index < this.tokens.Count && this.tokens[this.index] == Scanner.Semi) { this.index++; if (this.index < this.tokens.Count && !this.tokens[this.index].Equals(“end”)) { Sequence sequence = new Sequence(); sequence.First = result; sequence.Second = this.ParseStmt(); result = sequence; } } The AST tree shown in Figure 7 is the result of the following snippet of Good for Nothing code: var x = “hello world!”; print x; Targeting the .NET Framework When a token is identified, an AST node is created and any further parsing required by the node is performed. The code required for creating the print AST node is as follows: // := print if (this.tokens[this.index].Equals(“print”)) { this.index++; Print print = new Print(); print.Expr = this.ParseExpr(); result = print; } Two things happen here. The print token is discarded by incrementing the index counter, and a call to the ParseExpr method is made to obtain an Expr node, since the language definition requires that the print token be followed by an expression. Figure 6 shows the ParseExpr code. It traverses the list of tokens from the current index, identifying tokens that satisfy the language definition of an expression. In this case, the method simply looks for strings, integers, and variables (which were created by the scanner instance) and returns the appropriate AST nodes representing these expressions. Before I get into the code that performs code generation, I should first step back and discuss my target. So here I will describe the compiler services that the .NET CLR provides, including the stackbased virtual machine, the type system, and the libraries used for .NET assembly creation. I’ll also briefly touch on the tools that are required to identify and diagnose errors in compiler output. The CLR is a virtual machine, meaning it is a piece of software that emulates a computer system. Like any computer, the CLR has a set of low-level operations it can perform, a set of memory services, and an assembly language to define executable programs. The CLR uses an abstract stack-based data structure to model code execution, and an assembly language, called Intermediate Language (IL), to define the operations you can perform on the stack. When a computer program defined in IL is executed, the CLR simply simulates the operations specified against a stack, pushing and popping data to be executed by an instruction. Suppose you want to add two numbers using IL. Here’s the code used to perform 10 + 20: ldc.i4 ldc.i4 add 10 20 Figure 7 helloworld.gfn AST Tree and High-Level Trace The first line (ldc.i4 10) pushes the integer 10 onto the stack. Then the second line (ldc.i4 20) pushes the integer 20 onto the stack. The third line (add) pops the two integers off the stack, adds them, and pushes the result onto the stack. Simulation of the stack machine occurs by translating IL and the stack semantics to the underlying processor’s machine language, either at run time through just-in-time (JIT) compilation or before hand through services like Native Image Generator (Ngen). There are lots of IL instructions available for building your programs—they range from basic arithmetic to flow control to a variety of calling conventions. Details about all the IL instructions can be found in Partition III of the European Computer Manufacturers 66 msdnmagazine .NET Compiler
For optimal viewing of this digital publication, please enable JavaScript and then refresh the page. If you would like to try to load the digital publication without using Flash Player detection, please click here.