%{
#include <Message.h>
#include <map>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include "rdef.h"
#include "compile.h"
#include "private.h"
using namespace std;
#define YYERROR_VERBOSE
static void yyerror(const char*);
struct ident_compare_t {
bool
operator()(const char* s1, const char* s2) const
{
return strcmp(s1, s2) < 0;
}
};
typedef std::map<const char*, int32, ident_compare_t> sym_tab_t;
typedef sym_tab_t::iterator sym_iter_t;
typedef std::map<const char*, type_t, ident_compare_t> type_tab_t;
typedef type_tab_t::iterator type_iter_t;
typedef std::map<const char*, define_t, ident_compare_t> define_tab_t;
typedef define_tab_t::iterator define_iter_t;
static sym_tab_t symbol_table;
static int32 enum_cnt;
static type_tab_t type_table;
static define_tab_t define_table;
static void add_user_type(res_id_t, type_code, const char*, list_t);
static void add_symbol(const char*, int32);
static int32 get_symbol(const char*);
static bool is_type(const char* name);
static define_t get_define(const char* name);
static data_t make_data(size_t, type_t);
static data_t make_bool(bool);
static data_t make_int(uint64);
static data_t make_float(double);
static data_t import_data(char*);
static data_t resize_data(data_t, size_t);
static BMessage* make_msg(list_t);
static data_t flatten_msg(BMessage*);
static data_t make_default(type_t);
static data_t make_type(char* name, list_t);
static list_t make_field_list(field_t);
static list_t concat_field_list(list_t, field_t);
static list_t make_data_list(data_t);
static list_t concat_data_list(list_t, data_t);
static data_t concat_data(data_t, data_t);
static data_t cast(type_t, data_t);
static data_t unary_expr(data_t, char);
static data_t binary_expr(data_t, data_t, char);
static void add_resource(res_id_t, type_code, data_t);
%}
%expect 15
%union {
bool b;
uint64 i;
double f;
char* I;
type_code t;
res_id_t id;
data_t d;
list_t l;
field_t F;
type_t T;
}
%token ENUM RESOURCE ARCHIVE ARRAY MESSAGE RTYPE IMPORT
%token <b> BOOL
%token <i> INTEGER
%token <f> FLOAT
%token <d> STRING RAW
%token <I> IDENT
%token <t> TYPECODE
%type <i> integer
%type <f> float
%type <id> id
%type <d> archive array arrayfields data expr message msgfield
%type <d> type typefield type_or_define
%type <l> msgfields typefields typedeffields
%type <F> typedeffield
%type <T> datatype typecast
%left '|'
%left '^'
%left '&'
%left '+' '-'
%left '*' '/' '%'
%right FLIP
%%
script
:
| script enum
| script typedef
| script resource
;
enum
: enumstart '{' '}' ';'
| enumstart '{' symbols '}' ';'
| enumstart '{' symbols ',' '}' ';'
;
enumstart
: ENUM { enum_cnt = 0; }
;
symbols
: symbols ',' symboldef
| symboldef
;
symboldef
: IDENT
{
add_symbol($1, enum_cnt);
++enum_cnt;
}
| IDENT '=' integer
{
int32 id = (int32) $3;
add_symbol($1, id);
enum_cnt = id + 1;
}
;
typedef
: RTYPE id TYPECODE IDENT '{' typedeffields '}' ';'
{
add_user_type($2, $3, $4, $6);
}
| RTYPE id IDENT '{' typedeffields '}' ';'
{
add_user_type($2, B_RAW_TYPE, $3, $5);
}
;
typedeffields
: typedeffields ',' typedeffield { $$ = concat_field_list($1, $3); }
| typedeffield { $$ = make_field_list($1); }
;
typedeffield
: datatype IDENT
{
$$.type = $1;
$$.name = $2;
$$.resize = 0;
$$.data = make_default($1);
}
| datatype IDENT '=' expr
{
$$.type = $1;
$$.name = $2;
$$.resize = 0;
$$.data = cast($1, $4);
}
| datatype IDENT '[' INTEGER ']'
{
$$.type = $1;
$$.name = $2;
$$.resize = (size_t) $4;
$$.data = resize_data(make_default($1), $$.resize);
}
| datatype IDENT '[' INTEGER ']' '=' expr
{
$$.type = $1;
$$.name = $2;
$$.resize = (size_t) $4;
$$.data = resize_data(cast($1, $7), $$.resize);
}
;
resource
: RESOURCE id expr ';'
{
add_resource($2, $3.type.code, $3);
}
| RESOURCE id TYPECODE expr ';'
{
add_resource($2, $3, $4);
}
| RESOURCE id '(' TYPECODE ')' expr ';'
{
add_resource($2, $4, $6);
}
;
id
:
{
$$.has_id = false; $$.has_name = false; $$.name = NULL;
}
| '(' ')'
{
$$.has_id = false; $$.has_name = false; $$.name = NULL;
}
| '(' integer ')'
{
$$.has_id = true; $$.id = (int32) $2;
$$.has_name = false; $$.name = NULL;
}
| '(' integer ',' STRING ')'
{
$$.has_id = true; $$.id = (int32) $2;
$$.has_name = true; $$.name = (char*) $4.ptr;
}
| '(' IDENT ')'
{
$$.has_id = true; $$.id = get_symbol($2);
if (flags & RDEF_AUTO_NAMES)
{
$$.has_name = true; $$.name = $2;
}
else
{
$$.has_name = false; $$.name = NULL;
free_mem($2);
}
}
| '(' IDENT ',' STRING ')'
{
$$.has_id = true; $$.id = get_symbol($2);
$$.has_name = true; $$.name = (char*) $4.ptr;
free_mem($2);
}
| '(' STRING ')'
{
$$.has_id = false;
$$.has_name = true; $$.name = (char*) $2.ptr;
}
;
array
: ARRAY '{' arrayfields '}' { $$ = $3; }
| ARRAY '{' '}' { $$ = make_data(0, get_type("raw")); }
| ARRAY { $$ = make_data(0, get_type("raw")); }
| ARRAY IMPORT STRING { $$ = import_data((char*) $3.ptr); }
| IMPORT STRING { $$ = import_data((char*) $2.ptr); }
;
arrayfields
: arrayfields ',' expr { $$ = concat_data($1, $3); }
| expr { $$ = $1; $$.type = get_type("raw"); }
;
message
: MESSAGE '(' integer ')' '{' msgfields '}'
{
BMessage* msg = make_msg($6);
msg->what = (int32) $3;
$$ = flatten_msg(msg);
}
| MESSAGE '(' integer ')' '{' '}'
{
BMessage* msg = new BMessage;
msg->what = (int32) $3;
$$ = flatten_msg(msg);
}
| MESSAGE '(' integer ')'
{
BMessage* msg = new BMessage;
msg->what = (int32) $3;
$$ = flatten_msg(msg);
}
| MESSAGE '{' msgfields '}' { $$ = flatten_msg(make_msg($3)); }
| MESSAGE '{' '}' { $$ = flatten_msg(new BMessage); }
| MESSAGE { $$ = flatten_msg(new BMessage); }
;
msgfields
: msgfields ',' msgfield { $$ = concat_data_list($1, $3); }
| msgfield { $$ = make_data_list($1); }
;
msgfield
: STRING '=' expr
{
$$ = $3;
$$.name = (char*) $1.ptr;
}
| datatype STRING '=' expr
{
$$ = cast($1, $4);
$$.name = (char*) $2.ptr;
}
| TYPECODE STRING '=' expr
{
$$ = $4;
$$.type.code = $1;
$$.name = (char*) $2.ptr;
}
| TYPECODE datatype STRING '=' expr
{
$$ = cast($2, $5);
$$.type.code = $1;
$$.name = (char*) $3.ptr;
}
;
archive
: ARCHIVE IDENT '{' msgfields '}'
{
BMessage* msg = make_msg($4);
msg->AddString("class", $2);
free_mem($2);
$$ = flatten_msg(msg);
}
| ARCHIVE '(' STRING ')' IDENT '{' msgfields '}'
{
BMessage* msg = make_msg($7);
msg->AddString("class", $5);
msg->AddString("add_on", (char*) $3.ptr);
free_mem($5);
free_mem($3.ptr);
$$ = flatten_msg(msg);
}
| ARCHIVE '(' ',' integer ')' IDENT '{' msgfields '}'
{
BMessage* msg = make_msg($8);
msg->what = (int32) $4;
msg->AddString("class", $6);
free_mem($6);
$$ = flatten_msg(msg);
}
| ARCHIVE '(' STRING ',' integer ')' IDENT '{' msgfields '}'
{
BMessage* msg = make_msg($9);
msg->what = (int32) $5;
msg->AddString("class", $7);
msg->AddString("add_on", (char*) $3.ptr);
free_mem($7);
free_mem($3.ptr);
$$ = flatten_msg(msg);
}
;
type
: IDENT '{' typefields '}' { $$ = make_type($1, $3); }
| IDENT '{' '}'
{
list_t list; list.count = 0; list.items = NULL;
$$ = make_type($1, list);
}
| IDENT expr
{
$$ = make_type($1, make_data_list($2));
}
| type_or_define { $$ = $1; }
;
type_or_define
: IDENT
{
if (is_type($1))
{
list_t list; list.count = 0; list.items = NULL;
$$ = make_type($1, list);
}
else
{
define_t define = get_define($1);
$$ = cast(get_type("int32"), make_int(define.value));
free_mem($1);
}
}
;
typefields
: typefields ',' typefield { $$ = concat_data_list($1, $3); }
| typefield { $$ = make_data_list($1); }
;
typefield
: IDENT '=' expr { $$ = $3; $$.name = $1; }
| expr { $$ = $1; }
;
expr
: expr '+' expr { $$ = binary_expr($1, $3, '+'); }
| expr '-' expr { $$ = binary_expr($1, $3, '-'); }
| expr '*' expr { $$ = binary_expr($1, $3, '*'); }
| expr '/' expr { $$ = binary_expr($1, $3, '/'); }
| expr '%' expr { $$ = binary_expr($1, $3, '%'); }
| expr '|' expr { $$ = binary_expr($1, $3, '|'); }
| expr '^' expr { $$ = binary_expr($1, $3, '^'); }
| expr '&' expr { $$ = binary_expr($1, $3, '&'); }
| '~' expr %prec FLIP { $$ = unary_expr($2, '~'); }
| data { $$ = $1; }
;
data
: BOOL { $$ = cast(get_type("bool"), make_bool($1)); }
| integer { $$ = cast(get_type("int32"), make_int($1)); }
| float { $$ = cast(get_type("float"), make_float($1)); }
| STRING { $$ = cast($1.type, $1); }
| RAW { $$ = cast($1.type, $1); }
| array { $$ = cast($1.type, $1); }
| message { $$ = cast($1.type, $1); }
| archive { $$ = cast($1.type, $1); }
| type { $$ = cast($1.type, $1); }
| '(' expr ')' { $$ = $2; }
| typecast BOOL { $$ = cast($1, make_bool($2)); }
| typecast integer { $$ = cast($1, make_int($2)); }
| typecast float { $$ = cast($1, make_float($2)); }
| typecast STRING { $$ = cast($1, $2); }
| typecast RAW { $$ = cast($1, $2); }
| typecast array { $$ = cast($1, $2); }
| typecast message { $$ = cast($1, $2); }
| typecast archive { $$ = cast($1, $2); }
| typecast type { $$ = cast($1, $2); }
| typecast '(' expr ')' { $$ = cast($1, $3); }
;
typecast
: '(' ARRAY ')' { $$ = get_type("raw"); }
| '(' MESSAGE ')' { $$ = get_type("message"); }
| '(' ARCHIVE IDENT ')' { $$ = get_type("message"); free_mem($3); }
| '(' IDENT ')' { $$ = get_type($2); free_mem($2); }
;
datatype
: ARRAY { $$ = get_type("raw"); }
| MESSAGE { $$ = get_type("message"); }
| ARCHIVE IDENT { $$ = get_type("message"); free_mem($2); }
| IDENT { $$ = get_type($1); free_mem($1); }
;
integer
: INTEGER { $$ = $1; }
| '-' INTEGER { $$ = -($2); }
;
float
: FLOAT { $$ = $1; }
| '-' FLOAT { $$ = -($2); }
;
%%
void
yyerror(const char* msg)
{
rdef_err = RDEF_COMPILE_ERR;
rdef_err_line = yylineno;
strcpy(rdef_err_file, lexfile);
strcpy(rdef_err_msg, msg);
}
void
add_symbol(const char* name, int32 id)
{
if (symbol_table.find(name) != symbol_table.end())
abort_compile(RDEF_COMPILE_ERR, "duplicate symbol %s", name);
symbol_table.insert(make_pair(name, id));
}
int32
get_symbol(const char* name)
{
sym_iter_t i = symbol_table.find(name);
if (i == symbol_table.end())
abort_compile(RDEF_COMPILE_ERR, "unknown symbol %s", name);
return i->second;
}
static void
add_builtin_type(type_code code, const char* name)
{
type_t type;
type.code = code;
type.name = name;
type.count = 0;
type.fields = NULL;
type.def_id = 1;
type.def_name = NULL;
type_table.insert(make_pair(name, type));
}
void
add_user_type(res_id_t id, type_code code, const char* name, list_t list)
{
if (type_table.find(name) != type_table.end())
abort_compile(RDEF_COMPILE_ERR, "duplicate type %s", name);
type_t type;
type.code = code;
type.name = name;
type.count = list.count;
type.fields = (field_t*) list.items;
type.def_id = 1;
type.def_name = NULL;
if (id.has_id)
type.def_id = id.id;
if (id.has_name)
type.def_name = id.name;
type_table.insert(make_pair(name, type));
}
static bool
is_builtin_type(type_t type)
{
return type.count == 0;
}
static bool
same_type(type_t type1, type_t type2)
{
return type1.name == type2.name;
}
type_t
get_type(const char* name)
{
type_iter_t i = type_table.find(name);
if (i == type_table.end())
abort_compile(RDEF_COMPILE_ERR, "unknown type %s", name);
return i->second;
}
bool
is_type(const char* name)
{
return type_table.find(name) != type_table.end();
}
define_t
get_define(const char* name)
{
define_iter_t i = define_table.find(name);
if (i == define_table.end())
abort_compile(RDEF_COMPILE_ERR, "unknown define %s", name);
return i->second;
}
data_t
make_data(size_t size, type_t type)
{
data_t out;
out.type = type;
out.name = NULL;
out.size = size;
out.ptr = alloc_mem(size);
return out;
}
data_t
make_bool(bool b)
{
data_t out = make_data(sizeof(bool), get_type("bool"));
*((bool*)out.ptr) = b;
return out;
}
data_t
make_int(uint64 i)
{
data_t out = make_data(sizeof(uint64), get_type("uint64"));
*((uint64*)out.ptr) = i;
return out;
}
data_t
make_float(double f)
{
data_t out = make_data(sizeof(double), get_type("double"));
*((double*)out.ptr) = f;
return out;
}
data_t
import_data(char* filename)
{
data_t out;
out.type = get_type("raw");
out.name = NULL;
char tmpname[B_PATH_NAME_LENGTH];
if (open_file_from_include_dir(filename, tmpname)) {
BFile file(tmpname, B_READ_ONLY);
if (file.InitCheck() == B_OK) {
off_t size;
if (file.GetSize(&size) == B_OK) {
out.size = (size_t) size;
out.ptr = alloc_mem(size);
if (file.Read(out.ptr, out.size) == (ssize_t) out.size) {
free_mem(filename);
return out;
}
}
}
}
abort_compile(RDEF_COMPILE_ERR, "cannot import %s", filename);
return out;
}
data_t
resize_data(data_t data, size_t newSize)
{
if (newSize == 0) {
abort_compile(RDEF_COMPILE_ERR, "invalid size %lu", newSize);
} else if (data.size != newSize) {
void* newBuffer = alloc_mem(newSize);
memset(newBuffer, 0, newSize);
memcpy(newBuffer, data.ptr, min(data.size, newSize));
if (data.type.code == B_STRING_TYPE)
((char*)newBuffer)[newSize - 1] = '\0';
free_mem(data.ptr);
data.ptr = newBuffer;
data.size = newSize;
}
return data;
}
BMessage*
make_msg(list_t list)
{
BMessage* msg = new BMessage;
for (int32 t = 0; t < list.count; ++t) {
data_t data = ((data_t*)list.items)[t];
msg->AddData(data.name, data.type.code, data.ptr, data.size, false);
free_mem(data.name);
free_mem(data.ptr);
}
free_mem(list.items);
return msg;
}
data_t
flatten_msg(BMessage* msg)
{
#ifndef B_BEOS_VERSION_DANO
data_t out = make_data(msg->FlattenedSize(), get_type("message"));
msg->Flatten((char*)out.ptr, out.size);
#else
data_t out = make_data(msg->FlattenedSize(B_MESSAGE_VERSION_1),
get_type("message"));
msg->Flatten(B_MESSAGE_VERSION_1, (char*)out.ptr, out.size);
#endif
delete msg;
return out;
}
data_t
make_default(type_t type)
{
data_t out;
if (is_builtin_type(type)) {
switch (type.code) {
case B_BOOL_TYPE:
out = make_data(sizeof(bool), type);
*((bool*)out.ptr) = false;
break;
case B_INT8_TYPE:
case B_UINT8_TYPE:
out = make_data(sizeof(uint8), type);
*((uint8*)out.ptr) = 0;
break;
case B_INT16_TYPE:
case B_UINT16_TYPE:
out = make_data(sizeof(uint16), type);
*((uint16*)out.ptr) = 0;
break;
case B_INT32_TYPE:
case B_UINT32_TYPE:
case B_SIZE_T_TYPE:
case B_SSIZE_T_TYPE:
case B_TIME_TYPE:
out = make_data(sizeof(uint32), type);
*((uint32*)out.ptr) = 0;
break;
case B_INT64_TYPE:
case B_UINT64_TYPE:
case B_OFF_T_TYPE:
out = make_data(sizeof(uint64), type);
*((uint64*)out.ptr) = 0;
break;
case B_FLOAT_TYPE:
out = make_data(sizeof(float), type);
*((float*)out.ptr) = 0.0f;
break;
case B_DOUBLE_TYPE:
out = make_data(sizeof(double), type);
*((double*)out.ptr) = 0.0;
break;
case B_STRING_TYPE:
out = make_data(sizeof(char), type);
*((char*)out.ptr) = '\0';
break;
case B_RAW_TYPE:
out = make_data(0, type);
break;
case B_MESSAGE_TYPE:
out = flatten_msg(new BMessage);
break;
}
} else {
size_t size = 0;
for (int32 t = 0; t < type.count; ++t) {
size += type.fields[t].data.size;
}
out = make_data(size, type);
uint8* ptr = (uint8*) out.ptr;
for (int32 t = 0; t < type.count; ++t) {
data_t field_data = type.fields[t].data;
memcpy(ptr, field_data.ptr, field_data.size);
ptr += field_data.size;
}
}
return out;
}
static data_t*
fill_slots(type_t type, list_t list)
{
data_t* slots = (data_t*)alloc_mem(type.count * sizeof(data_t));
memset(slots, 0, type.count * sizeof(data_t));
for (int32 t = 0; t < list.count; ++t) {
data_t data = ((data_t*)list.items)[t];
if (data.name == NULL) {
bool found = false;
for (int32 k = 0; k < type.count; ++k) {
if (slots[k].ptr == NULL) {
slots[k] = cast(type.fields[k].type, data);
found = true;
break;
}
}
if (!found)
abort_compile(RDEF_COMPILE_ERR, "too many fields");
} else {
bool found = false;
for (int32 k = 0; k < type.count; ++k) {
if (strcmp(type.fields[k].name, data.name) == 0) {
if (slots[k].ptr != NULL)
free_mem(slots[k].ptr);
slots[k] = cast(type.fields[k].type, data);
free_mem(data.name);
found = true;
break;
}
}
if (!found)
abort_compile(RDEF_COMPILE_ERR, "unknown field %s", data.name);
}
}
return slots;
}
static data_t
convert_slots(type_t type, data_t* slots)
{
size_t size = 0;
for (int32 k = 0; k < type.count; ++k) {
if (slots[k].ptr == NULL) {
size += type.fields[k].data.size;
} else if (type.fields[k].resize != 0)
size += type.fields[k].resize;
else
size += slots[k].size;
}
data_t out = make_data(size, type);
uint8* ptr = (uint8*) out.ptr;
for (int32 k = 0; k < type.count; ++k) {
if (slots[k].ptr == NULL) {
memcpy(ptr, type.fields[k].data.ptr, type.fields[k].data.size);
ptr += type.fields[k].data.size;
} else if (type.fields[k].resize != 0) {
data_t temp = resize_data(slots[k], type.fields[k].resize);
memcpy(ptr, temp.ptr, temp.size);
ptr += temp.size;
free_mem(temp.ptr);
} else {
memcpy(ptr, slots[k].ptr, slots[k].size);
ptr += slots[k].size;
free_mem(slots[k].ptr);
}
}
free_mem(slots);
return out;
}
data_t
make_type(char* name, list_t list)
{
type_t type = get_type(name);
data_t* slots = fill_slots(type, list);
data_t out = convert_slots(type, slots);
free_mem(name);
free_mem(list.items);
return out;
}
list_t
make_field_list(field_t field)
{
list_t out;
out.count = 1;
out.items = alloc_mem(sizeof(field_t));
*((field_t*)out.items) = field;
return out;
}
list_t
concat_field_list(list_t list, field_t field)
{
list_t out;
out.count = list.count + 1;
out.items = alloc_mem(out.count * sizeof(field_t));
memcpy(out.items, list.items, list.count * sizeof(field_t));
memcpy((field_t*)out.items + list.count, &field, sizeof(field_t));
free_mem(list.items);
return out;
}
list_t
make_data_list(data_t data)
{
list_t out;
out.count = 1;
out.items = alloc_mem(sizeof(data_t));
*((data_t*)out.items) = data;
return out;
}
list_t
concat_data_list(list_t list, data_t data)
{
list_t out;
out.count = list.count + 1;
out.items = (data_t*)alloc_mem(out.count * sizeof(data_t));
memcpy(out.items, list.items, list.count * sizeof(data_t));
memcpy((data_t*)out.items + list.count, &data, sizeof(data_t));
free_mem(list.items);
return out;
}
data_t
concat_data(data_t data1, data_t data2)
{
data_t out = make_data(data1.size + data2.size, get_type("raw"));
memcpy(out.ptr, data1.ptr, data1.size);
memcpy((uint8*)out.ptr + data1.size, data2.ptr, data2.size);
free_mem(data1.ptr);
free_mem(data2.ptr);
return out;
}
static data_t
cast_to_uint8(type_t new_type, data_t data)
{
data_t out = make_data(sizeof(uint8), new_type);
switch (data.type.code) {
case B_INT8_TYPE:
case B_UINT8_TYPE:
*((uint8*)out.ptr) = *(uint8*)data.ptr;
break;
case B_INT16_TYPE:
case B_UINT16_TYPE:
*((uint8*)out.ptr) = (uint8)*(uint16*)data.ptr;
break;
case B_INT32_TYPE:
case B_UINT32_TYPE:
case B_SIZE_T_TYPE:
case B_SSIZE_T_TYPE:
case B_TIME_TYPE:
*((uint8*)out.ptr) = (uint8)*(uint32*)data.ptr;
break;
case B_INT64_TYPE:
case B_UINT64_TYPE:
case B_OFF_T_TYPE:
*((uint8*)out.ptr) = (uint8)*(uint64*)data.ptr;
break;
default:
abort_compile(RDEF_COMPILE_ERR, "cannot cast to this type");
}
free_mem(data.ptr);
return out;
}
static data_t
cast_to_uint16(type_t new_type, data_t data)
{
data_t out = make_data(sizeof(uint16), new_type);
switch (data.type.code) {
case B_INT8_TYPE:
case B_UINT8_TYPE:
*((uint16*)out.ptr) = (uint16)*(uint8*)data.ptr;
break;
case B_INT16_TYPE:
case B_UINT16_TYPE:
*((uint16*)out.ptr) = *(uint16*)data.ptr;
break;
case B_INT32_TYPE:
case B_UINT32_TYPE:
case B_SIZE_T_TYPE:
case B_SSIZE_T_TYPE:
case B_TIME_TYPE:
*((uint16*)out.ptr) = (uint16)*(uint32*)data.ptr;
break;
case B_INT64_TYPE:
case B_UINT64_TYPE:
case B_OFF_T_TYPE:
*((uint16*)out.ptr) = (uint16)*(uint64*)data.ptr;
break;
default:
abort_compile(RDEF_COMPILE_ERR, "cannot cast to this type");
}
free_mem(data.ptr);
return out;
}
static data_t
cast_to_uint32(type_t new_type, data_t data)
{
data_t out = make_data(sizeof(uint32), new_type);
switch (data.type.code) {
case B_INT8_TYPE:
case B_UINT8_TYPE:
*((uint32*)out.ptr) = (uint32)*(uint8*)data.ptr;
break;
case B_INT16_TYPE:
case B_UINT16_TYPE:
*((uint32*)out.ptr) = (uint32)*(uint16*)data.ptr;
break;
case B_INT32_TYPE:
case B_UINT32_TYPE:
case B_SIZE_T_TYPE:
case B_SSIZE_T_TYPE:
case B_TIME_TYPE:
*((uint32*)out.ptr) = *(uint32*)data.ptr;
break;
case B_INT64_TYPE:
case B_UINT64_TYPE:
case B_OFF_T_TYPE:
*((uint32*)out.ptr) = (uint32)*(uint64*)data.ptr;
break;
default:
abort_compile(RDEF_COMPILE_ERR, "cannot cast to this type");
}
free_mem(data.ptr);
return out;
}
static data_t
cast_to_uint64(type_t new_type, data_t data)
{
data_t out = make_data(sizeof(uint64), new_type);
switch (data.type.code) {
case B_INT8_TYPE:
case B_UINT8_TYPE:
*((uint64*)out.ptr) = (uint64)*(uint8*)data.ptr;
break;
case B_INT16_TYPE:
case B_UINT16_TYPE:
*((uint64*)out.ptr) = (uint64)*(uint16*)data.ptr;
break;
case B_INT32_TYPE:
case B_UINT32_TYPE:
case B_SIZE_T_TYPE:
case B_SSIZE_T_TYPE:
case B_TIME_TYPE:
*((uint64*)out.ptr) = (uint64)*(uint32*)data.ptr;
break;
case B_INT64_TYPE:
case B_UINT64_TYPE:
case B_OFF_T_TYPE:
*((uint64*)out.ptr) = *(uint64*)data.ptr;
break;
default:
abort_compile(RDEF_COMPILE_ERR, "cannot cast to this type");
}
free_mem(data.ptr);
return out;
}
static data_t
cast_to_float(type_t new_type, data_t data)
{
data_t out = make_data(sizeof(float), new_type);
switch (data.type.code) {
case B_INT8_TYPE:
case B_UINT8_TYPE:
*((float*)out.ptr) = (float)*((uint8*)data.ptr);
break;
case B_INT16_TYPE:
case B_UINT16_TYPE:
*((float*)out.ptr) = (float)*((uint16*)data.ptr);
break;
case B_INT32_TYPE:
case B_UINT32_TYPE:
case B_SIZE_T_TYPE:
case B_SSIZE_T_TYPE:
case B_TIME_TYPE:
*((float*)out.ptr) = (float)*((uint32*)data.ptr);
break;
case B_INT64_TYPE:
case B_UINT64_TYPE:
case B_OFF_T_TYPE:
*((float*)out.ptr) = (float)*((uint64*)data.ptr);
break;
case B_DOUBLE_TYPE:
*((float*)out.ptr) = (float)*((double*)data.ptr);
break;
default:
abort_compile(RDEF_COMPILE_ERR, "cannot cast to this type");
}
free_mem(data.ptr);
return out;
}
static data_t
cast_to_double(type_t new_type, data_t data)
{
data_t out = make_data(sizeof(double), new_type);
switch (data.type.code) {
case B_INT8_TYPE:
case B_UINT8_TYPE:
*((double*)out.ptr) = (double)*((uint8*)data.ptr);
break;
case B_INT16_TYPE:
case B_UINT16_TYPE:
*((double*)out.ptr) = (double)*((uint16*)data.ptr);
break;
case B_INT32_TYPE:
case B_UINT32_TYPE:
case B_SIZE_T_TYPE:
case B_SSIZE_T_TYPE:
case B_TIME_TYPE:
*((double*)out.ptr) = (double)*((uint32*)data.ptr);
break;
case B_INT64_TYPE:
case B_UINT64_TYPE:
case B_OFF_T_TYPE:
*((double*)out.ptr) = (double)*((uint64*)data.ptr);
break;
case B_FLOAT_TYPE:
*((double*)out.ptr) = (double)*((float*)data.ptr);
break;
default:
abort_compile(RDEF_COMPILE_ERR, "cannot cast to this type");
}
free_mem(data.ptr);
return out;
}
data_t
cast(type_t newType, data_t data)
{
if (same_type(newType, data.type)) {
return data;
}
if (is_builtin_type(newType)) {
switch (newType.code) {
case B_INT8_TYPE:
case B_UINT8_TYPE:
return cast_to_uint8(newType, data);
case B_INT16_TYPE:
case B_UINT16_TYPE:
return cast_to_uint16(newType, data);
case B_INT32_TYPE:
case B_UINT32_TYPE:
case B_SIZE_T_TYPE:
case B_SSIZE_T_TYPE:
case B_TIME_TYPE:
return cast_to_uint32(newType, data);
case B_INT64_TYPE:
case B_UINT64_TYPE:
case B_OFF_T_TYPE:
return cast_to_uint64(newType, data);
case B_FLOAT_TYPE:
return cast_to_float(newType, data);
case B_DOUBLE_TYPE:
return cast_to_double(newType, data);
case B_RAW_TYPE:
data.type = newType;
return data;
}
}
abort_compile(RDEF_COMPILE_ERR, "cannot cast to this type");
return data;
}
data_t
unary_expr(data_t data, char oper)
{
data_t op = cast_to_uint32(get_type("int32"), data);
int32 i = *((int32*)op.ptr);
data_t out;
switch (oper) {
case '~':
out = make_int(~i);
break;
}
free_mem(op.ptr);
return cast(get_type("int32"), out);
}
data_t
binary_expr(data_t data1, data_t data2, char oper)
{
data_t op1 = cast_to_uint32(get_type("int32"), data1);
data_t op2 = cast_to_uint32(get_type("int32"), data2);
int32 i1 = *((int32*) op1.ptr);
int32 i2 = *((int32*) op2.ptr);
data_t out;
switch (oper) {
case '+':
out = make_int(i1 + i2);
break;
case '-':
out = make_int(i1 - i2);
break;
case '*':
out = make_int(i1 * i2);
break;
case '/':
if (i2 == 0)
abort_compile(RDEF_COMPILE_ERR, "division by zero");
else
out = make_int(i1 / i2);
break;
case '%':
if (i2 == 0)
abort_compile(RDEF_COMPILE_ERR, "division by zero");
else
out = make_int(i1 % i2);
break;
case '|':
out = make_int(i1 | i2);
break;
case '^':
out = make_int(i1 ^ i2);
break;
case '&':
out = make_int(i1 & i2);
break;
}
free_mem(op1.ptr);
free_mem(op2.ptr);
return cast(get_type("int32"), out);
}
void
add_resource(res_id_t id, type_code code, data_t data)
{
if (!id.has_id)
id.id = data.type.def_id;
if (!id.has_name)
id.name = (char*)data.type.def_name;
if (!(flags & RDEF_MERGE_RESOURCES) && rsrc.HasResource(code, id.id))
abort_compile(RDEF_COMPILE_ERR, "duplicate resource");
status_t err = rsrc.AddResource(code, id.id, data.ptr, data.size, id.name);
if (err != B_OK) {
rdef_err = RDEF_WRITE_ERR;
rdef_err_line = 0;
strcpy(rdef_err_file, rsrc_file);
sprintf(rdef_err_msg, "cannot add resource (%s)", strerror(err));
abort_compile();
}
if (id.has_name)
free_mem(id.name);
free_mem(data.ptr);
}
static void
add_point_type()
{
field_t* fields = (field_t*)alloc_mem(2 * sizeof(field_t));
fields[0].type = get_type("float");
fields[0].name = "x";
fields[0].resize = 0;
fields[0].data = make_default(fields[0].type);
fields[1].type = get_type("float");
fields[1].name = "y";
fields[1].resize = 0;
fields[1].data = make_default(fields[1].type);
type_t type;
type.code = B_POINT_TYPE;
type.name = "point";
type.fields = fields;
type.count = 2;
type.def_id = 1;
type.def_name = NULL;
type_table.insert(make_pair(type.name, type));
}
static void
add_rect_type()
{
field_t* fields = (field_t*)alloc_mem(4 * sizeof(field_t));
fields[0].type = get_type("float");
fields[0].name = "left";
fields[0].resize = 0;
fields[0].data = make_default(fields[0].type);
fields[1].type = get_type("float");
fields[1].name = "top";
fields[1].resize = 0;
fields[1].data = make_default(fields[1].type);
fields[2].type = get_type("float");
fields[2].name = "right";
fields[2].resize = 0;
fields[2].data = make_default(fields[2].type);
fields[3].type = get_type("float");
fields[3].name = "bottom";
fields[3].resize = 0;
fields[3].data = make_default(fields[3].type);
type_t type;
type.code = B_RECT_TYPE;
type.name = "rect";
type.fields = fields;
type.count = 4;
type.def_id = 1;
type.def_name = NULL;
type_table.insert(make_pair(type.name, type));
}
static void
add_rgb_color_type()
{
field_t* fields = (field_t*)alloc_mem(4 * sizeof(field_t));
fields[0].type = get_type("uint8");
fields[0].name = "red";
fields[0].resize = 0;
fields[0].data = make_default(fields[0].type);
fields[1].type = get_type("uint8");
fields[1].name = "green";
fields[1].resize = 0;
fields[1].data = make_default(fields[1].type);
fields[2].type = get_type("uint8");
fields[2].name = "blue";
fields[2].resize = 0;
fields[2].data = make_default(fields[2].type);
fields[3].type = get_type("uint8");
fields[3].name = "alpha";
fields[3].resize = 0;
fields[3].data = make_default(fields[3].type);
*((uint8*)fields[3].data.ptr) = 255;
type_t type;
type.code = B_RGB_COLOR_TYPE;
type.name = "rgb_color";
type.fields = fields;
type.count = 4;
type.def_id = 1;
type.def_name = NULL;
type_table.insert(make_pair(type.name, type));
}
static void
add_app_signature_type()
{
field_t* fields = (field_t*)alloc_mem(1 * sizeof(field_t));
fields[0].type = get_type("string");
fields[0].name = "signature";
fields[0].resize = 0;
fields[0].data = make_default(fields[0].type);
type_t type;
type.code = 'MIMS';
type.name = "app_signature";
type.fields = fields;
type.count = 1;
type.def_id = 1;
type.def_name = "BEOS:APP_SIG";
type_table.insert(make_pair(type.name, type));
}
static void
add_app_name_catalog_entry()
{
field_t* fields = (field_t*)alloc_mem(1 * sizeof(field_t));
fields[0].type = get_type("string");
fields[0].name = "catalog_entry";
fields[0].resize = 0;
fields[0].data = make_default(fields[0].type);
type_t type;
type.code = B_STRING_TYPE;
type.name = "app_name_catalog_entry";
type.fields = fields;
type.count = 1;
type.def_id = 1;
type.def_name = "SYS:NAME";
type_table.insert(make_pair(type.name, type));
}
static void
add_app_flags()
{
field_t* fields = (field_t*)alloc_mem(1 * sizeof(field_t));
fields[0].type = get_type("uint32");
fields[0].name = "flags";
fields[0].resize = 0;
fields[0].data = make_default(fields[0].type);
type_t type;
type.code = 'APPF';
type.name = "app_flags";
type.fields = fields;
type.count = 1;
type.def_id = 1;
type.def_name = "BEOS:APP_FLAGS";
type_table.insert(make_pair(type.name, type));
}
static void
add_app_version()
{
field_t* fields = (field_t*)alloc_mem(7 * sizeof(field_t));
fields[0].type = get_type("uint32");
fields[0].name = "major";
fields[0].resize = 0;
fields[0].data = make_default(fields[0].type);
fields[1].type = get_type("uint32");
fields[1].name = "middle";
fields[1].resize = 0;
fields[1].data = make_default(fields[1].type);
fields[2].type = get_type("uint32");
fields[2].name = "minor";
fields[2].resize = 0;
fields[2].data = make_default(fields[2].type);
fields[3].type = get_type("uint32");
fields[3].name = "variety";
fields[3].resize = 0;
fields[3].data = make_default(fields[3].type);
fields[4].type = get_type("uint32");
fields[4].name = "internal";
fields[4].resize = 0;
fields[4].data = make_default(fields[4].type);
fields[5].type = get_type("string");
fields[5].name = "short_info";
fields[5].resize = 64;
fields[5].data = make_data(fields[5].resize, fields[5].type);
fields[6].type = get_type("string");
fields[6].name = "long_info";
fields[6].resize = 256;
fields[6].data = make_data(fields[6].resize, fields[6].type);
memset(fields[5].data.ptr, '\0', fields[5].data.size);
memset(fields[6].data.ptr, '\0', fields[6].data.size);
type_t type;
type.code = 'APPV';
type.name = "app_version";
type.fields = fields;
type.count = 7;
type.def_id = 1;
type.def_name = "BEOS:APP_VERSION";
type_table.insert(make_pair(type.name, type));
}
static void
add_png_icon()
{
field_t* fields = (field_t*)alloc_mem(1 * sizeof(field_t));
fields[0].type = get_type("raw");
fields[0].name = "icon";
fields[0].resize = 0;
fields[0].data = make_data(fields[0].resize, fields[0].type);
type_t type;
type.code = 'PNG ';
type.name = "png_icon";
type.fields = fields;
type.count = 1;
type.def_id = 101;
type.def_name = "BEOS:ICON";
type_table.insert(make_pair(type.name, type));
}
static void
add_vector_icon()
{
field_t* fields = (field_t*)alloc_mem(1 * sizeof(field_t));
fields[0].type = get_type("raw");
fields[0].name = "icon";
fields[0].resize = 0;
fields[0].data = make_data(fields[0].resize, fields[0].type);
type_t type;
type.code = 'VICN';
type.name = "vector_icon";
type.fields = fields;
type.count = 1;
type.def_id = 101;
type.def_name = "BEOS:ICON";
type_table.insert(make_pair(type.name, type));
}
static void
add_large_icon()
{
field_t* fields = (field_t*)alloc_mem(1 * sizeof(field_t));
fields[0].type = get_type("raw");
fields[0].name = "icon";
fields[0].resize = 1024;
fields[0].data = make_data(fields[0].resize, fields[0].type);
type_t type;
type.code = 'ICON';
type.name = "large_icon";
type.fields = fields;
type.count = 1;
type.def_id = 101;
type.def_name = "BEOS:L:STD_ICON";
type_table.insert(make_pair(type.name, type));
}
static void
add_mini_icon()
{
field_t* fields = (field_t*)alloc_mem(1 * sizeof(field_t));
fields[0].type = get_type("raw");
fields[0].name = "icon";
fields[0].resize = 256;
fields[0].data = make_data(fields[0].resize, fields[0].type);
type_t type;
type.code = 'MICN';
type.name = "mini_icon";
type.fields = fields;
type.count = 1;
type.def_id = 101;
type.def_name = "BEOS:M:STD_ICON";
type_table.insert(make_pair(type.name, type));
}
static void
add_file_types()
{
field_t* fields = (field_t*)alloc_mem(1 * sizeof(field_t));
fields[0].type = get_type("message");
fields[0].name = "types";
fields[0].resize = 0;
fields[0].data = make_default(fields[0].type);
type_t type;
type.code = 'MSGG';
type.name = "file_types";
type.fields = fields;
type.count = 1;
type.def_id = 1;
type.def_name = "BEOS:FILE_TYPES";
type_table.insert(make_pair(type.name, type));
}
static void
add_define(const char* name, int32 value)
{
define_t define;
define.name = name;
define.value = value;
define_table.insert(make_pair(define.name, define));
}
void
init_parser()
{
add_builtin_type(B_BOOL_TYPE, "bool");
add_builtin_type(B_INT8_TYPE, "int8");
add_builtin_type(B_UINT8_TYPE, "uint8");
add_builtin_type(B_INT16_TYPE, "int16");
add_builtin_type(B_UINT16_TYPE, "uint16");
add_builtin_type(B_INT32_TYPE, "int32");
add_builtin_type(B_UINT32_TYPE, "uint32");
add_builtin_type(B_SIZE_T_TYPE, "size_t");
add_builtin_type(B_SSIZE_T_TYPE, "ssize_t");
add_builtin_type(B_TIME_TYPE, "time_t");
add_builtin_type(B_INT64_TYPE, "int64");
add_builtin_type(B_UINT64_TYPE, "uint64");
add_builtin_type(B_OFF_T_TYPE, "off_t");
add_builtin_type(B_FLOAT_TYPE, "float");
add_builtin_type(B_DOUBLE_TYPE, "double");
add_builtin_type(B_STRING_TYPE, "string");
add_builtin_type(B_RAW_TYPE, "raw");
add_builtin_type(B_RAW_TYPE, "buffer");
add_builtin_type(B_MESSAGE_TYPE, "message");
add_point_type();
add_rect_type();
add_rgb_color_type();
add_app_signature_type();
add_app_name_catalog_entry();
add_app_flags();
add_app_version();
add_large_icon();
add_mini_icon();
add_vector_icon();
add_png_icon();
add_file_types();
add_define("B_SINGLE_LAUNCH", 0x0);
add_define("B_MULTIPLE_LAUNCH", 0x1);
add_define("B_EXCLUSIVE_LAUNCH", 0x2);
add_define("B_BACKGROUND_APP", 0x4);
add_define("B_ARGV_ONLY", 0x8);
add_define("B_APPV_DEVELOPMENT", 0x0);
add_define("B_APPV_ALPHA", 0x1);
add_define("B_APPV_BETA", 0x2);
add_define("B_APPV_GAMMA", 0x3);
add_define("B_APPV_GOLDEN_MASTER", 0x4);
add_define("B_APPV_FINAL", 0x5);
}
void
clean_up_parser()
{
#ifdef DEBUG
for (sym_iter_t i = symbol_table.begin(); i != symbol_table.end(); ++i) {
free_mem((void*) i->first);
}
for (type_iter_t i = type_table.begin(); i != type_table.end(); ++i) {
free_mem((void*) i->first);
type_t type = i->second;
for (int32 t = 0; t < type.count; ++t) {
free_mem((void*) type.fields[t].name);
free_mem((void*) type.fields[t].data.ptr);
}
free_mem((void*) type.fields);
free_mem((void*) type.name);
free_mem((void*) type.def_name);
}
#endif
symbol_table.clear();
type_table.clear();
define_table.clear();
}