Skip to content

Commit

Permalink
Semantic analysis now tries to assign a unique id to every variable.
Browse files Browse the repository at this point in the history
This way, we don't have to worry about scopes or identifier lookup when
 building the IR.
  • Loading branch information
icculus committed Dec 12, 2010
1 parent 17f5190 commit 48e1d4d
Show file tree
Hide file tree
Showing 2 changed files with 73 additions and 18 deletions.
8 changes: 8 additions & 0 deletions mojoshader.h
Expand Up @@ -1224,11 +1224,19 @@ typedef struct MOJOSHADER_astExpressionTernary
MOJOSHADER_astExpression *right;
} MOJOSHADER_astExpressionTernary;

/* Identifier indexes aren't available until semantic analysis phase completes.
* It provides a unique id for this identifier's variable.
* It will be negative for global scope, positive for function scope
* (global values are globally unique, function values are only
* unique within the scope of the given function).
* May be zero for various reasons (function name, unknown identifier, etc).
*/
typedef struct MOJOSHADER_astExpressionIdentifier
{
MOJOSHADER_astNodeInfo ast; /* Always MOJOSHADER_AST_OP_IDENTIFIER */
const MOJOSHADER_astDataType *datatype;
const char *identifier;
int index;
} MOJOSHADER_astExpressionIdentifier;

typedef struct MOJOSHADER_astExpressionIntLiteral
Expand Down
83 changes: 65 additions & 18 deletions mojoshader_compiler.c
Expand Up @@ -68,6 +68,7 @@ typedef struct SymbolScope
{
const char *symbol;
const MOJOSHADER_astDataType *datatype;
int index; // unique positive value within a function, negative if global.
struct SymbolScope *next;
} SymbolScope;

Expand Down Expand Up @@ -96,6 +97,9 @@ typedef struct Context
SymbolMap variables;
MOJOSHADER_astNode *ast; // Abstract Syntax Tree
const char *source_profile;
int is_func_scope; // non-zero if semantic analysis is in function scope.
int var_index; // next variable index for current function.
int global_var_index; // next variable index for global scope.

// Cache intrinsic types for fast lookup and consistent pointer values.
MOJOSHADER_astDataType dt_bool;
Expand Down Expand Up @@ -221,26 +225,54 @@ static int create_symbolmap(Context *ctx, SymbolMap *map)
} // create_symbolmap


static void push_symbol(Context *ctx, SymbolMap *map,
const char *sym, const MOJOSHADER_astDataType *dt)
static void push_symbol(Context *ctx, SymbolMap *map, const char *sym,
const MOJOSHADER_astDataType *dt, const int index)
{
// !!! FIXME: decide if this symbol is defined, and if so, if it's in
// !!! FIXME: the current scope.
// Decide if this symbol is defined, and if it's in the current scope.
SymbolScope *item = NULL;
const void *value = NULL;
void *iter = NULL;
if ((sym != NULL) && (hash_iter(map->hash, sym, &value, &iter)))
{
item = (SymbolScope *) value;
// Functions are always global, so no need to search scopes.
// !!! FIXME: Functions overload, though, so we have to continue
// !!! FIXME: iterating to see if it matches anything.
//const MOJOSHADER_astDataType *dt = item->datatype;
//if (dt->type == MOJOSHADER_AST_DATATYPE_FUNCTION)
//{
//} // if
//else // check the current scope for a dupe.
{
item = map->scope;
while ((item) && (item->symbol))
{
if (strcmp(item->symbol, sym) == 0)
{
failf(ctx, "Symbol '%s' already defined", sym);
return;
} // if
item = item->next;
} // while
} // else
} // if

SymbolScope *item = (SymbolScope *) Malloc(ctx, sizeof (SymbolScope));
// Add the symbol to our map and scope stack.
item = (SymbolScope *) Malloc(ctx, sizeof (SymbolScope));
if (item == NULL)
return;

if (sym != NULL)
if (sym != NULL) // sym can be NULL if we're pushing a new scope.
{
if (hash_insert(map->hash, sym, dt) == -1)
if (hash_insert(map->hash, sym, item) == -1)
{
Free(ctx, item);
return;
} // if
} // if

item->symbol = sym; // cached strings, don't copy.
item->index = index;
item->datatype = dt;
item->next = map->scope;
map->scope = item;
Expand Down Expand Up @@ -269,12 +301,21 @@ static void push_usertype(Context *ctx, const char *sym, const MOJOSHADER_astDat
} // if
} // if

