cfad47cfa3/t3compiler/tads3/tct3base.h
Commiter: Nikos Chantziaras
Author: Nikos Chantziaras
Revision: cfad47cfa3
File Size: 12.2 KB
(June 01, 2009 20:54 UTC) Almost 3 years ago
Initial commit.
/* $Header: d:/cvsroot/tads/tads3/TCT3BASE.H,v 1.3 1999/07/11 00:46:57 MJRoberts Exp $ */
/*
* Copyright (c) 1999, 2002 Michael J. Roberts. All Rights Reserved.
*
* Please see the accompanying license file, LICENSE.TXT, for information
* on using and copying this software.
*/
/*
Name
tct3base.h - base parse node classes for T3 code generator
Function
Notes
Modified
05/10/99 MJRoberts - Creation
*/
#ifndef TCT3BASE_H
#define TCT3BASE_H
#include "tcprs.h"
/* include the target-independent base classes */
#include "tcpnbase.h"
/* ------------------------------------------------------------------------ */
/*
* Base parse node class
*/
class CTcPrsNode: public CTcPrsNodeBase
{
public:
/*
* Generate code to assign into the expression as an lvalue. By
* default, we'll throw an error; a default node should never be
* called upon to generate code as an assignment target, because the
* impossibility of this condition should be detected during
* parsing. Each class that overrides check_lvalue() to return true
* must override this to generate code for an assignment.
*
* Returns true if the assignment type was handled, false if not.
* Simple assignment must always be handled, but composite
* assignments (such as "+=" or "*=") can refused. If the
* assignment isn't handled, the caller must perform a generic
* calculation to compute the result of the assignment (for example,
* for "+=", the caller must generate code compute the sum of the
* right-hand side and the original value of the left-hand side),
* then call gen_code_asi() again to generate a simple assignment.
*
* In general, gen_code_asi() must generate code for complex
* assignments itself only when it can take advantage of special
* opcodes that would result in more efficient generated code. When
* no special opcodes are available for the assignment, there's no
* need for special coding here.
*
* If 'ignore_error' is true, this should not generate an error if
* this node is not a suitable lvalue, but should simply return
* false.
*/
virtual int gen_code_asi(int discard, tc_asitype_t typ,
class CTcPrsNode *rhs,
int ignore_error);
/*
* Generate code to take the address of the expression. By default,
* we'll throw an internal error; a default node should never be
* called upon to generate code to take its address, because we
* shouldn't be able to parse such a thing. Each class that
* overrides has_addr() to return true must override this to
* generate address code.
*/
virtual void gen_code_addr();
/*
* Generate an if-then-else condition test. This is called on the
* controlling expression of an if-then-else, and can also be called on
* subexpressions of short-circuit operators (|| and &&). The purpose
* of this type of code generation is to avoid pushing the result of
* the controlling expression onto the stack when this can be avoided,
* and generate a jump to the appropriate if-else branch directly.
*
* Either then_label or else_label will be non-null; the one that's
* null directly follows the condition test, so we are simply to fall
* through to that code rather than jump to it explicitly.
*/
virtual void gen_code_cond(struct CTcCodeLabel *then_label,
struct CTcCodeLabel *else_label);
/*
* Generate code to call the expression as a function or method.
* The caller will already have generated code to push the argument
* list; this routine only needs to generate code to make the call.
*
* By default, we'll assume that the result of evaluating the
* expression is a method or function pointer, so we'll generate a
* call-indirect instruction to call the result of evaluating the
* expression.
*/
virtual void gen_code_call(int discard, int argc, int varargs);
/*
* Generate code to apply operator 'new' to the expression. By
* default, 'new' cannot be applied to an expression; nodes that
* allow operator 'new' must override this.
*/
virtual void gen_code_new(int discard, int argc, int varargs,
int from_call, int is_transient);
/*
* Generate code to evaluate a member expression on this object
* expression, calling the property expression given. By default,
* we'll evaluate our own expression to yield the object value, then
* get the property expression (either as a constant or by
* generating code to yield a property pointer), then we'll invoke
* that code. Nodes should override this where more specific
* instructions can be generated.
*
* If 'prop_is_expr' is true, the property expression (prop_expr) is
* a parenthesized expression; otherwise, it's a simple property
* symbol. (We need this information because a symbol enclosed in
* parentheses would be otherwise indistinguishable from a plain
* symbol, but the two syntax cases differ in their behavior: a
* plain symbol is always a property name, whereas a symbol in
* parentheses can be a local variable.)
*/
virtual void gen_code_member(int discard,
class CTcPrsNode *prop_expr,
int prop_is_expr,
int argc, int varargs);
/*
* Generate code for an object on the left side of a '.' expression.
* If possible, return the constant object rather than generating
* code. If the expression refers to "self", set (*is_self) to true
* and return VM_INVALID_OBJ; otherwise, if the expression refers to
* a constant object reference, set (*is_self) to false and return
* the constant object value; otherwise, generate code for the
* expression, set (*is_self) to false, and return VM_INVALID_OBJ to
* indicate that the value must be obtained from the generated code
* at run-time.
*
* By default, we'll use generated code to get the value.
*/
virtual vm_obj_id_t gen_code_obj_predot(int *is_self)
{
/* generate the expression */
gen_code(FALSE, FALSE);
/* tell the caller that the value is not a compile-time constant */
*is_self = FALSE;
return VM_INVALID_OBJ;
}
/*
* generic generation for a member expression after the left side
* has been generated
*/
static void s_gen_member_rhs(int discard,
class CTcPrsNode *prop_expr,
int prop_is_expr, int argc, int varargs);
/*
* Get the property ID of this expression. If the property ID is
* available as a constant value, this doesn't generate any code and
* simply returns the constant property ID value. If this
* expression requires run-time evaluation, we'll generate code for
* the expression and return VM_INVALID_PROP to indicate that a
* constant property ID is not available.
*
* If 'check_only' is true, this routine should only check to see
* whether a constant property value is available and return the
* appropriate indication, but should not generate any code in any
* case. Errors should also be suppressed in this case, because the
* routine will always be called again to perform the actual
* generation, at which point any errors can be logged.
*
* If 'is_expr' is true, it means that this property was given as an
* expression by being explicitly enclosed in parentheses. If
* 'is_expr' is false, it means that the property was given as a
* simple symbol name. For cases where the property expression is a
* symbol, this distinction is important because we must resolve an
* unparenthesized symbol as a property name, even if it's hidden by
* a local variable.
*/
virtual vm_prop_id_t gen_code_propid(int check_only, int is_expr);
/*
* generate a jump-ahead instruction, returning a new label which
* serves as the jump destination
*/
static struct CTcCodeLabel *gen_jump_ahead(uchar opc);
/* define the position of a code label */
static void def_label_pos(struct CTcCodeLabel *lbl);
/* allocate a new label at the current write position */
static struct CTcCodeLabel *new_label_here();
};
/* ------------------------------------------------------------------------ */
/*
* Basic T3-specific symbol class
*/
class CTcSymbol: public CTcSymbolBase
{
public:
CTcSymbol(const char *str, size_t len, int copy, tc_symtype_t typ)
: CTcSymbolBase(str, len, copy, typ) { }
/*
* get the object value for the symbol, if the symbol has an object
* value; returns VM_INVALID_OBJ if the symbol is not an object
*/
virtual vm_obj_id_t get_val_obj() const { return VM_INVALID_OBJ; }
/* generate code to evaluate the symbol */
virtual void gen_code(int discard) = 0;
/*
* Generate code to assign to the symbol. By default, we'll
* generate an error indicating that the symbol cannot be assigned
* into. As with CTcPrsNode::gen_code_asi(), this returns true if
* the assignment was generated, false if the caller must generate a
* generic assignment; simple assignment must always return true.
*
* If 'rhs' is null, the caller has already generated the value to
* be assigned, so this code doesn't need to do that. Otherwise,
* this code must generate the rvalue code. The reason that 'rhs'
* is passed down at all is that we can sometimes optimize the type
* of opcode we generate according to the type of value being
* assigned, especially when a constant value is being assigned.
*
* If 'ignore_error' is true, this should not log an error if the
* value cannot be assigned.
*/
virtual int gen_code_asi(int discard, tc_asitype_t typ,
class CTcPrsNode *rhs, int ignore_error);
/*
* Generate code for taking the address of the symbol. By default,
* we'll generate an error indicating that the symbol's address
* cannot be taken.
*/
virtual void gen_code_addr();
/*
* Generate code to call the symbol. By default, we can't call a
* symbol.
*/
virtual void gen_code_call(int discard, int argc, int varargs);
/*
* generate code for operator 'new' applied to the symbol, with the
* given number of arguments; by default, we can't generate any such
* code
*/
virtual void gen_code_new(int discard, int argc, int varargs,
int is_transient);
/* evaluate a property ID */
virtual vm_prop_id_t gen_code_propid(int check_only, int is_expr);
/* generate code for a member expression */
virtual void gen_code_member(int discard,
class CTcPrsNode *prop_expr,
int prop_is_expr,
int argc, int varargs);
/* get the object value for a '.' expression */
virtual vm_obj_id_t gen_code_obj_predot(int *is_self);
/*
* Write the symbol to a local frame debugging record in the code
* stream. Returns true if we wrote the symbol, false if not. By
* default, we'll write nothing and return false, since most symbols
* aren't used in local symbol tables.
*/
virtual int write_to_debug_frame() { return FALSE; }
/*
* Write the symbol to the global symbol table in the debugging
* records in an image file. Returns true if we wrote the symbol,
* false if not. By default, we'll write nothing and return false,
* since by default symbols don't go in the image file's global
* symbol table.
*/
virtual int write_to_image_file_global(class CVmImageWriter *)
{ return FALSE; }
};
#endif /* TCT3BASE_H */
|