[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

6. API's available in the generated output

The source code that is generated by treecc exports a number of application programmer interfaces (API's) to the programmer. These can be used elsewhere in the compiler implementation to manipulate abstract syntax trees. The following sections describe the API's for each of the output languages.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

6.1 C Language APIs

In the C output language, each node type is converted into a ‘typedef’ that contains the node's fields, and the fields of its ancestor node types. The following example demonstrates how treecc node declarations are converted into C source code:

 
%node expression %abstract %typedef =
{
    %nocreate type_code type;
}
%node binary expression %abstract =
{
    expression *expr1;
    expression *expr2;
}
%node plus binary

becomes:

 
typedef struct expression__ expression;
typedef struct binary__ binary;
typedef struct plus__ plus;

struct expression__ {
    const struct expression_vtable__ *vtable__;
    int kind__;
    char *filename__;
    long linenum__;
    type_code type;
};
struct binary__ {
    const struct binary_vtable__ *vtable__;
    int kind__;
    char *filename__;
    long linenum__;
    type_code type;
    expression * expr1;
    expression * expr2;
};
struct plus__ {
    const struct plus_vtable__ *vtable__;
    int kind__;
    char *filename__;
    long linenum__;
    type_code type;
    expression * expr1;
    expression * expr2;
};

Programmers should avoid using any identifiers that end in ‘__’. Such identifiers are reserved for internal use by treecc and its support routines.

For each non-abstract node type called ‘NAME’, treecc generates a function called ‘NAME_create’ that creates nodes of that type. The general form of the function's prototype is as follows:

 
TYPE *NAME_create([YYNODESTATE *state,] PARAMS)
TYPE

The return node type, which is the nearest ancestor that has the ‘%typedef’ flag.

NAME

The name of the node type that is being created.

state

The system state, if reentrant code is being generated.

PARAMS

The create parameters, consisting of every field that does not have the ‘%nocreate’ flag. The parameters appear in the same order as the fields in the node types, from the top-most ancestor down to the node type itself. For example:

 
expression *plus_create(expression * expr1, expression * expr2);

Enumerated types are converted into a C ‘typedef’ with the same name and values:

 
%enum JavaType =
{
    JT_BYTE,
    JT_SHORT,
    JT_CHAR,
    JT_INT,
    JT_LONG,
    JT_FLOAT,
    JT_DOUBLE,
    JT_OBJECT_REF
}

becomes:

 
typedef enum
{
    JT_BYTE,
    JT_SHORT,
    JT_CHAR,
    JT_INT,
    JT_LONG,
    JT_FLOAT,
    JT_DOUBLE,
    JT_OBJECT_REF

} JavaType;

Virtual operations are converted into C macros that invoke the correct vtable entry on a node type:

 
%operation %virtual void infer_type(expression *e)

becomes:

 
#define infer_type(this__) \
    ((*(((struct expression_vtable__ *) \
        ((this__)->vtable__))->infer_type_v__)) \
            ((expression *)(this__)))

Calls to ‘infer_type’ can then be made with ‘infer_type(node)’.

Non-virtual operations are converted into C functions:

 
%operation void infer_type(expression *e)

becomes:

 
extern void infer_type(expression *e);

Because virtual and non-virtual operations use a similar call syntax, it is very easy to convert a virtual operation into a non-virtual operation when the output language is C. This isn't possible with the other output languages.

Other house-keeping tasks are performed by the following functions and macros. Some of these must be supplied by the programmer. The ‘state’ parameter is required only if a reentrant compiler is being built.

int yykind(ANY *node)

Gets the numeric kind value associated with a particular node. The kind value for node type ‘NAME’ is called ‘NAME_kind’.

const char *yykindname(ANY *node)

Gets the name of the node kind associated with a particular node. This may be helpful for debugging and logging code.

int yyisa(ANY *node, type)

Determines if ‘node’ is an instance of the node type ‘type’.

char *yygetfilename(ANY *node)

Gets the filename corresponding to where ‘node’ was created during parsing. This macro is only generated if ‘%option track_lines’ was specified.

long yygetlinenum(ANY *node)

Gets the line number corresponding to where ‘node’ was created during parsing. This macro is only generated if ‘%option track_lines’ was specified.

void yysetfilename(ANY *node, char *value)

Sets the filename associated with ‘node’ to ‘value’. The string is not copied, so ‘value’ must persist for the lifetime of the node. This macro will rarely be required, unless a node corresponds to a different line than the current parse line. This macro is only generated if ‘%option track_lines’ was specified.

void yysetlinenum(ANY *node, long value)

Sets the line number associated with ‘node’ to ‘value’. This macro will rarely be required, unless a node corresponds to a different line than the current parse line. This macro is only generated if ‘%option track_lines’ was specified.

char *yycurrfilename([YYNODESTATE *state])

Get the name of the current input file from the parser. The pointer that is returned from this function is stored as-is: the string is not copied. Therefore, the value must persist for at least as long as the node will persist. This function must be supplied by the programmer if ‘%option track_lines’ was specified.

long yycurrlinenum([YYNODESTATE *state])

Get the number of the current input line from the parser. This function must be supplied by the programmer if ‘%option track_lines’ was specified.

void yynodeinit([YYNODESTATE *state])

Initializes the node memory manager. If the system is reentrant, then the node memory manager is ‘state’. Otherwise a global node memory manager is used.

void *yynodealloc([YYNODESTATE *state,] unsigned int size)

Allocates a block of memory of ‘size’ bytes in size from the node memory manager. This function is called automatically from the node-specific ‘*_create’ functions. The programmer will not normally need to call this function.

This function will return NULL if the system is out of memory, or if ‘size’ is too large to be allocated within the node memory manager. If the system is out of memory, then ‘yynodealloc’ will call ‘yynodefailed’ prior to returning NULL.

int yynodepush([YYNODESTATE *state])

Pushes the current node memory manager position. The next time yynodepop is called, the node memory manager will reset to the pushed position. This function returns zero if the system is out of memory.

void yynodepop([YYNODESTATE *state])

Pops the current node memory manager position. This function has no effect if yynodepush was not called previously.

The yynodepush and yynodepop functions can be used to perform a simple kind of garbage collection on nodes. When the parser enters a scope, it pushes the node memory manager position. After all definitions in the scope have been dealt with, the parser pops the node memory manager to reclaim all of the memory used.

void yynodeclear([YYNODESTATE *state])

Clears the entire node memory manager and returns it to the state it had after calling yynodeinit. This is typically used upon program shutdown to free all remaining node memory.

void yynodefailed([YYNODESTATE *state])

Called when yynodealloc or yynodepush detects that the system is out of memory. This function must be supplied by the programmer. The programmer may choose to exit to program when the system is out of memory; in which case yynodealloc will never return NULL.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

6.2 C++ Language APIs

In the C++ output language, each node type is converted into a ‘class’ that contains the node's fields, virtual operations, and other house-keeping definitions. The following example demonstrates how treecc node declarations are converted into C++ source code:

 
%node expression %abstract %typedef =
{
    %nocreate type_code type;
}
%node binary expression %abstract =
{
    expression *expr1;
    expression *expr2;
}
%node plus binary

becomes:

 
class expression
{
protected:

    int kind__;
    char *filename__;
    long linenum__;

public:

    int getKind() const { return kind__; }
    const char *getFilename() const { return filename__; }
    int getLinenum() const { return linenum__; }
    void setFilename(char *filename) { filename__ = filename; }
    void setLinenum(long linenum) { linenum__ = linenum; }

    void *operator new(size_t);
    void operator delete(void *, size_t);

protected:

    expression();

public:

    type_code type;

    virtual int isA(int kind) const;
    virtual const char *getKindName() const;

protected:

    virtual ~expression();

};

class binary : public expression
{
protected:

    binary(expression * expr1, expression * expr2);

public:

    expression * expr1;
    expression * expr2;

    virtual int isA(int kind) const;
    virtual const char *getKindName() const;

protected:

    virtual ~binary();

};

class plus : public binary
{
public:

    plus(expression * expr1, expression * expr2);

public:

    virtual int isA(int kind) const;
    virtual const char *getKindName() const;

protected:

    virtual ~plus();

};

The following standard methods are available on every node type:

int getKind()

Gets the numeric kind value associated with a particular node. The kind value for node type ‘NAME’ is called ‘NAME_kind’.

virtual const char *getKindName()

Gets the name of the node kind associated with a particular node. This may be helpful for debugging and logging code.

virtual int isA(int kind)

Determines if the node is a member of the node type that corresponds to the numeric kind value ‘kind’.

const char *getFilename()

Gets the filename corresponding to where the node was created during parsing. This method is only generated if ‘%option track_lines’ was specified.

long getLinenum()

Gets the line number corresponding to where the node was created during parsing. This method is only generated if ‘%option track_lines’ was specified.

void setFilename(char *value)

Sets the filename associated with the node to ‘value’. The string is not copied, so ‘value’ must persist for the lifetime of the node. This method will rarely be required, unless a node corresponds to a different line than the current parse line. This method is only generated if ‘%option track_lines’ was specified.

void setLinenum(long value)

Sets the line number associated with the node to ‘value’. This method will rarely be required, unless a node corresponds to a different line than the current parse line. This method is only generated if ‘%option track_lines’ was specified.

If the generated code is non-reentrant, then the constructor for the class can be used to construct nodes of the specified node type. The constructor parameters are the same as the fields within the node type's definition, except for ‘%nocreate’ fields.

If the generated code is reentrant, then nodes cannot be constructed using the C++ ‘new’ operator. The ‘*Create’ methods on the ‘YYNODESTATE’ factory class must be used instead.

The ‘YYNODESTATE’ class contains a number of house-keeping methods that are used to manage nodes:

static YYNODESTATE *getState()

Gets the global ‘YYNODESTATE’ instance that is being used by non-reentrant code. If an instance has not yet been created, this method will create one.

When using non-reentrant code, the programmer will normally subclass ‘YYNODESTATE’, override some of the methods below, and then construct an instance of the subclass. This constructed instance will then be returned by future calls to ‘getState’.

void *alloc(size_t size)

Allocates a block of memory of ‘size’ bytes in size from the node memory manager. This function is called automatically from the node-specific constructors and ‘*Create’ methods. The programmer will not normally need to call this function.

This function will return NULL if the system is out of memory, or if ‘size’ is too large to be allocated within the node memory manager. If the system is out of memory, then ‘alloc’ will call ‘failed’ prior to returning NULL.

int push()

Pushes the current node memory manager position. The next time pop is called, the node memory manager will reset to the pushed position. This function returns zero if the system is out of memory.

void pop()

Pops the current node memory manager position. This function has no effect if push was not called previously.

The push and pop methods can be used to perform a simple kind of garbage collection on nodes. When the parser enters a scope, it pushes the node memory manager position. After all definitions in the scope have been dealt with, the parser pops the node memory manager to reclaim all of the memory used.

void clear()

Clears the entire node memory manager and returns it to the state it had after construction.

virtual void failed()

Called when alloc or push detects that the system is out of memory. This method is typically overridden by the programmer in subclasses. The programmer may choose to exit to program when the system is out of memory; in which case alloc will never return NULL.

virtual char *currFilename()

Get the name of the current input file from the parser. The pointer that is returned from this function is stored as-is: the string is not copied. Therefore, the value must persist for at least as long as the node will persist. This method is usually overrriden by the programmer in subclasses if ‘%option track_lines’ was specified.

virtual long currLinenum()

Get the number of the current input line from the parser. This method is usually overridden by the programmer in subclasses if ‘%option track_lines’ was specified.

The programmer will typically subclass ‘YYNODESTATE’ to provide additional functionality, and then create an instance of this class to act as the node memory manager and node creation factory.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

6.3 Java Language APIs

In the Java output language, each node type is converted into a ‘class’ that contains the node's fields, virtual operations, and other house-keeping definitions. The following example demonstrates how treecc node declarations are converted into Java source code:

 
%node expression %abstract %typedef =
{
    %nocreate type_code type;
}
%node binary expression %abstract =
{
    expression expr1;
    expression expr2;
}
%node plus binary

becomes:

 
public class expression
{
    protected int kind__;
    protected String filename__;
    protected long linenum__;

    public int getKind() { return kind__; }
    public String getFilename() { return filename__; }
    public long getLinenum() const { return linenum__; }
    public void setFilename(String filename) { filename__ = filename; }
    public void setLinenum(long linenum) { linenum__ = linenum; }

    public static final int KIND = 1;

    public type_code type;

    protected expression()
    {
        this.kind__ = KIND;
        this.filename__ = YYNODESTATE.getState().currFilename();
        this.linenum__ = YYNODESTATE.getState().currLinenum();
    }

    public int isA(int kind)
    {
        if(kind == KIND)
            return 1;
        else
            return 0;
    }

    public String getKindName()
    {
        return "expression";
    }
}

public class binary extends expression
{
    public static final int KIND = 2;

    public expression expr1;
    public expression expr2;

    protected binary(expression expr1, expression expr2)
    {
        super();
        this.kind__ = KIND;
        this.expr1 = expr1;
        this.expr2 = expr2;
    }

    public int isA(int kind)
    {
        if(kind == KIND)
            return 1;
        else
            return super.isA(kind);
    }

    public String getKindName()
    {
        return "binary";
    }
}

public class plus extends binary
{
    public static final int KIND = 3;

    public plus(expression expr1, expression expr2)
    {
        super(expr1, expr2);
        this.kind__ = KIND;
    }

    public int isA(int kind)
    {
        if(kind == KIND)
            return 1;
        else
            return super.isA(kind);
    }

    public String getKindName()
    {
        return "plus";
    }
}

The following standard members are available on every node type:

int KIND

The kind value for the node type corresponding to this class.

int getKind()

Gets the numeric kind value associated with a particular node. The kind value for node type ‘NAME’ is called ‘NAME.KIND’.

String getKindName()

Gets the name of the node kind associated with a particular node. This may be helpful for debugging and logging code.

int isA(int kind)

Determines if the node is a member of the node type that corresponds to the numeric kind value ‘kind’.

String getFilename()

Gets the filename corresponding to where the node was created during parsing. This method is only generated if ‘%option track_lines’ was specified.

long getLinenum()

Gets the line number corresponding to where the node was created during parsing. This method is only generated if ‘%option track_lines’ was specified.

void setFilename(String value)

Sets the filename associated with the node to ‘value’. This method will rarely be required, unless a node corresponds to a different line than the current parse line. This method is only generated if ‘%option track_lines’ was specified.

void setLinenum(long value)

Sets the line number associated with the node to ‘value’. This method will rarely be required, unless a node corresponds to a different line than the current parse line. This method is only generated if ‘%option track_lines’ was specified.

If the generated code is non-reentrant, then the constructor for the class can be used to construct nodes of the specified node type. The constructor parameters are the same as the fields within the node type's definition, except for ‘%nocreate’ fields.

If the generated code is reentrant, then nodes cannot be constructed using the Java ‘new’ operator. The ‘*Create’ methods on the ‘YYNODESTATE’ factory class must be used instead.

Enumerated types are converted into a Java ‘class’:

 
%enum JavaType =
{
    JT_BYTE,
    JT_SHORT,
    JT_CHAR,
    JT_INT,
    JT_LONG,
    JT_FLOAT,
    JT_DOUBLE,
    JT_OBJECT_REF
}

becomes:

 
public class JavaType
{
    public static final int JT_BYTE = 0;
    public static final int JT_SHORT = 1;
    public static final int JT_CHAR = 2;
    public static final int JT_INT = 3;
    public static final int JT_LONG = 4;
    public static final int JT_FLOAT = 5;
    public static final int JT_DOUBLE = 6;
    public static final int JT_OBJECT_REF = 7;
}

References to enumerated types in fields and operation parameters are replaced with the type ‘int’.

Virtual operations are converted into public methods on the Java node classes.

Non-virtual operations are converted into a static method within a class named for the operation. For example,

 
%operation void InferType::infer_type(expression e)

becomes:

 
public class InferType
{
    public static void infer_type(expression e)
    {
        ...
    }
}

If the class name (‘InferType’ in the above example) is omitted, then the name of the operation is used as both the class name and the the method name.

The ‘YYNODESTATE’ class contains a number of house-keeping methods that are used to manage nodes:

static YYNODESTATE getState()

Gets the global ‘YYNODESTATE’ instance that is being used by non-reentrant code. If an instance has not yet been created, this method will create one.

When using non-reentrant code, the programmer will normally subclass ‘YYNODESTATE’, override some of the methods below, and then construct an instance of the subclass. This constructed instance will then be returned by future calls to ‘getState’.

This method will not be present if a reentrant system is being generated.

String currFilename()

Get the name of the current input file from the parser. This method is usually overrriden by the programmer in subclasses if ‘%option track_lines’ was specified.

long currLinenum()

Get the number of the current input line from the parser. This method is usually overridden by the programmer in subclasses if ‘%option track_lines’ was specified.

The programmer will typically subclass ‘YYNODESTATE’ to provide additional functionality, and then create an instance of this class to act as the global state and node creation factory.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

6.4 C# Language APIs

In the C# output language, each node type is converted into a ‘class’ that contains the node's fields, virtual operations, and other house-keeping definitions. The following example demonstrates how treecc node declarations are converted into C# source code:

 
%node expression %abstract %typedef =
{
    %nocreate type_code type;
}
%node binary expression %abstract =
{
    expression expr1;
    expression expr2;
}
%node plus binary

becomes:

 
public class expression
{
    protected int kind__;
    protected String filename__;
    protected long linenum__;

    public int getKind() { return kind__; }
    public String getFilename() { return filename__; }
    public long getLinenum() const { return linenum__; }
    public void setFilename(String filename) { filename__ = filename; }
    public void setLinenum(long linenum) { linenum__ = linenum; }

    public const int KIND = 1;

    public type_code type;

    protected expression()
    {
        this.kind__ = KIND;
        this.filename__ = YYNODESTATE.getState().currFilename();
        this.linenum__ = YYNODESTATE.getState().currLinenum();
    }

    public virtual int isA(int kind)
    {
        if(kind == KIND)
            return 1;
        else
            return 0;
    }

    public virtual String getKindName()
    {
        return "expression";
    }
}

public class binary : expression
{
    public const int KIND = 2;

    public expression expr1;
    public expression expr2;

    protected binary(expression expr1, expression expr2)
        : expression()
    {
        this.kind__ = KIND;
        this.expr1 = expr1;
        this.expr2 = expr2;
    }

    public override int isA(int kind)
    {
        if(kind == KIND)
            return 1;
        else
            return base.isA(kind);
    }

    public override String getKindName()
    {
        return "binary";
    }
}

public class plus : binary
{
    public const int KIND = 5;

    public plus(expression expr1, expression expr2)
        : binary(expr1, expr2)
    {
        this.kind__ = KIND;
    }

    public override int isA(int kind)
    {
        if(kind == KIND)
            return 1;
        else
            return base.isA(kind);
    }

    public override String getKindName()
    {
        return "plus";
    }
}

The following standard members are available on every node type:

const int KIND

The kind value for the node type corresponding to this class.

int getKind()

Gets the numeric kind value associated with a particular node. The kind value for node type ‘NAME’ is called ‘NAME.KIND’.

virtual String getKindName()

Gets the name of the node kind associated with a particular node. This may be helpful for debugging and logging code.

virtual int isA(int kind)

Determines if the node is a member of the node type that corresponds to the numeric kind value ‘kind’.

String getFilename()

Gets the filename corresponding to where the node was created during parsing. This method is only generated if ‘%option track_lines’ was specified.

long getLinenum()

Gets the line number corresponding to where the node was created during parsing. This method is only generated if ‘%option track_lines’ was specified.

void setFilename(String value)

Sets the filename associated with the node to ‘value’. This method will rarely be required, unless a node corresponds to a different line than the current parse line. This method is only generated if ‘%option track_lines’ was specified.

void setLinenum(long value)

Sets the line number associated with the node to ‘value’. This method will rarely be required, unless a node corresponds to a different line than the current parse line. This method is only generated if ‘%option track_lines’ was specified.

If the generated code is non-reentrant, then the constructor for the class can be used to construct nodes of the specified node type. The constructor parameters are the same as the fields within the node type's definition, except for ‘%nocreate’ fields.

If the generated code is reentrant, then nodes cannot be constructed using the C# ‘new’ operator. The ‘*Create’ methods on the ‘YYNODESTATE’ factory class must be used instead.

Enumerated types are converted into a C# ‘enum’ definition:

 
%enum JavaType =
{
    JT_BYTE,
    JT_SHORT,
    JT_CHAR,
    JT_INT,
    JT_LONG,
    JT_FLOAT,
    JT_DOUBLE,
    JT_OBJECT_REF
}

becomes:

 
public enum JavaType
{
    JT_BYTE,
    JT_SHORT,
    JT_CHAR,
    JT_INT,
    JT_LONG,
    JT_FLOAT,
    JT_DOUBLE,
    JT_OBJECT_REF,
}

Virtual operations are converted into public virtual methods on the C# node classes.

Non-virtual operations are converted into a static method within a class named for the operation. For example,

 
%operation void InferType::infer_type(expression e)

becomes:

 
public class InferType
{
    public static void infer_type(expression e)
    {
        ...
    }
}

If the class name (‘InferType’ in the above example) is omitted, then the name of the operation is used as both the class name and the the method name.

The ‘YYNODESTATE’ class contains a number of house-keeping methods that are used to manage nodes:

static YYNODESTATE getState()

Gets the global ‘YYNODESTATE’ instance that is being used by non-reentrant code. If an instance has not yet been created, this method will create one.

When using non-reentrant code, the programmer will normally subclass ‘YYNODESTATE’, override some of the methods below, and then construct an instance of the subclass. This constructed instance will then be returned by future calls to ‘getState’.

This method will not be present if a reentrant system is being generated.

virtual String currFilename()

Get the name of the current input file from the parser. This method is usually overrriden by the programmer in subclasses if ‘%option track_lines’ was specified.

virtual long currLinenum()

Get the number of the current input line from the parser. This method is usually overridden by the programmer in subclasses if ‘%option track_lines’ was specified.

The programmer will typically subclass ‘YYNODESTATE’ to provide additional functionality, and then create an instance of this class to act as the global state and node creation factory.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

6.5 Ruby Language APIs

In the Ruby output language, each node type is converted into a ‘class’ that contains the node's fields, operations, and other house-keeping definitions. The following example demonstrates how treecc node declarations are converted into Ruby source code:

 
%node expression %abstract %typedef =
{
    %nocreate type_code type;
}
%node binary expression %abstract =
{
    expression expr1;
    expression expr2;
}
%node plus binary

becomes:

 
class YYNODESTATE

  @@state = nil

  def YYNODESTATE.state
    return @@state unless @@state.nil?
    @@state = YYNODESTATE.new()
    return @@state
  end

  def intialize 
     @@state = self 
   end

  def currFilename 
     return nil
  end

  def currLinenum 
     return 0 
  end
end

class Expression
  protected
  attr_reader :kind
  public 

  attr_accessor :Linenum, :Filename

  attr_accessor :type

  KIND = 1

  def initialize()
    @kind = KIND
    @Filename = YYNODESTATE.state.currFilename()
    @Linenum = YYNODESTATE.state.currLinenum()
  end

  def isA(kind)
    if(@kind == KIND) then
      return true
    else
      return 0
    end
  end

  def KindName
    return "Expression"
  end

end

class Binary < Expression

  attr_accessor :expr1
  attr_accessor :expr2

  KIND = 2

  def initialize(expr1, expr2)
  super(expr1, expr2)
    @kind = KIND
    self.expr1 = expr1
    self.expr2 = expr2
  end

  def isA(kind)
    if(@kind == Kind) then
      return true
    else
      return super(kind)
    end
  end

  def KindName
    return "Binary"
  end

end

class Plus < Binary

  KIND = 3

  def initialize(expr1, expr2)
  super(expr1, expr2expr1, expr2)
    @kind = KIND
  end

  def isA(kind)
    if(@kind == KIND) then
      return true
    else
      return super(kind)
    end
  end

  def KindName
    return "Plus"
  end

end

The following standard members are available on every node type:

KIND

The kind value for the node type corresponding to this class. The kind value for node type ‘NAME’ is called ‘NAME::KIND’.

KindName

The name of the node kind associated with a particular node. This may be helpful for debugging and logging code.

isA(int kind)

Determines if the node is a member of the node type that corresponds to the numeric kind value ‘kind’.

Filename

The filename corresponding to where the node was created during parsing. This method is only generated if ‘%option track_lines’ was specified.

Linenum()

The line number corresponding to where the node was created during parsing. This method is only generated if ‘%option track_lines’ was specified.

Enumerated types are converted into a Ruby ‘class’ definition:

 
%enum JavaType =
{
    JT_BYTE,
    JT_SHORT,
    JT_CHAR,
    JT_INT,
    JT_LONG,
    JT_FLOAT,
    JT_DOUBLE,
    JT_OBJECT_REF
}

becomes:

 
class JavaType 
  JT_BYTE = 0
  JT_SHORT = 1
  JT_CHAR = 2
  JT_INT = 3
  JT_LONG = 4
  JT_FLOAT = 5
  JT_DOUBLE = 6
  JT_OBJECT_REF = 7
end

Virtual operations are converted into public methods on the Ruby node classes.

Non-virtual operations are converted into a class method within a class named for the operation. For example,

 
%operation void InferType::infer_type(expression e)

becomes:

 
class InferType
    def InferType.infer_type(expression e)   
        ...
    end
end

If the class name (‘InferType’ in the above example) is omitted, then the name of the operation is used as both the class name and the the method name. You then get a method with a name starting with an uppercase letter. However, Ruby methods start with lowercase methods. So never forget the class name.

The ‘YYNODESTATE’ class contains a number of house-keeping methods that are used to manage nodes:

YYNODESTATE::state()

Gets the global ‘YYNODESTATE’ instance that is being used by non-reentrant code. If an instance has not yet been created, this method will create one.

currFilename

The name of the current input file from the parser. This fields accessor method is usually overrriden by the programmer in subclasses if ‘%option track_lines’ was specified.

currLinenum

The number of the current input line from the parser. This fields accessor method is usually overridden by the programmer in subclasses if ‘%option track_lines’ was specified.

The programmer will typically subclass ‘YYNODESTATE’ to provide additional functionality, and then create an instance of this class to act as the global state and node creation factory.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

6.6 Python Language APIs

In the Python output language, each node type is converted into a ‘class’ that contains the node's fields, operations, and other house-keeping definitions. The following example demonstrates how treecc node declarations are converted into Python source code:

 
%node expression %abstract %typedef =
{
    %nocreate type_code type;
}
%node binary expression %abstract =
{
    expression expr1;
    expression expr2;
}
%node plus binary

becomes:

 
class expression:
    KIND = 1
    def __init__(self):
        self.kind = 1
        self.filename = yycurrfilename()
        self.linenum = yycurrlinenum()

    def getKindName(self):
        return self.__class__.__name__

class binary (expression):
    KIND = 2
    def __init__(self, expr1, expr2):
        expression.__init__(self)
        self.kind = 2
        self.expr1 = expr1
        self.expr2 = expr2

class plus (binary):
    KIND = 3
    def __init__(self, expr1, expr2):
        binary.__init__(self, expr1, expr2)
        self.kind = 3

The following standard members are available on every node type:

KIND

The kind value for the node type corresponding to this class. The kind value for node type ‘NAME’ is called ‘NAME.KIND’.

kind

Gets the numeric kind value associated with a particular node. The kind value for node type ‘NAME’ is called ‘NAME.KIND’.

getKindName()

The name of the node kind associated with a particular node. This may be helpful for debugging and logging code.

filename

The filename corresponding to where the node was created during parsing. This field is only initialized if ‘%option track_lines’ was specified.

linenum

The line number corresponding to where the node was created during parsing. This field is only initialized if ‘%option track_lines’ was specified.

The isA() method from the other output languages is not present in the Python binding. Use the standard Python isinstance function instead.

Enumerated types are converted into a Python ‘class’ definition:

 
%enum JavaType =
{
    JT_BYTE,
    JT_SHORT,
    JT_CHAR,
    JT_INT,
    JT_LONG,
    JT_FLOAT,
    JT_DOUBLE,
    JT_OBJECT_REF
}

becomes:

 
class JavaType:
    JT_BYTE = 0
    JT_SHORT = 1
    JT_CHAR = 2
    JT_INT = 3
    JT_LONG = 4
    JT_FLOAT = 5
    JT_DOUBLE = 6
    JT_OBJECT_REF = 7

Virtual operations are converted into public methods on the Python node classes. Non-virtual operations are converted into a global method within the generated Python module.

If ‘%option track_lines’ is specified, then the generated Python module is assumed to contain the following global methods to provide line tracking information:

yycurrfilename()

The name of the current input file from the parser.

yycurrlinenum()

The number of the current input line from the parser.

The programmer will typically provide a literal %end block to define these methods.


[ << ] [ >> ]           [Top] [Contents] [Index] [ ? ]

This document was generated by Klaus Treichel on January, 18 2009 using texi2html 1.78.