push_symbol(ctx, &ctx->usertypes, sym, dt);
push_symbol(ctx, &ctx->usertypes, sym, dt, 0);
} // push_usertype

static inline void push_variable(Context *ctx, const char *sym, const MOJOSHADER_astDataType *dt)
{
push_symbol(ctx, &ctx->variables, sym, dt);
int idx = 0;
if (sym != NULL)
{
if (ctx->is_func_scope)
idx = ++ctx->var_index; // these are positive.
else
idx = --ctx->global_var_index; // these are negative.
} // if

push_symbol(ctx, &ctx->variables, sym, dt, idx);
} // push_variable

static inline void push_scope(Context *ctx)
Expand Down Expand Up @@ -311,21 +352,24 @@ static inline void pop_scope(Context *ctx)
pop_symbol_scope(ctx, &ctx->variables);
} // push_scope

static const MOJOSHADER_astDataType *find_symbol(Context *ctx, SymbolMap *map, const char *sym)
static const MOJOSHADER_astDataType *find_symbol(Context *ctx, SymbolMap *map, const char *sym, int *_index)
{
const void *value = NULL;
hash_find(map->hash, sym, &value);
return (const MOJOSHADER_astDataType *) value;
const void *_item = NULL;
hash_find(map->hash, sym, &_item);
SymbolScope *item = (SymbolScope *) item;
if (item && _index)
*_index = item->index;
return item ? item->datatype : NULL;
} // find_symbol

static inline const MOJOSHADER_astDataType *find_usertype(Context *ctx, const char *sym)
{
return find_symbol(ctx, &ctx->usertypes, sym);
return find_symbol(ctx, &ctx->usertypes, sym, NULL);
} // find_usertype

static inline const MOJOSHADER_astDataType *find_variable(Context *ctx, const char *sym)
static inline const MOJOSHADER_astDataType *find_variable(Context *ctx, const char *sym, int *_index)
{
return find_symbol(ctx, &ctx->variables, sym);
return find_symbol(ctx, &ctx->variables, sym, _index);
} // find_variable

static void destroy_symbolmap(Context *ctx, SymbolMap *map)
Expand Down Expand Up @@ -1321,7 +1365,7 @@ static const MOJOSHADER_astDataType *get_usertype(const Context *ctx,
const void *value; // search all scopes.
if (!hash_find(ctx->usertypes.hash, token, &value))
return NULL;
return (MOJOSHADER_astDataType *) value;
return value ? ((SymbolScope *) value)->datatype : NULL;
} // get_usertype


Expand Down Expand Up @@ -2138,7 +2182,7 @@ static const MOJOSHADER_astDataType *type_check_ast(Context *ctx, void *_ast)
return ast->ternary.datatype;

case MOJOSHADER_AST_OP_IDENTIFIER:
datatype = find_variable(ctx, ast->identifier.identifier);
datatype = find_variable(ctx, ast->identifier.identifier, &ast->identifier.index);
if (datatype == NULL)
{
fail(ctx, "Unknown identifier");
Expand Down Expand Up @@ -2394,6 +2438,8 @@ static const MOJOSHADER_astDataType *type_check_ast(Context *ctx, void *_ast)
fail(ctx, "function sigs don't match");
} // else

ctx->is_func_scope = 1;
ctx->var_index = 0; // reset this every function.
push_scope(ctx); // so function params are in function scope.
type_check_ast(ctx, ast->funcunit.declaration);
if (ast->funcunit.definition == NULL)
Expand All @@ -2404,6 +2450,7 @@ static const MOJOSHADER_astDataType *type_check_ast(Context *ctx, void *_ast)
pop_scope(ctx);
push_variable(ctx, ast->funcunit.declaration->identifier, datatype);
} // else
ctx->is_func_scope = 0;

type_check_ast(ctx, ast->funcunit.next);
return NULL;
Expand Down

0 comments on commit 48e1d4d

Please sign in to comment.