+ parseerror(parser, "parse error after label");
+ return false;
+ }
+ for (i = 0; i < vec_size(parser->gotos); ++i) {
+ if (!strcmp(parser->gotos[i]->name, label->name)) {
+ ast_goto_set_label(parser->gotos[i], label);
+ vec_remove(parser->gotos, i, 1);
+ --i;
+ }
+ }
+ return true;
+ }
+ else if (parser->tok == ';')
+ {
+ if (!parser_next(parser)) {
+ parseerror(parser, "parse error after empty statement");
+ return false;
+ }
+ return true;
+ }
+ else
+ {
+ lex_ctx ctx = parser_ctx(parser);
+ ast_expression *exp = parse_expression(parser, false, false);
+ if (!exp)
+ return false;
+ *out = exp;
+ if (!ast_side_effects(exp)) {
+ if (compile_warning(ctx, WARN_EFFECTLESS_STATEMENT, "statement has no effect"))
+ return false;
+ }
+ return true;
+ }
+}
+
+static bool parse_enum(parser_t *parser)
+{
+ bool flag = false;
+ bool reverse = false;
+ qcfloat num = 0;
+ ast_value **values = NULL;
+ ast_value *var = NULL;
+ ast_value *asvalue;
+
+ ast_expression *old;
+
+ if (!parser_next(parser) || (parser->tok != '{' && parser->tok != ':')) {
+ parseerror(parser, "expected `{` or `:` after `enum` keyword");
+ return false;
+ }
+
+ /* enumeration attributes (can add more later) */
+ if (parser->tok == ':') {
+ if (!parser_next(parser) || parser->tok != TOKEN_IDENT){
+ parseerror(parser, "expected `flag` or `reverse` for enumeration attribute");
+ return false;
+ }
+
+ /* attributes? */
+ if (!strcmp(parser_tokval(parser), "flag")) {
+ num = 1;
+ flag = true;
+ }
+ else if (!strcmp(parser_tokval(parser), "reverse")) {
+ reverse = true;
+ }
+ else {
+ parseerror(parser, "invalid attribute `%s` for enumeration", parser_tokval(parser));
+ return false;
+ }
+
+ if (!parser_next(parser) || parser->tok != '{') {
+ parseerror(parser, "expected `{` after enum attribute ");
+ return false;
+ }
+ }
+
+ while (true) {
+ if (!parser_next(parser) || parser->tok != TOKEN_IDENT) {
+ if (parser->tok == '}') {
+ /* allow an empty enum */
+ break;
+ }
+ parseerror(parser, "expected identifier or `}`");
+ goto onerror;
+ }
+
+ old = parser_find_field(parser, parser_tokval(parser));
+ if (!old)
+ old = parser_find_global(parser, parser_tokval(parser));
+ if (old) {
+ parseerror(parser, "value `%s` has already been declared here: %s:%i",
+ parser_tokval(parser), ast_ctx(old).file, ast_ctx(old).line);
+ goto onerror;
+ }
+
+ var = ast_value_new(parser_ctx(parser), parser_tokval(parser), TYPE_FLOAT);
+ vec_push(values, var);
+ var->cvq = CV_CONST;
+ var->hasvalue = true;
+
+ /* for flagged enumerations increment in POTs of TWO */
+ var->constval.vfloat = (flag) ? (num *= 2) : (num ++);
+ parser_addglobal(parser, var->name, (ast_expression*)var);
+
+ if (!parser_next(parser)) {
+ parseerror(parser, "expected `=`, `}` or comma after identifier");
+ goto onerror;
+ }
+
+ if (parser->tok == ',')
+ continue;
+ if (parser->tok == '}')
+ break;
+ if (parser->tok != '=') {
+ parseerror(parser, "expected `=`, `}` or comma after identifier");
+ goto onerror;
+ }
+
+ if (!parser_next(parser)) {
+ parseerror(parser, "expected expression after `=`");
+ goto onerror;