* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
-#include <stdio.h>
-#include <stdarg.h>
+#include <string.h>
#include <math.h>
#include "gmqcc.h"
* We should also consider adding correction tables for
* other things as well.
*/
- if (OPTS_OPTION_BOOL(OPTION_CORRECTION)) {
+ if (OPTS_OPTION_BOOL(OPTION_CORRECTION) && strlen(parser_tokval(parser)) <= 16) {
correction_t corr;
correct_init(&corr);
}
vec_push(func->blocks, block);
-
+
parser->function = old;
if (!parser_leaveblock(parser))
return NULL;
}
- cexp = parse_expression_leave(parser, true, false, false);
+ if (parser->tok != ']') {
+ cexp = parse_expression_leave(parser, true, false, false);
- if (!cexp || !ast_istype(cexp, ast_value)) {
- if (cexp)
- ast_unref(cexp);
- ast_delete(var);
- parseerror(parser, "expected array-size as constant positive integer");
- return NULL;
+ if (!cexp || !ast_istype(cexp, ast_value)) {
+ if (cexp)
+ ast_unref(cexp);
+ ast_delete(var);
+ parseerror(parser, "expected array-size as constant positive integer");
+ return NULL;
+ }
+ cval = (ast_value*)cexp;
+ }
+ else {
+ cexp = NULL;
+ cval = NULL;
}
- cval = (ast_value*)cexp;
tmp = ast_value_new(ctx, "<type[]>", TYPE_ARRAY);
tmp->expression.next = (ast_expression*)var;
var = tmp;
- if (cval->expression.vtype == TYPE_INTEGER)
- tmp->expression.count = cval->constval.vint;
- else if (cval->expression.vtype == TYPE_FLOAT)
- tmp->expression.count = cval->constval.vfloat;
- else {
+ if (cval) {
+ if (cval->expression.vtype == TYPE_INTEGER)
+ tmp->expression.count = cval->constval.vint;
+ else if (cval->expression.vtype == TYPE_FLOAT)
+ tmp->expression.count = cval->constval.vfloat;
+ else {
+ ast_unref(cexp);
+ ast_delete(var);
+ parseerror(parser, "array-size must be a positive integer constant");
+ return NULL;
+ }
+
ast_unref(cexp);
- ast_delete(var);
- parseerror(parser, "array-size must be a positive integer constant");
- return NULL;
+ } else {
+ var->expression.count = -1;
+ var->expression.flags |= AST_FLAG_ARRAY_INIT;
}
- ast_unref(cexp);
if (parser->tok != ']') {
ast_delete(var);
return true;
}
+static bool create_array_accessors(parser_t *parser, ast_value *var)
+{
+ char name[1024];
+ util_snprintf(name, sizeof(name), "%s##SET", var->name);
+ if (!parser_create_array_setter(parser, var, name))
+ return false;
+ util_snprintf(name, sizeof(name), "%s##GET", var->name);
+ if (!parser_create_array_getter(parser, var, var->expression.next, name))
+ return false;
+ return true;
+}
+
+static bool parse_array(parser_t *parser, ast_value *array)
+{
+ size_t i;
+ if (array->initlist) {
+ parseerror(parser, "array already initialized elsewhere");
+ return false;
+ }
+ if (!parser_next(parser)) {
+ parseerror(parser, "parse error in array initializer");
+ return false;
+ }
+ i = 0;
+ while (parser->tok != '}') {
+ ast_value *v = (ast_value*)parse_expression_leave(parser, true, false, false);
+ if (!v)
+ return false;
+ if (!ast_istype(v, ast_value) || !v->hasvalue || v->cvq != CV_CONST) {
+ ast_unref(v);
+ parseerror(parser, "initializing element must be a compile time constant");
+ return false;
+ }
+ vec_push(array->initlist, v->constval);
+ if (v->expression.vtype == TYPE_STRING) {
+ array->initlist[i].vstring = util_strdupe(array->initlist[i].vstring);
+ ++i;
+ }
+ ast_unref(v);
+ if (parser->tok == '}')
+ break;
+ if (parser->tok != ',' || !parser_next(parser)) {
+ parseerror(parser, "expected comma or '}' in element list");
+ return false;
+ }
+ }
+ if (!parser_next(parser) || parser->tok != ';') {
+ parseerror(parser, "expected semicolon after initializer, got %s");
+ return false;
+ }
+ /*
+ if (!parser_next(parser)) {
+ parseerror(parser, "parse error after initializer");
+ return false;
+ }
+ */
+
+ if (array->expression.flags & AST_FLAG_ARRAY_INIT) {
+ if (array->expression.count != (size_t)-1) {
+ parseerror(parser, "array `%s' has already been initialized with %u elements",
+ array->name, (unsigned)array->expression.count);
+ }
+ array->expression.count = vec_size(array->initlist);
+ if (!create_array_accessors(parser, array))
+ return false;
+ }
+ return true;
+}
+
static bool parse_variable(parser_t *parser, ast_block *localblock, bool nofields, int qualifier, ast_value *cached_typedef, bool noref, bool is_static, uint32_t qflags, char *vstring)
{
ast_value *var;
* deal with arrays
*/
if (var->expression.vtype == TYPE_ARRAY) {
- char name[1024];
- util_snprintf(name, sizeof(name), "%s##SET", var->name);
- if (!parser_create_array_setter(parser, var, name))
- goto cleanup;
- util_snprintf(name, sizeof(name), "%s##GET", var->name);
- if (!parser_create_array_getter(parser, var, var->expression.next, name))
- goto cleanup;
+ if (var->expression.count != (size_t)-1) {
+ if (!create_array_accessors(parser, var))
+ goto cleanup;
+ }
}
else if (!localblock && !nofields &&
var->expression.vtype == TYPE_FIELD &&
parseerror(parser, "TODO: initializers for local arrays");
break;
}
- /*
-static ast_expression* parse_expression_leave(parser_t *parser, bool stopatcomma, bool truthvalue, bool with_labels);
-*/
- parseerror(parser, "TODO: initializing global arrays is not supported yet!");
- break;
+
+ var->hasvalue = true;
+ if (!parse_array(parser, var))
+ break;
}
else if (var->expression.vtype == TYPE_FUNCTION && (parser->tok == '{' || parser->tok == '['))
{