Welcome to MSDN Blogs Sign in | Join | Help

Kathy Kam

Reflection on the CLR and .NET
Augmenting to the Good For Nothing Compiler (Part 1 of 2)

A little while back, Joel posted the source to the Good For Nothing (GFN) Compiler and wondered what people can do with it. As a little side project, I added some features to the GFN Compiler which I will post in two parts.

Part 1: Making BCL calls from the GFN Compiler

Part 2: Making Function calls from the GFN Compiler

And without further ado.. here is part 1...

Part 1: Making BCL calls from the GFN Compiler

Here is the grammar modification I did to accomodate making BCL calls:

<stmt> := var <ident> = <expr>
      | <ident> = <expr>
      | <ident> = <func_stmt>
      | for <ident> = <expr> to <expr> do <stmt> end
      | read_int <ident>
      | print <expr>
      | <stmt> ; <stmt>
      | <func_stmt>

<func_stmt> := <scope><func_call>
<scope> := (<namespace>)? <scope>*
<namespace> := <ident>.
<func_call> := <ident> (<args>)

Additons to scanner.cs for class Scanner:

First, I need to scan the new objects for a function call into the tokens.

// Constants to represent arithmitic tokens. This could
// be alternatively written as an enum.
// ....
public static readonly object Comma = new object();
public static readonly object LeftBracket = new object(); // "("
public static readonly object RightBracket = new object(); // ")"

// Switch statment for character
// ....
else switch (ch)

case ',':   
   input.Read(); 
   
result.Add(Scanner.Comma); 
   break;
case '(': 
   input.Read();
   result.Add(Scanner.LeftBracket);
   
break;
case ')':
   input.Read();
   
result.Add(Scanner.RightBracket);
   
break;
}

Additons to Ast.cs:

Then, I created a class to hold a function call.

public class FunctionCall : Stmt 
{ 
    public List<string> DotedScopes; 
    public string FunctionName; 
    public List<Expr> Args; 

    public FunctionCall() 
    { 
        DotedScopes = new List<string>(); 
        Args = new List<Expr>(); 
    } 
}

Additons to Parser.cs for class Paser:

I need to make additions to the Parser so that it can parse the function call into the the class I created in Ast.cs.

    private FunctionCall ParseFunc() 
    { 
        //Function calls 
        FunctionCall func = new FunctionCall(); 

        // function scope 
        while (this.index + 1 < this.tokens.Count 
            && this.tokens[this.index + 1] == Scanner.Dot) 
        { 
            func.DotedScopes.Add((string)this.tokens[this.index++]); 
            // Skips the dot 
            this.index++; 
        } 
        // Function Name 
        if (this.index == this.tokens.Count || 
            !(this.tokens[this.index] is string)) 
        { 
            throw new System.Exception("expected function name after scope"); 
        } 
        func.FunctionName = (string)this.tokens[this.index++]; 

        // Arguments 
        if (this.index == this.tokens.Count || 
            this.tokens[this.index] != Scanner.LeftBracket) 
        { 
            throw new System.Exception("expect open bracket after function name"); 
        } 
        this.index++;   // Skip Left Bracket 

        while ((this.tokens[this.index] != Scanner.RightBracket) 
            && (this.index < this.tokens.Count)) 
        { 
            func.Args.Add(this.ParseExpr()); 
            if (this.tokens[this.index] == Scanner.Comma) 
                this.index++; // Skip comma 
            else if (this.tokens[this.index] == Scanner.RightBracket) 
                break; 
            else 
                throw new System.Exception("unexpected character in arg list"); 
        } 

        if (this.index == this.tokens.Count || 
            this.tokens[this.index] != Scanner.RightBracket) 
        { 
            throw new System.Exception("expect close bracket after open bracket/args"); 
        } 
        this.index++;   // Skip RightBracket 

        return func; 
    } 
} 

Additons to CodeGen.cs for class CodeGen

Now, the best part of writing a compiler... the actual code generation.

    private void CallFunction(FunctionCall func, out System.Type returnType) 
    { 
        System.Type[] typeArray = new System.Type[func.Args.Count]; 
        for (int i = 0; i < func.Args.Count; i++) 
        { 
            typeArray[i] = this.TypeOfExpr(func.Args[i]); 
            this.GenExpr(func.Args[i], typeof(object)); 
        } 
        Reflect.MethodInfo mi = null; 
        // BCL calls 
        if (func.DotedScopes.Count > 0) 
        { 
            Text.StringBuilder scope = new Text.StringBuilder(); 
            foreach (string str in func.DotedScopes) 
            { 
                scope.Append(str + "."); 
            } 
            // Remove the last dot 
            scope.Remove(scope.Length - 1, 1); 
            System.Type type = System.Type.GetType(scope.ToString()); 
            mi = type.GetMethod(func.FunctionName, typeArray); 
        } 
        else 
        // Local Function calls 
        { 
            if (!this.symbolTable.FunctionTable.ContainsKey(func.FunctionName)) 
            { 
                throw new System.Exception("function \"" + func.FunctionName + "\" not declared");     
            } 
            mi = this.symbolTable.FunctionTable[func.FunctionName]; 
        } 
        returnType = mi.ReturnType; 
        this.il.Emit(Emit.OpCodes.Call, mi); 
    } 
Posted: Monday, October 17, 2005 6:49 PM by KathyKam
Filed under:

Comments

barrkel said:

Is there any way you could change DotedScope to DottedScope?

(Yes, I know I'm a pedant. The pain, the pain.)
# October 19, 2005 8:13 AM

Burak SARICA said:

What about boolean expression? Can you show a way to implement boolean? So this may be the first step for If or while statements?

# October 19, 2006 8:26 AM

Isaiah's blog said:

Over the past few weeks I have been developing a version of Joel Pobar&#39;s GFN language that utilizes

# January 8, 2009 4:02 PM
Leave a Comment

(required) 

(required) 

(optional)

(required) 

  
Enter Code Here: Required

Comment Notification

If you would like to receive an email when updates are made to this post, please register here

Subscribe to this post's comments using RSS

Page view tracker