| home
| contents
| previous
| next page
| send comment
| send link
| add bookmark |
PRS_DECL.CPP
declarations
/*-------------------------------------------------------------------*
Declaration Parser
File: prs_decl.cpp
Module: parser
by: Stephen R. Schmitt
*-------------------------------------------------------------------*/
#include "tpl_data.h"
#include <assert.h>
#include <stdlib.h>
#include <values.h>
/*
* External variables
*/
/* in scn_main.cpp */
extern token_struct Token;
extern TOKEN_CODE Stmt_start_list[];
extern TOKEN_CODE Stmt_end_list[];
extern TOKEN_CODE Decl_start_list[];
extern TOKEN_CODE Follow_dimension_list[];
/* in sym_tabl.cpp */
extern int Scope;
extern SYMTAB_NODE_PTR Symbol_table[];
extern TYPE_STRUCT_PTR Integer_typep, Real_typep,
Boolean_typep, Char_typep,
String_typep, Null_typep;
/* in exc_util */
extern bool Routine_flag;
/*
* Global declarations
*/
SYMTAB_NODE_PTR Last_rtne_idp;
int Int_stack[MAX_STACK_SIZE];
int Tos;
/*-------------------------------------------------------------------*
Code Section
*-------------------------------------------------------------------*/
/*
* "declaration" calls routines to parse declarations
*
* returns: nothing
*/
void declaration()
{
switch (Token.code)
{
case CONST:
const_definition(); // and get next token
break;
case VAR:
var_declaration(); // and get next token
break;
case TYPE:
type_definition(); // and get next token
break;
case LABEL:
label_declaration(); // and get next token
break;
default:
assert(0);
break;
}
}
/*
* "const_definition" process:
*
* const <id> : <type spec> := <expn>
*
* returns: nothing
*/
void const_definition()
{
SYMTAB_NODE_PTR idp; // for id node creation
TYPE_STRUCT_PTR expr_tp;
get_token(); // after "const"
if (Token.code != ID_TOKEN)
{
compile_error(M_MISSING, M_IDENTIFIER, M_0);
synchronize(Stmt_start_list, Decl_start_list, Stmt_end_list);
return;
}
idp = lookup(Token.lexeme, Symbol_table[Scope]);
if (idp == NULL)
{
idp = insert(Token.lexeme, &Symbol_table[Scope]);
idp->definition = CONST_DEFN;
idp->typep = Null_typep;
Last_rtne_idp->next = idp;
idp->prev = Last_rtne_idp;
Last_rtne_idp = idp;
}
else
compile_error(M_REDEFINED, M_IDENTIFIER, M_0);
get_token(); // after <id>
if (Token.code == COLON)
{
get_token(); // after ":"
idp->typep = do_type(); // and get next token
if (!Routine_flag)
emit_alloc_data(idp); // add data item
if_code_get_token_else_error(ASSIGN);
emit_statement_marker(Token.file, Token.line);
if (idp->typep == Integer_typep)
{
Tos = 0; // initialize int stack
expr_tp = int_expression(); // evaluate integer
idp->integer = pop_int_stack(); // get integer value
emit_push_imm_integer(idp->integer);
}
else
expr_tp = expression(); // add expression code
if (!assign_type_compatible(idp->typep, expr_tp))
compile_error(M_INVALID, M_ASSIGNMENT, M_0);
else
{
emit_mem_item(POP, idp, idp->typep);
idp->initialized = true;
}
}
else
{
compile_error(M_MISSING, M_COLON, M_0);
synchronize(Stmt_start_list, Decl_start_list, Stmt_end_list);
}
}
/*
* "var_declaration" processes:
*
* var <id> {, <id> } : <type spec> [:= <expn>]
*
* returns: nothing
*/
void var_declaration()
{
SYMTAB_NODE_PTR idp, first_idp, last_idp; // for id node creation
TYPE_STRUCT_PTR expr_tp; // also for id nodes
bool initialize_flag; // if true emit code
// loop to process list of <id>, each of same type
first_idp = NULL;
initialize_flag = false; // default
get_token(); // after "var"
if (Token.code != ID_TOKEN)
{
compile_error(M_MISSING, M_IDENTIFIER, M_0);
synchronize(Stmt_start_list, Decl_start_list, Stmt_end_list);
return;
}
while (Token.code == ID_TOKEN)
{
idp = lookup(Token.lexeme, Symbol_table[Scope]);
if (idp == NULL)
{
idp = insert(Token.lexeme, &Symbol_table[Scope]);
idp->definition = VAR_DEFN;
idp->typep = Null_typep; // prevent errors
// link <id>s together
if (first_idp == NULL)
{
Last_rtne_idp->next = idp; // previous declaration
idp->prev = Last_rtne_idp;
first_idp = idp;
last_idp = idp;
}
else
{
last_idp->next = idp;
idp->prev = last_idp;
last_idp = idp;
}
}
else
compile_error(M_REDEFINED, M_IDENTIFIER, M_0);
get_token(); // after <id>
if (Token.code == COMMA)
get_token(); // after ","
}
Last_rtne_idp = idp; // for next declaration
// type pointer is assigned to first_idp and copied later
// to the other idp's
if (Token.code == COLON)
{
get_token(); // after ":"
first_idp->typep = do_type(); // and get next token
if (!Routine_flag)
{
emit_alloc_data(first_idp); // add data item
first_idp->initialized = true; // no check of globals
}
if (Token.code == ASSIGN)
{
initialize_flag = true;
get_token(); // after ":="
emit_statement_marker(Token.file, Token.line);
expr_tp = expression(); // add expression code
if (!assign_type_compatible(first_idp->typep, expr_tp))
compile_error(M_INVALID, M_ASSIGNMENT, M_0);
else
{
emit_mem_item(POP, first_idp, first_idp->typep);
first_idp->initialized = true;
}
}
}
else
{
compile_error(M_MISSING, M_COLON, M_0);
synchronize(Stmt_start_list, Decl_start_list, Stmt_end_list);
return;
}
// copy first_idp type to all other variables in the list
// and, if initialized, emit additional code
for (idp = first_idp->next; idp != NULL; idp = idp->next)
{
idp->definition = first_idp->definition;
idp->typep = first_idp->typep;
idp->initialized = first_idp->initialized;
if (!Routine_flag)
emit_alloc_data(idp); // add data item
if (initialize_flag == true)
{
// emit code to perform an assignment
// to the other identifiers
emit_statement_marker(Token.file, Token.line);
emit_mem_item(PUSH, first_idp, first_idp->typep);
emit_mem_item(POP, idp, idp->typep);
}
}
}
/*
* "type_definition" process:
*
* type <id> : <type spec>
*
* returns: nothing
*/
void type_definition()
{
SYMTAB_NODE_PTR idp; // for id node creation
get_token(); // after "type"
if (Token.code == ID_TOKEN)
{
idp = lookup(Token.lexeme, Symbol_table[Scope]);
if (idp == NULL) // create a new type definition
{
idp = insert(Token.lexeme, &Symbol_table[Scope]);
idp->definition = TYPE_DEFN;
}
else
compile_error(M_REDEFINED, M_IDENTIFIER, M_0);
get_token(); // after <id>
if_code_get_token_else_error(COLON);
idp->typep = do_type(); // and get next token
if (idp->typep->type_idp == NULL)
idp->typep->type_idp = idp;
}
else
{
compile_error(M_MISSING, M_IDENTIFIER, M_0);
synchronize(Stmt_start_list, Decl_start_list, Stmt_end_list);
}
}
/*
* "label_declaration" processes:
*
* label <id> :
*
* returns: nothing
*/
void label_declaration()
{
SYMTAB_NODE_PTR idp;
get_token(); // after "label"
if (Token.code != ID_TOKEN)
{
compile_error(M_MISSING, M_IDENTIFIER, M_0);
synchronize(Stmt_start_list, Decl_start_list, Stmt_end_list);
return;
}
idp = lookup(Token.lexeme, Symbol_table[Scope]);
if (idp == NULL)
{
idp = insert(Token.lexeme, &Symbol_table[Scope]);
idp->definition = LABEL_DEFN;
idp->typep = Null_typep;
idp->integer = next_code_label();
}
else
compile_error(M_REDEFINED, M_IDENTIFIER, M_0);
get_token(); // after <id>
if_code_get_token_else_error(COLON);
}
/*
* "do_type" processes type specifications by calling the
* appropriate procedure to create a type structure; the next
* global "Token" is obtained from the source file
*
* returns: a pointer to the type structure
*/
TYPE_STRUCT_PTR do_type()
{
SYMTAB_NODE_PTR idp;
TYPE_STRUCT_PTR tp;
switch (Token.code)
{
case ID_TOKEN:
idp = search_symbol_tables(Token.lexeme);
if (idp == NULL)
{
compile_error(M_UNDEFINED, M_IDENTIFIER, M_0);
get_token();
tp = Null_typep;
}
else if (idp->definition == TYPE_DEFN)
{
tp = named_type(idp);
}
else
{
compile_error(M_NOT, M_TYPE, M_IDENTIFIER, M_0);
get_token();
tp = Null_typep;
}
break;
case CHAR:
get_token(); // after "char"
tp = Char_typep;
break;
case INT:
get_token(); // after "int"
tp = Integer_typep;
break;
case REAL:
get_token(); // after "real"
tp = Real_typep;
break;
case BOOLEAN:
get_token(); // after "boolean"
tp = Boolean_typep;
break;
case STRING:
tp = string_type();
break;
case ENUM:
tp = enumeration_type();
break;
case ARRAY:
tp = array_type();
break;
case RECORD:
tp = record_type();
break;
case UNION:
tp = union_type();
break;
default:
compile_error(M_INVALID, M_TYPE, M_0);
tp = Null_typep;
}
return tp;
}
/*
* "named_type" processes an identifier of a named type and returns
* a pointer to its type structure
*
* returns: a pointer to the type structure
*/
TYPE_STRUCT_PTR named_type(SYMTAB_NODE_PTR idp) // of type
{
TYPE_STRUCT_PTR named_tp; // return value
named_tp = idp->typep;
get_token(); // after <id>
return named_tp;
}
/*
* "string_type" processes:
*
* string[(<expn>)]
*
* by parsing it, creating a type structure, and returning a pointer
* to it
*
* returns: a pointer to the type structure
*/
TYPE_STRUCT_PTR string_type()
{
TYPE_STRUCT_PTR string_tp; // return value
TYPE_STRUCT_PTR expr_tp; // of length
int length; // of string
get_token(); // after "string"
if (Token.code == L_PAREN)
{
get_token(); // after "("
Tos = 0; // initialize int stack
expr_tp = int_expression(); // evaluate index
if (expr_tp == Integer_typep)
length = pop_int_stack();
else
compile_error(M_INVALID, M_TYPE, M_0);
if (length <= MAX_STRING_LENGTH)
string_tp = make_string_type_ptr(length);
else
{
string_tp = String_typep;
compile_error(M_INTEGER, M_OUT, M_OF, M_RANGE, M_0);
}
if_code_get_token_else_error(R_PAREN);
}
else
string_tp = String_typep;
return string_tp;
}
/*
* "enumeration_type" processes:
*
* enum(<id> {, <id> })
*
* by parsing it, creating a type structure, and returning a pointer
* to it
*
* returns: a pointer to the type structure
*/
TYPE_STRUCT_PTR enumeration_type()
{
SYMTAB_NODE_PTR idp, last_idp; // for <id>'s
TYPE_STRUCT_PTR enum_tp; // return value
int enum_value; // values for <id>'s
enum_tp = alloc_type_struct();
enum_tp->form = ENUM_FORM;
enum_tp->size = 1;
enum_tp->type_idp = NULL;
enum_tp->enumeration.field_symtab = NULL;
get_token(); // after "enum"
if_code_get_token_else_error(L_PAREN);
enum_value = 0;
last_idp = NULL;
// loop to process list of identifiers
while (Token.code == ID_TOKEN)
{
idp = lookup(Token.lexeme, enum_tp->enumeration.field_symtab);
if (idp == NULL)
idp = insert(Token.lexeme, &enum_tp->enumeration.field_symtab);
else
compile_error(M_REDEFINED, M_IDENTIFIER, M_0);
idp->typep = enum_tp;
idp->definition = CONST_DEFN;
idp->integer = enum_value;
idp->initialized = true;
enum_value++; // of next item
// link constant id's together
if (last_idp == NULL)
{
last_idp = idp;
enum_tp->enumeration.first_idp = last_idp;
}
else
{
last_idp->next = idp;
last_idp = idp;
}
get_token(); // after <id>
if (Token.code == COMMA)
get_token(); // after ","
}
if_code_get_token_else_error(R_PAREN);
enum_tp->enumeration.max = enum_value - 1;
return enum_tp;
}
/*
* "array_type" processes:
*
* array(<index size> {, <index size> }) of <type spec>
*
* by parsing it, creating a type structure and returning a pointer
* to it
*
* returns: a pointer to the type structure
*/
TYPE_STRUCT_PTR array_type()
{
TYPE_STRUCT_PTR array_tp, next_tp, tp;
int index_size, elements, element_size, array_storage_size;
tp = alloc_type_struct();
array_tp = tp; // save first type ptr
elements = 1; // at least 1
get_token(); // after "array"
if (Token.code != L_PAREN)
{
compile_error(M_MISSING, M_LPAREN, M_0);
synchronize(Stmt_start_list, Decl_start_list, Stmt_end_list);
goto array_type_exit;
}
do
{
get_token(); // after "(" or ","
elements = elements * get_array_index(tp);
// chain indices together
if (Token.code == COMMA)
{
next_tp = alloc_type_struct();
tp->array.next_indexp = next_tp;
tp = next_tp;
}
}
while (Token.code == COMMA);
if_code_get_token_else_error(R_PAREN);
if_code_get_token_else_error(OF);
array_tp->array.elmt_typep = do_type(); // and get next token
element_size = array_tp->array.elmt_typep->size;
array_storage_size = elements * element_size;
array_tp->size = array_storage_size;
if (array_storage_size > MAX_ARRAY_SIZE)
compile_error(M_ARRAY, M_TOO, M_LARGE, M_0);
// set index values for use in calculating memory offsets for
// array elements; last index should have value 1
tp = array_tp;
while (tp != NULL)
{
index_size = tp->array.max_index + 1; // zero based indices
array_storage_size = array_storage_size / index_size;
tp->array.val_index = array_storage_size;
tp = tp->array.next_indexp;
}
array_type_exit:
return array_tp;
}
/*
* "get_array_index" processes the size of an array index
*
* returns: the size of the index
*/
int get_array_index(TYPE_STRUCT_PTR tp) // of array index
{
int size = 1; // index size
TYPE_STRUCT_PTR expr_tp; // of index
Tos = 0; // initialize int stack
expr_tp = int_expression(); // evaluate index
if (expr_tp == Integer_typep)
size = pop_int_stack();
else
compile_error(M_INVALID, M_TYPE, M_0);
if ((size < 1) || (size > MAX_ARRAY_SIZE))
{
compile_error(M_INTEGER, M_OUT, M_OF, M_RANGE, M_0);
size = 1; // avoid division error
}
tp->form = ARRAY_FORM;
tp->type_idp = NULL;
tp->array.next_indexp = NULL;
tp->array.max_index = size - 1;
return size;
}
/*
* "record_type" processes:
*
* record
* id {, id }:typeSpec
* { id {, id }:typeSpec }
* end record
*
* by parsing it, creating a type structure and returning a pointer
* to it
*
* returns: a pointer to the type structure
*/
TYPE_STRUCT_PTR record_type()
{
TYPE_STRUCT_PTR record_tp;
record_tp = alloc_type_struct();
record_tp->form = RECORD_FORM;
record_tp->size = 1; // to avoid error
record_tp->type_idp = NULL;
record_tp->record_struct.field_symtab = NULL;
get_token(); // after "record"
if (Token.code != ID_TOKEN)
{
compile_error(M_MISSING, M_IDENTIFIER, M_0);
synchronize(Stmt_start_list, Decl_start_list, Stmt_end_list);
}
else
get_record_fields(record_tp);
if_code_get_token_else_error(END);
if_code_get_token_else_error(RECORD);
return record_tp;
}
/*
* "get_record_fields" processes record field definitions.
*
* returns: nothing
*/
void get_record_fields(TYPE_STRUCT_PTR record_tp) // of record
{
SYMTAB_NODE_PTR idp, first_idp, last_idp; // field idps
SYMTAB_NODE_PTR prev_last_idp = NULL; // last id of list
TYPE_STRUCT_PTR tp; // of field
int size; // of field
int offset = 0;
// loop to process sublists, each of a type
while (Token.code == ID_TOKEN)
{
first_idp = NULL;
// loop to process each variable or field id in a sublist
while (Token.code == ID_TOKEN)
{
idp = lookup(Token.lexeme, record_tp->record_struct.field_symtab);
if (idp == NULL)
idp = insert(Token.lexeme, &record_tp->record_struct.field_symtab);
else
compile_error(M_REDEFINED, M_IDENTIFIER, M_0);
idp->definition = FIELD_DEFN;
// link ids together into a sublist
if (first_idp == NULL)
{
last_idp = idp;
first_idp = idp;
}
else
{
last_idp->next = idp;
last_idp = idp;
}
get_token(); // after <id>
if (Token.code == COMMA)
get_token(); // after ","
}
// process the sublist's type
if (Token.code == COLON)
{
get_token(); // after ":"
tp = do_type(); // and get next token
size = tp->size;
}
else
compile_error(M_MISSING, M_COLON, M_0);
// assign the offset and type to all fields in the sublist
for (idp = first_idp; idp != NULL; idp = idp->next)
{
idp->typep = tp;
idp->data_offset = offset;
offset += size;
}
// link this sublist to the previous sublist
if (prev_last_idp != NULL)
prev_last_idp->next = first_idp;
prev_last_idp = last_idp;
// error synchronization
if ((!token_in(Stmt_start_list))&&
(!token_in(Decl_start_list))&&
(!token_in(Stmt_end_list )))
{
compile_error(M_SYNTAX, M_ERROR, M_0);
synchronize(Stmt_start_list, Decl_start_list, Stmt_end_list);
}
}
record_tp->size = offset;
}
/*
* "union_type" processes:
*
* union
* id {, id }:typeSpec
* { id {, id }:typeSpec }
* end union
*
* by parsing it, creating a type structure and returning a pointer
* to it
*
* returns: a pointer to the type structure
*/
TYPE_STRUCT_PTR union_type()
{
TYPE_STRUCT_PTR union_tp;
union_tp = alloc_type_struct();
union_tp->form = UNION_FORM;
union_tp->size = 1; // to avoid error
union_tp->type_idp = NULL;
union_tp->union_struct.field_symtab = NULL;
get_token(); // after "union"
if (Token.code != ID_TOKEN)
{
compile_error(M_MISSING, M_IDENTIFIER, M_0);
synchronize(Stmt_start_list, Decl_start_list, Stmt_end_list);
}
else
get_union_fields(union_tp);
if_code_get_token_else_error(END);
if_code_get_token_else_error(UNION);
return union_tp;
}
/*
* "get_union_fields" processes union field definitions.
*
* returns: nothing
*/
void get_union_fields(TYPE_STRUCT_PTR union_tp) // of union
{
SYMTAB_NODE_PTR idp, first_idp, last_idp; // field idps
SYMTAB_NODE_PTR prev_last_idp = NULL; // last id of list
TYPE_STRUCT_PTR tp; // of field
int size = 0; // of field
int offset = 0; // of field
// loop to process sublists, each of a type
while (Token.code == ID_TOKEN)
{
first_idp = NULL;
// loop to process each variable or field id in a sublist
while (Token.code == ID_TOKEN)
{
idp = lookup(Token.lexeme, union_tp->union_struct.field_symtab);
if (idp == NULL)
idp = insert(Token.lexeme, &union_tp->union_struct.field_symtab);
else
compile_error(M_REDEFINED, M_IDENTIFIER, M_0);
idp->definition = FIELD_DEFN;
// link ids together into a sublist
if (first_idp == NULL)
{
last_idp = idp;
first_idp = idp;
}
else
{
last_idp->next = idp;
last_idp = idp;
}
get_token(); // after <id>
if (Token.code == COMMA)
get_token(); // after ","
}
// process the sublist's type
if (Token.code == COLON)
{
get_token(); // after ":"
tp = do_type(); // and get next token
if (tp->size > size) // size of union
size = tp->size;
}
else
compile_error(M_MISSING, M_COLON, M_0);
// assign the offset and type to all fields in the sublist
for (idp = first_idp; idp != NULL; idp = idp->next)
{
idp->typep = tp;
idp->data_offset = offset;
}
// link this sublist to the previous sublist
if (prev_last_idp != NULL)
prev_last_idp->next = first_idp;
prev_last_idp = last_idp;
// error synchronization
if ((!token_in(Stmt_start_list))&&
(!token_in(Decl_start_list))&&
(!token_in(Stmt_end_list )))
{
compile_error(M_SYNTAX, M_ERROR, M_0);
synchronize(Stmt_start_list, Decl_start_list, Stmt_end_list);
}
}
union_tp->size = size;
}
/*
* "push_int_stack" puts an integer on top of the integer stack
*
* returns: nothing
*/
void push_int_stack(int value) // the integer
{
Tos++;
if ((Tos > 0)&&(Tos < MAX_STACK_SIZE))
Int_stack[Tos] = value;
}
/*
* "pop_int_stack" returns an integer from the top of the integer
* stack
*
* returns: the integer
*/
int pop_int_stack()
{
int value;
value = Int_stack[Tos];
Tos--;
return value;
}
| home
| contents
| previous
| next page
| send comment
| send link
| add bookmark |
Copyright © 2004, Stephen R. Schmitt