2001-09-28 07:09:38 +00:00
|
|
|
|
/*
|
2002-11-06 16:32:28 +00:00
|
|
|
|
qc-lex.l
|
2001-09-28 07:09:38 +00:00
|
|
|
|
|
2002-11-06 16:32:28 +00:00
|
|
|
|
lexer for quakec
|
2001-09-28 07:09:38 +00:00
|
|
|
|
|
2002-11-06 16:32:28 +00:00
|
|
|
|
Copyright (C) 2001 Bill Currie <bill@taniwha.org>
|
2001-09-28 07:09:38 +00:00
|
|
|
|
|
2002-11-06 16:32:28 +00:00
|
|
|
|
Author: Bill Currie <bill@taniwha.org>
|
|
|
|
|
Date: 2001/06/12
|
2001-09-28 07:09:38 +00:00
|
|
|
|
|
|
|
|
|
This program is free software; you can redistribute it and/or
|
|
|
|
|
modify it under the terms of the GNU General Public License
|
|
|
|
|
as published by the Free Software Foundation; either version 2
|
|
|
|
|
of the License, or (at your option) any later version.
|
|
|
|
|
|
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
|
|
|
|
|
|
|
|
See the GNU General Public License for more details.
|
|
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
|
along with this program; if not, write to:
|
|
|
|
|
|
|
|
|
|
Free Software Foundation, Inc.
|
|
|
|
|
59 Temple Place - Suite 330
|
|
|
|
|
Boston, MA 02111-1307, USA
|
|
|
|
|
|
|
|
|
|
*/
|
2023-10-08 01:57:57 +00:00
|
|
|
|
%option bison-locations
|
2023-10-10 17:34:39 +00:00
|
|
|
|
%option bison-bridge
|
|
|
|
|
%option reentrant
|
2023-10-08 01:57:57 +00:00
|
|
|
|
%option prefix="qc_yy"
|
|
|
|
|
%option noyywrap
|
|
|
|
|
%option debug
|
2023-10-21 01:12:41 +00:00
|
|
|
|
%option stack
|
2023-10-08 01:57:57 +00:00
|
|
|
|
|
2023-10-20 11:31:15 +00:00
|
|
|
|
%top{
|
2002-06-01 04:41:25 +00:00
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
|
# include "config.h"
|
|
|
|
|
#endif
|
2003-01-14 20:18:29 +00:00
|
|
|
|
|
2002-06-01 04:41:25 +00:00
|
|
|
|
#ifdef HAVE_STRING_H
|
|
|
|
|
# include <string.h>
|
|
|
|
|
#endif
|
|
|
|
|
#ifdef HAVE_STRINGS_H
|
|
|
|
|
# include <strings.h>
|
|
|
|
|
#endif
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <ctype.h>
|
|
|
|
|
|
2002-06-27 22:48:28 +00:00
|
|
|
|
#include <QF/dstring.h>
|
2001-06-13 07:16:39 +00:00
|
|
|
|
#include <QF/hash.h>
|
2001-10-24 22:50:06 +00:00
|
|
|
|
#include <QF/sys.h>
|
2002-06-27 22:48:28 +00:00
|
|
|
|
|
2020-06-21 14:15:17 +00:00
|
|
|
|
#include "tools/qfcc/include/class.h"
|
|
|
|
|
#include "tools/qfcc/include/debug.h"
|
|
|
|
|
#include "tools/qfcc/include/diagnostic.h"
|
|
|
|
|
#include "tools/qfcc/include/expr.h"
|
|
|
|
|
#include "tools/qfcc/include/grab.h"
|
|
|
|
|
#include "tools/qfcc/include/options.h"
|
|
|
|
|
#include "tools/qfcc/include/pragma.h"
|
|
|
|
|
#include "tools/qfcc/include/qfcc.h"
|
2023-10-20 11:31:15 +00:00
|
|
|
|
#include "tools/qfcc/include/rua-lang.h"
|
2020-06-21 14:15:17 +00:00
|
|
|
|
#include "tools/qfcc/include/shared.h"
|
|
|
|
|
#include "tools/qfcc/include/strpool.h"
|
|
|
|
|
#include "tools/qfcc/include/struct.h"
|
|
|
|
|
#include "tools/qfcc/include/symtab.h"
|
|
|
|
|
#include "tools/qfcc/include/type.h"
|
|
|
|
|
#include "tools/qfcc/include/value.h"
|
2023-10-20 11:31:15 +00:00
|
|
|
|
}
|
2020-06-21 14:15:17 +00:00
|
|
|
|
|
2023-10-20 11:31:15 +00:00
|
|
|
|
%{
|
2003-04-16 19:41:52 +00:00
|
|
|
|
#ifndef YY_PROTO
|
|
|
|
|
# define YY_PROTO(x) x
|
|
|
|
|
#else
|
|
|
|
|
# define YY_FLEX_REALLOC_HACK
|
|
|
|
|
#endif
|
|
|
|
|
|
2023-10-19 14:05:47 +00:00
|
|
|
|
#define YY_NO_INPUT // debian flex
|
|
|
|
|
#define YY_NO_UNPUT // debian flex
|
|
|
|
|
#define YY_NO_YYINPUT
|
|
|
|
|
#define YY_NO_YYUNPUT
|
2023-10-08 01:57:57 +00:00
|
|
|
|
|
2023-10-20 11:31:15 +00:00
|
|
|
|
#define YYSTYPE rua_tok_t
|
|
|
|
|
#define YYLTYPE rua_loc_t
|
2001-06-12 21:06:28 +00:00
|
|
|
|
|
2023-10-20 11:31:15 +00:00
|
|
|
|
typedef struct rua_extra_s {
|
|
|
|
|
int start_state;
|
|
|
|
|
} rua_extra_t;
|
|
|
|
|
#define YY_EXTRA_TYPE rua_extra_t *
|
|
|
|
|
|
|
|
|
|
rua_extra_t *qc_yyget_extra (yyscan_t yyscanner) __attribute__((pure));
|
2023-10-10 17:34:39 +00:00
|
|
|
|
int yyget_lineno (yyscan_t yyscanner) __attribute__((pure));
|
|
|
|
|
int yyget_column (yyscan_t yyscanner) __attribute__((pure));
|
|
|
|
|
YYSTYPE *yyget_lval (yyscan_t yyscanner) __attribute__((pure));
|
|
|
|
|
YYLTYPE *yyget_lloc (yyscan_t yyscanner) __attribute__((pure));
|
|
|
|
|
int yyget_leng (yyscan_t yyscanner) __attribute__((pure));
|
|
|
|
|
char *yyget_text (yyscan_t yyscanner) __attribute__((pure));
|
|
|
|
|
int yyget_debug (yyscan_t yyscanner) __attribute__((pure));
|
|
|
|
|
FILE *yyget_in (yyscan_t yyscanner) __attribute__((pure));
|
|
|
|
|
FILE *yyget_out (yyscan_t yyscanner) __attribute__((pure));
|
|
|
|
|
|
|
|
|
|
static int keyword_or_id (YYSTYPE *lval, const char *token);
|
2023-10-20 11:31:15 +00:00
|
|
|
|
static void user_action (rua_tok_t *tok, rua_loc_t *loc,
|
|
|
|
|
const char *text, size_t textlen);
|
2001-06-25 22:11:20 +00:00
|
|
|
|
|
2023-10-20 12:15:17 +00:00
|
|
|
|
enum {
|
|
|
|
|
rua_eof = 1,
|
|
|
|
|
rua_error,
|
|
|
|
|
rua_number,
|
|
|
|
|
rua_vector,
|
2023-10-20 16:13:32 +00:00
|
|
|
|
rua_string,
|
|
|
|
|
rua_char,
|
2023-10-20 12:15:17 +00:00
|
|
|
|
};
|
|
|
|
|
|
2023-10-20 11:31:15 +00:00
|
|
|
|
#define YY_USER_ACTION user_action (yylval, yylloc, yytext, yyleng);
|
2001-06-13 07:16:39 +00:00
|
|
|
|
|
2001-06-12 21:06:28 +00:00
|
|
|
|
%}
|
|
|
|
|
|
2011-01-14 03:10:28 +00:00
|
|
|
|
s [ \t]
|
|
|
|
|
m [\-+]
|
|
|
|
|
D [0-9]
|
2023-10-20 12:15:17 +00:00
|
|
|
|
IDs [a-zA-Z_]
|
|
|
|
|
IDc [a-zA-Z_0-9]
|
|
|
|
|
ID {IDs}{IDc}*
|
[qfcc] Extend vector literal processing
With this, all vector widths and types are supported: 2, 3, 4 and int,
uint, long, ulong, float and double, along with support for suffixes to
make the type explicit: '1 2'd specifies a dvec2 constant, while '1 2 3'u
is a uivec3 constant. Default types are double (dvec2, dvec3, dvec4) for
literals with float-type components, and int (ivec2...) for those with
integer-type components.
2022-04-29 02:49:45 +00:00
|
|
|
|
FD [fFdD]
|
|
|
|
|
UL ([uU]?([lL][lL]?)?)
|
|
|
|
|
ULFD ({UL}|{FD})
|
2011-01-14 03:10:28 +00:00
|
|
|
|
RANGE \.\.
|
|
|
|
|
ELLIPSIS \.\.\.
|
|
|
|
|
FRAMEID {ID}(\.{ID})*
|
2012-11-22 11:42:00 +00:00
|
|
|
|
PRAGMAID {ID}(-{ID})*
|
2023-10-20 16:13:32 +00:00
|
|
|
|
s_string \"(\\.|[^"\\])*\"
|
|
|
|
|
c_string '(\\.|[^'\\])*'
|
2001-06-12 21:06:28 +00:00
|
|
|
|
|
2023-10-20 12:15:17 +00:00
|
|
|
|
pp_number \.?{D}({IDc}|'{IDc}|[eEpP]{m}|\.)*
|
2023-10-20 16:17:11 +00:00
|
|
|
|
pp_vnumber '({s}*{m}?{pp_number}){2,4}{s}*'{ULFD}?
|
2023-10-20 12:15:17 +00:00
|
|
|
|
|
2023-10-07 16:50:06 +00:00
|
|
|
|
%x GRAB_FRAME GRAB_OTHER GRAB_WRITE COMMENT LCOMMENT PRAGMA
|
2023-10-20 12:15:17 +00:00
|
|
|
|
%x VECTOR
|
2001-06-13 18:35:41 +00:00
|
|
|
|
|
2001-06-12 21:06:28 +00:00
|
|
|
|
%%
|
2023-10-20 16:17:11 +00:00
|
|
|
|
yyset_debug (0, yyscanner);
|
|
|
|
|
grab_frame = GRAB_FRAME;
|
|
|
|
|
grab_other = GRAB_OTHER;
|
|
|
|
|
grab_write = GRAB_WRITE;
|
|
|
|
|
yylval->pointer = 0; // ensure pointer vals are null
|
|
|
|
|
|
2023-10-21 01:12:41 +00:00
|
|
|
|
"/*" { yy_push_state (COMMENT, yyscanner); }
|
2023-10-20 16:17:11 +00:00
|
|
|
|
<COMMENT>"/*" { warning (0, "nested /* in comment"); }
|
2023-10-21 01:12:41 +00:00
|
|
|
|
<COMMENT>"*/" { yy_pop_state (yyscanner); }
|
2023-10-20 16:17:11 +00:00
|
|
|
|
<COMMENT>\r*\n { pr.source_line++; }
|
|
|
|
|
<COMMENT>. /* nothing to do */
|
|
|
|
|
<COMMENT><<EOF>> { error (0, "EOF in comment"); return 0; }
|
2023-10-21 01:12:41 +00:00
|
|
|
|
"//" { yy_push_state (LCOMMENT, yyscanner); } /* exited by <*>\r\n rule */
|
2023-10-07 16:50:06 +00:00
|
|
|
|
<LCOMMENT>[^\\\r\n]* /* consume all but \ and EOL (see line continuation) */
|
2023-10-20 16:17:11 +00:00
|
|
|
|
<LCOMMENT>[\\]* /* consume \ */
|
2001-06-13 07:16:39 +00:00
|
|
|
|
|
2011-01-14 03:10:28 +00:00
|
|
|
|
^#{s}+{D}+{s}+\"(\.|[^"\n])*\".*$ { line_info (yytext + 1); }
|
|
|
|
|
^#line{s}+{D}+{s}+\"(\.|[^"\n])*\".*$ { line_info (yytext + 5); }
|
2007-04-06 05:52:20 +00:00
|
|
|
|
|
2023-10-21 01:12:41 +00:00
|
|
|
|
^{s}*#{s}*pragma{s}+ { yy_push_state (PRAGMA, yyscanner); }
|
2007-04-06 05:52:20 +00:00
|
|
|
|
|
2023-10-20 16:17:11 +00:00
|
|
|
|
{ID} { return keyword_or_id(yylval, yytext); }
|
|
|
|
|
@{ID} { return keyword_or_id(yylval, yytext); }
|
|
|
|
|
@ { return '@'; }
|
|
|
|
|
|
|
|
|
|
{pp_number} { return -rua_number; }
|
|
|
|
|
{pp_vnumber} { return -rua_vector; }
|
2023-10-20 12:15:17 +00:00
|
|
|
|
<VECTOR>{pp_number} { return -rua_number; }
|
|
|
|
|
<VECTOR>{m} { return yytext[0]; }
|
|
|
|
|
<VECTOR>' { return -rua_eof; }
|
2002-01-04 08:45:24 +00:00
|
|
|
|
|
2023-10-20 16:13:32 +00:00
|
|
|
|
{s_string} { return -rua_string; };
|
|
|
|
|
{c_string} { return -rua_char; }
|
2023-10-20 16:17:11 +00:00
|
|
|
|
|
|
|
|
|
[+\-*/&|^%]= { yylval->value.op = yytext[0]; return ASX; }
|
|
|
|
|
|
|
|
|
|
"%%=" { yylval->value.op = MOD; return ASX; }
|
|
|
|
|
"<<=" { yylval->value.op = SHL; return ASX; }
|
|
|
|
|
">>=" { yylval->value.op = SHR; return ASX; }
|
|
|
|
|
|
|
|
|
|
[!(){}.*/&|^~+\-=\[\];,#%?:] { return yytext[0]; }
|
|
|
|
|
|
|
|
|
|
"·" { return DOT; }
|
|
|
|
|
"â‹€" { return WEDGE; }
|
|
|
|
|
"•" { return DOT; }
|
|
|
|
|
"∧" { return WEDGE; }
|
|
|
|
|
"∨" { return REGRESSIVE; }
|
|
|
|
|
"†" { return REVERSE; }
|
|
|
|
|
"∗" { return STAR; }
|
|
|
|
|
"×" { return CROSS; }
|
|
|
|
|
"⋆" { return DUAL; }
|
|
|
|
|
|
|
|
|
|
"%%" { return MOD; }
|
|
|
|
|
|
|
|
|
|
{ELLIPSIS} { return ELLIPSIS; }
|
|
|
|
|
|
|
|
|
|
"<<" { return SHL; }
|
|
|
|
|
">>" { return SHR; }
|
|
|
|
|
|
|
|
|
|
"&&" { return AND; }
|
|
|
|
|
"||" { return OR; }
|
|
|
|
|
"==" { return EQ; }
|
|
|
|
|
"!=" { return NE; }
|
|
|
|
|
"<=" { return LE; }
|
|
|
|
|
">=" { return GE; }
|
|
|
|
|
"<" { return LT; }
|
|
|
|
|
">" { return GT; }
|
|
|
|
|
|
|
|
|
|
"++" { yylval->value.op = '+'; return INCOP; }
|
|
|
|
|
"--" { yylval->value.op = '-'; return INCOP; }
|
|
|
|
|
|
|
|
|
|
"$"{s}*{FRAMEID} {
|
|
|
|
|
int ret = do_grab (yytext);
|
|
|
|
|
if (ret >= 0) {
|
|
|
|
|
yylval->value.expr = new_int_expr (ret, false);
|
|
|
|
|
return VALUE;
|
|
|
|
|
} else {
|
2023-10-21 01:12:41 +00:00
|
|
|
|
yy_push_state (-ret, yyscanner);
|
2023-10-20 16:17:11 +00:00
|
|
|
|
}
|
2011-01-06 07:30:25 +00:00
|
|
|
|
}
|
2001-06-12 21:06:28 +00:00
|
|
|
|
|
2023-10-20 16:17:11 +00:00
|
|
|
|
<GRAB_FRAME>{FRAMEID} { add_frame_macro (yytext); }
|
2011-01-06 07:30:25 +00:00
|
|
|
|
<GRAB_OTHER>[^\r\n]* /* skip */
|
2023-10-20 16:13:32 +00:00
|
|
|
|
<GRAB_WRITE>{s_string} {
|
2012-11-21 11:50:45 +00:00
|
|
|
|
const char *s = make_string (yytext, 0);
|
|
|
|
|
write_frame_macros (s);
|
|
|
|
|
BEGIN (GRAB_OTHER); // ignore rest of line
|
|
|
|
|
}
|
2023-08-26 14:47:00 +00:00
|
|
|
|
<PRAGMA>{PRAGMAID} { pragma_add_arg (yytext); }
|
|
|
|
|
<PRAGMA>@{PRAGMAID} { pragma_add_arg (yytext); }
|
2001-06-13 18:35:41 +00:00
|
|
|
|
|
2023-10-20 16:17:11 +00:00
|
|
|
|
<*>\\\r*\n { pr.source_line++; } /* line continuation */
|
|
|
|
|
<*>\r*\n {
|
|
|
|
|
if (YY_START == PRAGMA) {
|
|
|
|
|
pragma_process ();
|
|
|
|
|
}
|
|
|
|
|
pr.source_line++;
|
2023-10-21 01:12:41 +00:00
|
|
|
|
if (yyg->yy_start_stack_ptr) {
|
|
|
|
|
yy_pop_state (yyscanner);
|
|
|
|
|
}
|
2020-02-15 10:41:20 +00:00
|
|
|
|
}
|
2001-06-12 21:06:28 +00:00
|
|
|
|
|
2023-10-20 16:17:11 +00:00
|
|
|
|
<*>{s}* /* skip */
|
2001-06-13 07:16:39 +00:00
|
|
|
|
|
2023-10-20 16:17:11 +00:00
|
|
|
|
<*>. error (0, "all your typo are belong to us");
|
2001-06-12 21:06:28 +00:00
|
|
|
|
|
|
|
|
|
%%
|
|
|
|
|
|
2001-06-13 07:16:39 +00:00
|
|
|
|
typedef struct {
|
2011-01-17 13:33:33 +00:00
|
|
|
|
const char *name;
|
|
|
|
|
int value;
|
2023-02-04 09:26:54 +00:00
|
|
|
|
specifier_t spec;
|
2001-06-13 07:16:39 +00:00
|
|
|
|
} keyword_t;
|
|
|
|
|
|
2022-02-03 15:25:31 +00:00
|
|
|
|
// These keywords are part of the Ruamoko language and require the QuakeForge
|
|
|
|
|
// Ruamoko VM.
|
|
|
|
|
static keyword_t rua_keywords[] = {
|
2023-02-04 09:26:54 +00:00
|
|
|
|
#define VEC_TYPE(type_name, base_type) \
|
|
|
|
|
{ #type_name, TYPE_SPEC, .spec = { .type = &type_##type_name } },
|
2022-02-03 15:25:31 +00:00
|
|
|
|
#include "tools/qfcc/include/vec_types.h"
|
|
|
|
|
};
|
|
|
|
|
|
2012-12-22 07:31:14 +00:00
|
|
|
|
// These keywords are all part of the Ruamoko (Objective-QC) language.
|
|
|
|
|
// The first time any one of them is encountered, the class system will be
|
|
|
|
|
// initialized.
|
|
|
|
|
// If not compiling for the QuakeForge VM, or if Ruamoko has been disabled,
|
|
|
|
|
// then they will be unavailable as keywords.
|
|
|
|
|
static keyword_t obj_keywords[] = {
|
2023-02-08 02:18:42 +00:00
|
|
|
|
{"id", OBJECT_NAME, .spec = { .type = &type_id } },
|
2023-02-04 09:26:54 +00:00
|
|
|
|
{"Class", TYPE_SPEC, .spec = { .type = &type_Class } },
|
|
|
|
|
{"Method", TYPE_SPEC, .spec = { .type = &type_method } },
|
|
|
|
|
{"Super", TYPE_SPEC, .spec = { .type = &type_super } },
|
|
|
|
|
{"SEL", TYPE_SPEC, .spec = { .type = &type_SEL } },
|
|
|
|
|
{"IMP", TYPE_SPEC, .spec = { .type = &type_IMP } },
|
2012-12-22 07:31:14 +00:00
|
|
|
|
|
|
|
|
|
{"@class", CLASS },
|
|
|
|
|
{"@defs", DEFS },
|
|
|
|
|
{"@encode", ENCODE },
|
|
|
|
|
{"@end", END },
|
|
|
|
|
{"@implementation", IMPLEMENTATION },
|
|
|
|
|
{"@interface", INTERFACE },
|
|
|
|
|
{"@private", PRIVATE },
|
|
|
|
|
{"@protected", PROTECTED },
|
|
|
|
|
{"@protocol", PROTOCOL },
|
|
|
|
|
{"@public", PUBLIC },
|
|
|
|
|
{"@reference", REFERENCE },
|
|
|
|
|
{"@selector", SELECTOR },
|
|
|
|
|
{"@self", SELF },
|
|
|
|
|
{"@this", THIS },
|
|
|
|
|
|
|
|
|
|
// This is a hack to trigger the initialization of the class
|
|
|
|
|
// sytem if it is seen before any other Objective-QC symbol. Otherwise,
|
|
|
|
|
// it is just an identifier, though it does reference a built-in type
|
|
|
|
|
// created by the class system.
|
|
|
|
|
{"obj_module", 0 },
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// These keywords are extensions to QC and thus available only in advanced
|
|
|
|
|
// or extended code. However, if they are preceeded by an @ (eg, @for), then
|
|
|
|
|
// they are always available. This is to prevent them from causing trouble
|
|
|
|
|
// for traditional code that might use these words as identifiers, but still
|
|
|
|
|
// make the language features available to traditional code.
|
|
|
|
|
static keyword_t at_keywords[] = {
|
|
|
|
|
{"for", FOR },
|
2020-03-11 03:53:40 +00:00
|
|
|
|
{"goto", GOTO },
|
2012-12-22 07:31:14 +00:00
|
|
|
|
{"break", BREAK },
|
|
|
|
|
{"continue", CONTINUE},
|
|
|
|
|
{"switch", SWITCH },
|
|
|
|
|
{"case", CASE },
|
|
|
|
|
{"default", DEFAULT },
|
|
|
|
|
{"nil", NIL },
|
|
|
|
|
{"struct", STRUCT },
|
|
|
|
|
{"union", STRUCT },
|
|
|
|
|
{"enum", ENUM },
|
|
|
|
|
{"typedef", TYPEDEF },
|
|
|
|
|
{"extern", EXTERN },
|
|
|
|
|
{"static", STATIC },
|
|
|
|
|
{"sizeof", SIZEOF },
|
2012-12-20 01:02:00 +00:00
|
|
|
|
{"not", NOT },
|
2023-08-18 07:05:54 +00:00
|
|
|
|
{"auto", TYPE_SPEC, .spec = { .type = &type_auto } },
|
2012-12-22 07:31:14 +00:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// These keywords require the QuakeForge VM to be of any use. ie, they cannot
|
|
|
|
|
// be supported (sanely) by v6 progs.
|
|
|
|
|
static keyword_t qf_keywords[] = {
|
2023-02-04 09:26:54 +00:00
|
|
|
|
{"quaternion", TYPE_SPEC, .spec = { .type = &type_quaternion } },
|
|
|
|
|
{"double", TYPE_SPEC, .spec = { .type = &type_double } },
|
|
|
|
|
{"int", TYPE_SPEC, .spec = { .type = &type_int } },
|
|
|
|
|
{"unsigned", TYPE_SPEC, .spec = { .is_unsigned = 1 } },
|
|
|
|
|
{"signed", TYPE_SPEC, .spec = { .is_signed = 1 } },
|
|
|
|
|
{"long", TYPE_SPEC, .spec = { .is_long = 1 } },
|
|
|
|
|
{"short", TYPE_SPEC, .spec = { .is_short = 1 } },
|
|
|
|
|
|
|
|
|
|
{"@function", TYPE_SPEC, .spec = { .type = &type_func } },
|
|
|
|
|
{"@args", ARGS, },
|
|
|
|
|
{"@va_list", TYPE_SPEC, .spec = { .type = &type_va_list } },
|
|
|
|
|
{"@param", TYPE_SPEC, .spec = { .type = &type_param } },
|
|
|
|
|
{"@return", AT_RETURN, },
|
|
|
|
|
|
2023-08-17 07:22:49 +00:00
|
|
|
|
{"@hadamard", HADAMARD, },
|
2023-02-04 09:26:54 +00:00
|
|
|
|
{"@cross", CROSS, },
|
|
|
|
|
{"@dot", DOT, },
|
2023-08-17 07:22:49 +00:00
|
|
|
|
{"@wedge", WEDGE, },
|
2023-08-30 08:32:02 +00:00
|
|
|
|
{"@regressive", REGRESSIVE, },
|
2023-08-17 07:22:49 +00:00
|
|
|
|
{"@geometric", GEOMETRIC, },
|
2023-08-21 08:37:56 +00:00
|
|
|
|
{"@algebra", ALGEBRA, },
|
2012-12-22 07:31:14 +00:00
|
|
|
|
};
|
|
|
|
|
|
2022-02-02 14:51:37 +00:00
|
|
|
|
// These keywors are always available. Other than the @ keywords, they
|
2012-12-22 07:31:14 +00:00
|
|
|
|
// form traditional QuakeC.
|
2001-06-13 07:16:39 +00:00
|
|
|
|
static keyword_t keywords[] = {
|
2023-02-04 09:26:54 +00:00
|
|
|
|
{"void", TYPE_SPEC, .spec = { .type = &type_void } },
|
|
|
|
|
{"float", TYPE_SPEC, .spec = { .type = &type_float } },
|
|
|
|
|
{"string", TYPE_SPEC, .spec = { .type = &type_string } },
|
|
|
|
|
{"vector", TYPE_SPEC, .spec = { .type = &type_vector } },
|
|
|
|
|
{"entity", TYPE_SPEC, .spec = { .type = &type_entity } },
|
|
|
|
|
{"local", LOCAL, },
|
|
|
|
|
{"return", RETURN, },
|
|
|
|
|
{"while", WHILE, },
|
|
|
|
|
{"do", DO, },
|
|
|
|
|
{"if", IF, },
|
|
|
|
|
{"else", ELSE, },
|
|
|
|
|
{"@system", SYSTEM, },
|
|
|
|
|
{"@overload", OVERLOAD, },
|
|
|
|
|
{"@attribute", ATTRIBUTE, },
|
[qfcc] Add a handle type for engine resources
I never liked the various hacks I had come up with for representing
resource handles in Ruamoko. Structs with an int were awkward to test,
pointers and ints could be modified, etc etc. The new @handle keyword (@
used to keep handle free for use) works just like struct, union and
enum in syntax, but creates an opaque type suitable for a 32-bit handle.
The backing type is a function so v6 progs can use it without (all the
necessary opcodes exist) and no modifications were needed for
type-checking in binary expressions, but only assignment and comparisons
are supported, and (of course) nil. Tested using cbuf_t and QFile: seems
to work as desired.
I had considered 64-bit handles, but really, if more than 4G resource
objects are needed, I'm not sure QF can handle the game. However, that
limit is per resource manager, not total.
2023-05-25 01:41:28 +00:00
|
|
|
|
{"@handle", HANDLE, },
|
2001-06-13 07:16:39 +00:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static const char *
|
2012-07-18 13:34:37 +00:00
|
|
|
|
keyword_get_key (const void *kw, void *unused)
|
2001-06-13 07:16:39 +00:00
|
|
|
|
{
|
|
|
|
|
return ((keyword_t*)kw)->name;
|
|
|
|
|
}
|
|
|
|
|
|
2012-12-22 07:31:14 +00:00
|
|
|
|
static int
|
2023-10-10 17:34:39 +00:00
|
|
|
|
process_keyword (YYSTYPE *lval, keyword_t *keyword, const char *token)
|
2012-12-22 07:31:14 +00:00
|
|
|
|
{
|
|
|
|
|
if (keyword->value == STRUCT) {
|
2023-10-20 11:31:15 +00:00
|
|
|
|
lval->value.op = token[0];
|
2023-02-08 02:18:42 +00:00
|
|
|
|
} else if (keyword->value == OBJECT_NAME) {
|
2012-12-22 07:31:14 +00:00
|
|
|
|
symbol_t *sym;
|
|
|
|
|
|
|
|
|
|
sym = symtab_lookup (current_symtab, token);
|
2023-10-20 11:31:15 +00:00
|
|
|
|
lval->value.symbol = sym;
|
2022-01-19 12:32:01 +00:00
|
|
|
|
// the global id symbol is always just a name so attempts to redefine
|
|
|
|
|
// it globally can be caught and treated as an error, but it needs to
|
|
|
|
|
// be redefinable when in an enclosing scope.
|
|
|
|
|
if (sym->sy_type == sy_name) {
|
|
|
|
|
// this is the global id (object)
|
2023-10-20 11:31:15 +00:00
|
|
|
|
lval->value.spec = (specifier_t) {
|
2023-02-08 02:18:42 +00:00
|
|
|
|
.type = sym->type,
|
|
|
|
|
.sym = sym,
|
|
|
|
|
};
|
|
|
|
|
return OBJECT_NAME;
|
2022-01-19 12:32:01 +00:00
|
|
|
|
} else if (sym->sy_type == sy_type) {
|
|
|
|
|
// id has been redeclared via a typedef
|
2023-10-20 11:31:15 +00:00
|
|
|
|
lval->value.spec = (specifier_t) {
|
2023-02-04 09:26:54 +00:00
|
|
|
|
.type = sym->type,
|
|
|
|
|
.sym = sym,
|
|
|
|
|
};
|
2022-01-19 12:32:01 +00:00
|
|
|
|
return TYPE_NAME;
|
|
|
|
|
}
|
|
|
|
|
// id has been redelcared as a variable (hopefully)
|
|
|
|
|
return NAME;
|
2012-12-22 07:31:14 +00:00
|
|
|
|
} else {
|
2023-10-20 11:31:15 +00:00
|
|
|
|
lval->value.spec = keyword->spec;
|
2012-12-22 07:31:14 +00:00
|
|
|
|
}
|
|
|
|
|
return keyword->value;
|
|
|
|
|
}
|
|
|
|
|
|
2011-01-06 07:30:25 +00:00
|
|
|
|
static int
|
2023-10-10 17:34:39 +00:00
|
|
|
|
keyword_or_id (YYSTYPE *lval, const char *token)
|
2001-06-13 07:16:39 +00:00
|
|
|
|
{
|
|
|
|
|
static hashtab_t *keyword_tab;
|
2012-12-22 07:31:14 +00:00
|
|
|
|
static hashtab_t *qf_keyword_tab;
|
|
|
|
|
static hashtab_t *at_keyword_tab;
|
|
|
|
|
static hashtab_t *obj_keyword_tab;
|
2022-02-03 15:25:31 +00:00
|
|
|
|
static hashtab_t *rua_keyword_tab;
|
2012-12-22 07:31:14 +00:00
|
|
|
|
|
|
|
|
|
keyword_t *keyword = 0;
|
2011-01-17 13:33:33 +00:00
|
|
|
|
symbol_t *sym;
|
2001-06-13 07:16:39 +00:00
|
|
|
|
|
2001-12-08 08:19:48 +00:00
|
|
|
|
if (!keyword_tab) {
|
2007-04-06 05:52:20 +00:00
|
|
|
|
size_t i;
|
2012-12-22 07:31:14 +00:00
|
|
|
|
|
2020-03-25 06:43:16 +00:00
|
|
|
|
keyword_tab = Hash_NewTable (253, keyword_get_key, 0, 0, 0);
|
|
|
|
|
qf_keyword_tab = Hash_NewTable (253, keyword_get_key, 0, 0, 0);
|
|
|
|
|
at_keyword_tab = Hash_NewTable (253, keyword_get_key, 0, 0, 0);
|
|
|
|
|
obj_keyword_tab = Hash_NewTable (253, keyword_get_key, 0, 0, 0);
|
2022-02-03 15:25:31 +00:00
|
|
|
|
rua_keyword_tab = Hash_NewTable (253, keyword_get_key, 0, 0, 0);
|
2012-12-22 07:31:14 +00:00
|
|
|
|
|
|
|
|
|
#define NUMKEYS(_k) (sizeof (_k) / sizeof (_k[0]))
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < NUMKEYS(keywords); i++)
|
|
|
|
|
Hash_Add (keyword_tab, &keywords[i]);
|
|
|
|
|
for (i = 0; i < NUMKEYS(qf_keywords); i++)
|
|
|
|
|
Hash_Add (qf_keyword_tab, &qf_keywords[i]);
|
|
|
|
|
for (i = 0; i < NUMKEYS(at_keywords); i++)
|
|
|
|
|
Hash_Add (at_keyword_tab, &at_keywords[i]);
|
|
|
|
|
for (i = 0; i < NUMKEYS(obj_keywords); i++)
|
|
|
|
|
Hash_Add (obj_keyword_tab, &obj_keywords[i]);
|
2022-02-03 15:25:31 +00:00
|
|
|
|
for (i = 0; i < NUMKEYS(rua_keywords); i++)
|
|
|
|
|
Hash_Add (rua_keyword_tab, &rua_keywords[i]);
|
2001-06-13 07:16:39 +00:00
|
|
|
|
}
|
2012-12-22 07:31:14 +00:00
|
|
|
|
if (options.traditional < 1) {
|
2022-02-03 15:25:31 +00:00
|
|
|
|
if (options.code.progsversion == PROG_VERSION) {
|
|
|
|
|
keyword = Hash_Find (rua_keyword_tab, token);
|
|
|
|
|
}
|
|
|
|
|
if (!keyword) {
|
|
|
|
|
keyword = Hash_Find (obj_keyword_tab, token);
|
|
|
|
|
if (keyword) {
|
|
|
|
|
if (!obj_initialized)
|
|
|
|
|
class_init ();
|
|
|
|
|
}
|
2011-01-17 13:33:33 +00:00
|
|
|
|
}
|
2012-12-22 07:31:14 +00:00
|
|
|
|
if (!keyword)
|
|
|
|
|
keyword = Hash_Find (qf_keyword_tab, token);
|
|
|
|
|
}
|
|
|
|
|
if (!keyword && options.traditional < 2)
|
|
|
|
|
keyword = Hash_Find (at_keyword_tab, token);
|
|
|
|
|
if (!keyword && token[0] == '@') {
|
|
|
|
|
keyword = Hash_Find (at_keyword_tab, token + 1);
|
|
|
|
|
if (keyword)
|
|
|
|
|
token += 1;
|
2001-06-13 07:16:39 +00:00
|
|
|
|
}
|
2012-12-22 07:31:14 +00:00
|
|
|
|
if (!keyword)
|
|
|
|
|
keyword = Hash_Find (keyword_tab, token);
|
|
|
|
|
if (keyword && keyword->value)
|
2023-10-10 17:34:39 +00:00
|
|
|
|
return process_keyword (lval, keyword, token);
|
2002-05-07 16:55:54 +00:00
|
|
|
|
if (token[0] == '@') {
|
|
|
|
|
return '@';
|
|
|
|
|
}
|
2011-01-17 13:33:33 +00:00
|
|
|
|
sym = symtab_lookup (current_symtab, token);
|
|
|
|
|
if (!sym)
|
|
|
|
|
sym = new_symbol (token);
|
2023-10-20 11:31:15 +00:00
|
|
|
|
lval->value.symbol = sym;
|
2023-02-04 09:26:54 +00:00
|
|
|
|
if (sym->sy_type == sy_type) {
|
2023-10-20 11:31:15 +00:00
|
|
|
|
lval->value.spec = (specifier_t) {
|
2023-02-04 09:26:54 +00:00
|
|
|
|
.type = sym->type,
|
|
|
|
|
.sym = sym,
|
|
|
|
|
};
|
2004-11-02 07:02:00 +00:00
|
|
|
|
return TYPE_NAME;
|
2023-02-04 09:26:54 +00:00
|
|
|
|
}
|
2011-02-13 07:05:09 +00:00
|
|
|
|
if (sym->sy_type == sy_class)
|
2011-01-17 13:33:33 +00:00
|
|
|
|
return CLASS_NAME;
|
2001-06-13 07:16:39 +00:00
|
|
|
|
return NAME;
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-20 12:15:17 +00:00
|
|
|
|
enum {
|
|
|
|
|
suff_error = -1,
|
|
|
|
|
suff_implicit,
|
|
|
|
|
suff_unsigned,
|
|
|
|
|
suff_long,
|
|
|
|
|
suff_unsigned_long,
|
|
|
|
|
suff_float,
|
|
|
|
|
suff_double,
|
|
|
|
|
suff_long_double,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
parse_suffix (const char *suffix, bool fp)
|
[qfcc] Extend vector literal processing
With this, all vector widths and types are supported: 2, 3, 4 and int,
uint, long, ulong, float and double, along with support for suffixes to
make the type explicit: '1 2'd specifies a dvec2 constant, while '1 2 3'u
is a uivec3 constant. Default types are double (dvec2, dvec3, dvec4) for
literals with float-type components, and int (ivec2...) for those with
integer-type components.
2022-04-29 02:49:45 +00:00
|
|
|
|
{
|
2023-10-20 12:15:17 +00:00
|
|
|
|
int expl = suff_implicit;
|
|
|
|
|
bool unsign = false;
|
[qfcc] Extend vector literal processing
With this, all vector widths and types are supported: 2, 3, 4 and int,
uint, long, ulong, float and double, along with support for suffixes to
make the type explicit: '1 2'd specifies a dvec2 constant, while '1 2 3'u
is a uivec3 constant. Default types are double (dvec2, dvec3, dvec4) for
literals with float-type components, and int (ivec2...) for those with
integer-type components.
2022-04-29 02:49:45 +00:00
|
|
|
|
|
2023-10-20 12:15:17 +00:00
|
|
|
|
if (!*suffix) {
|
|
|
|
|
return 0;
|
[qfcc] Extend vector literal processing
With this, all vector widths and types are supported: 2, 3, 4 and int,
uint, long, ulong, float and double, along with support for suffixes to
make the type explicit: '1 2'd specifies a dvec2 constant, while '1 2 3'u
is a uivec3 constant. Default types are double (dvec2, dvec3, dvec4) for
literals with float-type components, and int (ivec2...) for those with
integer-type components.
2022-04-29 02:49:45 +00:00
|
|
|
|
}
|
2023-10-20 12:15:17 +00:00
|
|
|
|
if (fp) {
|
|
|
|
|
if (*suffix == 'f' || *suffix == 'F') {
|
|
|
|
|
expl = suff_float;
|
|
|
|
|
suffix++;
|
|
|
|
|
} else if (*suffix == 'd' || *suffix == 'D') {
|
|
|
|
|
// treat as explicit double unless it's a proper C decimal
|
|
|
|
|
// suffix, in which case the decimal part will be ignored
|
|
|
|
|
// (non-standard, but no decimal supprt)
|
|
|
|
|
expl = suff_double;
|
|
|
|
|
suffix++;
|
|
|
|
|
if (*suffix == 'f' || *suffix == 'F'
|
|
|
|
|
|| *suffix == 'd' || *suffix == 'D'
|
|
|
|
|
|| *suffix == 'l' || *suffix == 'L') {
|
|
|
|
|
warning (0, "decimal fp treated as binary fp");
|
|
|
|
|
expl = suff_double;
|
|
|
|
|
suffix++;
|
|
|
|
|
}
|
|
|
|
|
} else if (*suffix == 'l' || *suffix == 'L') {
|
|
|
|
|
expl = suff_long_double;
|
|
|
|
|
suffix++;
|
2022-11-12 11:04:19 +00:00
|
|
|
|
}
|
2023-10-20 12:15:17 +00:00
|
|
|
|
} else {
|
|
|
|
|
if (*suffix == 'f' || *suffix == 'F') {
|
|
|
|
|
expl = suff_float;
|
|
|
|
|
suffix++;
|
|
|
|
|
} else if (*suffix == 'd' || *suffix == 'D') {
|
|
|
|
|
expl = suff_double;
|
|
|
|
|
suffix++;
|
|
|
|
|
} else {
|
|
|
|
|
if (*suffix == 'u' || *suffix == 'U') {
|
|
|
|
|
unsign = true;
|
|
|
|
|
expl = suff_unsigned;
|
|
|
|
|
suffix++;
|
[qfcc] Extend vector literal processing
With this, all vector widths and types are supported: 2, 3, 4 and int,
uint, long, ulong, float and double, along with support for suffixes to
make the type explicit: '1 2'd specifies a dvec2 constant, while '1 2 3'u
is a uivec3 constant. Default types are double (dvec2, dvec3, dvec4) for
literals with float-type components, and int (ivec2...) for those with
integer-type components.
2022-04-29 02:49:45 +00:00
|
|
|
|
}
|
2023-10-20 12:15:17 +00:00
|
|
|
|
if (*suffix == 'l' || *suffix == 'L') {
|
|
|
|
|
expl = unsign ? suff_unsigned_long : suff_long;
|
|
|
|
|
suffix++;
|
|
|
|
|
if (*suffix == 'l' || *suffix == 'L') {
|
|
|
|
|
suffix++;
|
[qfcc] Extend vector literal processing
With this, all vector widths and types are supported: 2, 3, 4 and int,
uint, long, ulong, float and double, along with support for suffixes to
make the type explicit: '1 2'd specifies a dvec2 constant, while '1 2 3'u
is a uivec3 constant. Default types are double (dvec2, dvec3, dvec4) for
literals with float-type components, and int (ivec2...) for those with
integer-type components.
2022-04-29 02:49:45 +00:00
|
|
|
|
}
|
2023-10-20 12:15:17 +00:00
|
|
|
|
if (!unsign && (*suffix == 'u' || *suffix == 'U')) {
|
|
|
|
|
expl = suff_unsigned_long;
|
|
|
|
|
suffix++;
|
[qfcc] Extend vector literal processing
With this, all vector widths and types are supported: 2, 3, 4 and int,
uint, long, ulong, float and double, along with support for suffixes to
make the type explicit: '1 2'd specifies a dvec2 constant, while '1 2 3'u
is a uivec3 constant. Default types are double (dvec2, dvec3, dvec4) for
literals with float-type components, and int (ivec2...) for those with
integer-type components.
2022-04-29 02:49:45 +00:00
|
|
|
|
}
|
2023-10-20 12:15:17 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (*suffix) {
|
|
|
|
|
return suff_error;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return expl;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
parse_number (rua_tok_t *tok, yyscan_t scanner)
|
|
|
|
|
{
|
|
|
|
|
bool binary = false;
|
|
|
|
|
const char *type = "integer";
|
|
|
|
|
bool hex = false;
|
|
|
|
|
bool fp = false;
|
|
|
|
|
char buf[tok->textlen + 1], *dst = buf;
|
|
|
|
|
const char *src = tok->text;
|
|
|
|
|
if ((*dst = *src++) == '0') {
|
|
|
|
|
switch ((*++dst = *src++)) {
|
|
|
|
|
case 'b': case 'B':
|
|
|
|
|
binary = true;
|
|
|
|
|
type = "binary";
|
|
|
|
|
break;
|
|
|
|
|
case 'x': case 'X':
|
|
|
|
|
hex = true;
|
|
|
|
|
type = "hexadecimal";
|
|
|
|
|
break;
|
|
|
|
|
case '.':
|
|
|
|
|
fp = true;
|
|
|
|
|
break;
|
|
|
|
|
case '1' ... '9':
|
|
|
|
|
type = "octal"; // unless fp becomes true
|
|
|
|
|
break;
|
|
|
|
|
case '\'': case '_':
|
|
|
|
|
if (*src == 'b' || *src == 'B' || *src == 'x' || *src == 'X') {
|
|
|
|
|
error (0, "digit separator outside digit sequence");
|
|
|
|
|
return -rua_error;
|
[qfcc] Extend vector literal processing
With this, all vector widths and types are supported: 2, 3, 4 and int,
uint, long, ulong, float and double, along with support for suffixes to
make the type explicit: '1 2'd specifies a dvec2 constant, while '1 2 3'u
is a uivec3 constant. Default types are double (dvec2, dvec3, dvec4) for
literals with float-type components, and int (ivec2...) for those with
integer-type components.
2022-04-29 02:49:45 +00:00
|
|
|
|
}
|
2023-10-20 12:15:17 +00:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (*dst) {
|
|
|
|
|
dst += (*dst != '\'' && *dst != '_');
|
|
|
|
|
while ((*dst = *src++)) {
|
|
|
|
|
if (hex && (*dst == 'p' || *dst == 'P')) {
|
|
|
|
|
fp = true;
|
|
|
|
|
}
|
|
|
|
|
if (!hex && (*dst == 'e' || *dst == 'E')) {
|
|
|
|
|
fp = true;
|
|
|
|
|
}
|
|
|
|
|
if (*dst == '.') {
|
|
|
|
|
fp = true;
|
|
|
|
|
}
|
|
|
|
|
// strip out digit separators (' is standard C, _ is a rust
|
|
|
|
|
// thing, but it does look a bit nicerer than ', so why not).
|
|
|
|
|
dst += (*dst != '\'' && *dst != '_');
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// use long long to avoid bit-size issues on windows
|
|
|
|
|
long long lvalue = 0;
|
|
|
|
|
double fvalue = 0;
|
|
|
|
|
char *endptr = 0;
|
|
|
|
|
if (binary) {
|
|
|
|
|
// to get here, 0b (or 0B) was seen, so buf is guaranted to start with
|
|
|
|
|
// that
|
|
|
|
|
lvalue = strtoll (buf + 2, &endptr, 2);
|
|
|
|
|
} else {
|
|
|
|
|
if (fp) {
|
|
|
|
|
fvalue = strtod (buf, &endptr);
|
|
|
|
|
} else {
|
|
|
|
|
lvalue = strtoll (buf, &endptr, 0);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int expl = parse_suffix (endptr, fp);
|
|
|
|
|
if (expl < 0) {
|
|
|
|
|
error (0, "invalid suffix \"%s\" on %s constant", endptr,
|
|
|
|
|
fp ? "floating" : type);
|
|
|
|
|
return -rua_error;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (fp) {
|
|
|
|
|
if (expl == suff_float) {
|
|
|
|
|
tok->value.expr = new_float_expr (fvalue);
|
|
|
|
|
} else {
|
|
|
|
|
if (expl == suff_long_double) {
|
|
|
|
|
warning (0, "long double treated as double");
|
|
|
|
|
expl = suff_double;
|
|
|
|
|
}
|
|
|
|
|
tok->value.expr = new_double_expr (fvalue, expl == suff_implicit);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
if (expl == suff_unsigned) {
|
|
|
|
|
tok->value.expr = new_uint_expr (lvalue);
|
|
|
|
|
} else if (expl == suff_long || expl == suff_implicit) {
|
|
|
|
|
tok->value.expr = new_long_expr (lvalue, expl == suff_implicit);
|
|
|
|
|
} else if (expl == suff_unsigned_long) {
|
|
|
|
|
tok->value.expr = new_ulong_expr (lvalue);
|
|
|
|
|
} else if (expl == suff_float) {
|
|
|
|
|
tok->value.expr = new_float_expr (lvalue);
|
|
|
|
|
} else if (expl == suff_double) {
|
|
|
|
|
tok->value.expr = new_double_expr (lvalue, false);
|
|
|
|
|
} else {
|
|
|
|
|
internal_error (0, "invalid suffix enum: %d", expl);
|
|
|
|
|
}
|
[qfcc] Extend vector literal processing
With this, all vector widths and types are supported: 2, 3, 4 and int,
uint, long, ulong, float and double, along with support for suffixes to
make the type explicit: '1 2'd specifies a dvec2 constant, while '1 2 3'u
is a uivec3 constant. Default types are double (dvec2, dvec3, dvec4) for
literals with float-type components, and int (ivec2...) for those with
integer-type components.
2022-04-29 02:49:45 +00:00
|
|
|
|
}
|
2023-10-20 12:15:17 +00:00
|
|
|
|
return VALUE;
|
[qfcc] Extend vector literal processing
With this, all vector widths and types are supported: 2, 3, 4 and int,
uint, long, ulong, float and double, along with support for suffixes to
make the type explicit: '1 2'd specifies a dvec2 constant, while '1 2 3'u
is a uivec3 constant. Default types are double (dvec2, dvec3, dvec4) for
literals with float-type components, and int (ivec2...) for those with
integer-type components.
2022-04-29 02:49:45 +00:00
|
|
|
|
}
|
|
|
|
|
|
2023-10-20 12:15:17 +00:00
|
|
|
|
typedef struct {
|
|
|
|
|
yyscan_t scanner;
|
|
|
|
|
yybuffer buffer;
|
|
|
|
|
} buffer_raii_t;
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
qc_restore_buffer (buffer_raii_t *raii)
|
[qfcc] Extend vector literal processing
With this, all vector widths and types are supported: 2, 3, 4 and int,
uint, long, ulong, float and double, along with support for suffixes to
make the type explicit: '1 2'd specifies a dvec2 constant, while '1 2 3'u
is a uivec3 constant. Default types are double (dvec2, dvec3, dvec4) for
literals with float-type components, and int (ivec2...) for those with
integer-type components.
2022-04-29 02:49:45 +00:00
|
|
|
|
{
|
2023-10-20 12:15:17 +00:00
|
|
|
|
yy_switch_to_buffer (raii->buffer, raii->scanner);
|
|
|
|
|
}
|
[qfcc] Extend vector literal processing
With this, all vector widths and types are supported: 2, 3, 4 and int,
uint, long, ulong, float and double, along with support for suffixes to
make the type explicit: '1 2'd specifies a dvec2 constant, while '1 2 3'u
is a uivec3 constant. Default types are double (dvec2, dvec3, dvec4) for
literals with float-type components, and int (ivec2...) for those with
integer-type components.
2022-04-29 02:49:45 +00:00
|
|
|
|
|
2023-10-20 12:15:17 +00:00
|
|
|
|
static void
|
|
|
|
|
qc_delete_buffer (buffer_raii_t *raii)
|
|
|
|
|
{
|
|
|
|
|
yy_delete_buffer (raii->buffer, raii->scanner);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
parse_vector (rua_tok_t *tok, yyscan_t scanner)
|
|
|
|
|
{
|
|
|
|
|
const char *end = tok->text + tok->textlen;
|
|
|
|
|
while (end > tok->text && *--end != '\'') continue;
|
|
|
|
|
|
|
|
|
|
const char *start = tok->text + 1;
|
|
|
|
|
auto yyg = (struct yyguts_t *)scanner;
|
|
|
|
|
auto __attribute__((cleanup (qc_restore_buffer)))
|
|
|
|
|
saved_buffer = (buffer_raii_t) {
|
|
|
|
|
.scanner = scanner,
|
|
|
|
|
.buffer = YY_CURRENT_BUFFER,
|
|
|
|
|
};
|
|
|
|
|
auto __attribute__((cleanup (qc_delete_buffer)))
|
|
|
|
|
buffer = (buffer_raii_t) {
|
|
|
|
|
.scanner = scanner,
|
|
|
|
|
.buffer = yy_scan_bytes (start, end - start, scanner),
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
int token;
|
|
|
|
|
rua_tok_t vtok = { .location = tok->location, };
|
|
|
|
|
vtok.location.first_column++;
|
|
|
|
|
const expr_t *components[4+1] = {}; // currently, max of 4
|
|
|
|
|
bool negate[4] = {};
|
|
|
|
|
int width = 0;
|
|
|
|
|
|
2023-10-21 01:12:41 +00:00
|
|
|
|
yy_push_state (VECTOR, scanner);
|
2023-10-20 12:15:17 +00:00
|
|
|
|
do {
|
|
|
|
|
token = yylex (&vtok, &vtok.location, scanner);
|
|
|
|
|
if (-token == rua_number) {
|
|
|
|
|
token = parse_number (&vtok, scanner);
|
|
|
|
|
}
|
|
|
|
|
if (token == VALUE) {
|
|
|
|
|
if (width < 4) {
|
|
|
|
|
components[width] = vtok.value.expr;
|
|
|
|
|
}
|
|
|
|
|
width++;
|
|
|
|
|
} else if (token == '-') {
|
|
|
|
|
if (width < 4) {
|
|
|
|
|
negate[width] = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} while (token && token != -rua_eof);
|
2023-10-21 01:12:41 +00:00
|
|
|
|
yy_pop_state (scanner);
|
2023-10-20 12:15:17 +00:00
|
|
|
|
|
|
|
|
|
if (width > 4) {
|
|
|
|
|
error (0, "too many components in vector literal");
|
|
|
|
|
width = 4;
|
|
|
|
|
return -rua_error;
|
[qfcc] Extend vector literal processing
With this, all vector widths and types are supported: 2, 3, 4 and int,
uint, long, ulong, float and double, along with support for suffixes to
make the type explicit: '1 2'd specifies a dvec2 constant, while '1 2 3'u
is a uivec3 constant. Default types are double (dvec2, dvec3, dvec4) for
literals with float-type components, and int (ivec2...) for those with
integer-type components.
2022-04-29 02:49:45 +00:00
|
|
|
|
}
|
2023-10-20 12:15:17 +00:00
|
|
|
|
bool fp = false;
|
|
|
|
|
for (int i = 0; i < width; i++) {
|
|
|
|
|
if (!components[i]->implicit) {
|
|
|
|
|
error (0, "explict numeric constant in vector literal."
|
|
|
|
|
" Suggest suffix after closing '.");
|
|
|
|
|
return -rua_error;
|
2022-11-12 11:04:19 +00:00
|
|
|
|
}
|
2023-10-20 12:15:17 +00:00
|
|
|
|
fp |= is_double (get_type (components[i]));
|
2022-11-12 11:04:19 +00:00
|
|
|
|
}
|
2023-10-20 12:15:17 +00:00
|
|
|
|
|
|
|
|
|
// end points at the final ' and thus any suffix is after that
|
|
|
|
|
int expl = parse_suffix (++end, fp);
|
|
|
|
|
if (expl < 0) {
|
|
|
|
|
error (0, "invalid suffix \"%s\" on %s vector constant", end,
|
|
|
|
|
fp ? "floating" : "integer");
|
|
|
|
|
return -rua_error;
|
|
|
|
|
}
|
|
|
|
|
union {
|
|
|
|
|
pr_float_t f[4];
|
|
|
|
|
pr_int_t i[4];
|
|
|
|
|
pr_double_t d[4];
|
|
|
|
|
pr_long_t l[4];
|
|
|
|
|
pr_type_t t[PR_SIZEOF (lvec4)];
|
|
|
|
|
} data;
|
|
|
|
|
type_t *type = 0;
|
|
|
|
|
if (expl == suff_long_double) {
|
|
|
|
|
warning (0, "long double treated as double");
|
|
|
|
|
expl = suff_double;
|
|
|
|
|
}
|
|
|
|
|
if (expl == suff_float) {
|
|
|
|
|
for (int i = 0; i < width; i++) {
|
|
|
|
|
auto c = components[i];
|
|
|
|
|
if (is_double (get_type (c))) {
|
|
|
|
|
data.f[i] = expr_double (c);
|
|
|
|
|
} else {
|
|
|
|
|
data.f[i] = expr_long (c);
|
[qfcc] Extend vector literal processing
With this, all vector widths and types are supported: 2, 3, 4 and int,
uint, long, ulong, float and double, along with support for suffixes to
make the type explicit: '1 2'd specifies a dvec2 constant, while '1 2 3'u
is a uivec3 constant. Default types are double (dvec2, dvec3, dvec4) for
literals with float-type components, and int (ivec2...) for those with
integer-type components.
2022-04-29 02:49:45 +00:00
|
|
|
|
}
|
2023-10-20 12:15:17 +00:00
|
|
|
|
if (negate[i]) {
|
|
|
|
|
data.f[i] = -data.f[i];
|
|
|
|
|
}
|
|
|
|
|
}
|
[qfcc] Extend vector literal processing
With this, all vector widths and types are supported: 2, 3, 4 and int,
uint, long, ulong, float and double, along with support for suffixes to
make the type explicit: '1 2'd specifies a dvec2 constant, while '1 2 3'u
is a uivec3 constant. Default types are double (dvec2, dvec3, dvec4) for
literals with float-type components, and int (ivec2...) for those with
integer-type components.
2022-04-29 02:49:45 +00:00
|
|
|
|
type = &type_float;
|
2023-10-20 12:15:17 +00:00
|
|
|
|
} else if (expl == suff_double) {
|
|
|
|
|
for (int i = 0; i < width; i++) {
|
|
|
|
|
auto c = components[i];
|
|
|
|
|
if (is_double (get_type (c))) {
|
|
|
|
|
data.d[i] = expr_double (c);
|
|
|
|
|
} else {
|
|
|
|
|
data.d[i] = expr_long (c);
|
|
|
|
|
}
|
|
|
|
|
if (negate[i]) {
|
|
|
|
|
data.d[i] = -data.d[i];
|
|
|
|
|
}
|
|
|
|
|
}
|
[qfcc] Extend vector literal processing
With this, all vector widths and types are supported: 2, 3, 4 and int,
uint, long, ulong, float and double, along with support for suffixes to
make the type explicit: '1 2'd specifies a dvec2 constant, while '1 2 3'u
is a uivec3 constant. Default types are double (dvec2, dvec3, dvec4) for
literals with float-type components, and int (ivec2...) for those with
integer-type components.
2022-04-29 02:49:45 +00:00
|
|
|
|
type = &type_double;
|
2023-10-20 12:15:17 +00:00
|
|
|
|
} else if (expl == suff_implicit) {
|
|
|
|
|
if (fp) {
|
|
|
|
|
for (int i = 0; i < width; i++) {
|
|
|
|
|
auto c = components[i];
|
|
|
|
|
if (is_double (get_type (c))) {
|
|
|
|
|
data.f[i] = expr_double (c);
|
|
|
|
|
} else {
|
|
|
|
|
data.f[i] = expr_long (c);
|
|
|
|
|
}
|
|
|
|
|
if (negate[i]) {
|
|
|
|
|
data.f[i] = -data.f[i];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
type = &type_float;
|
|
|
|
|
} else {
|
|
|
|
|
for (int i = 0; i < width; i++) {
|
|
|
|
|
auto c = components[i];
|
|
|
|
|
data.i[i] = expr_long (c);
|
|
|
|
|
if (negate[i]) {
|
|
|
|
|
data.i[i] = -data.i[i];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
type = &type_int;
|
|
|
|
|
}
|
|
|
|
|
} else if (expl == suff_unsigned) {
|
|
|
|
|
for (int i = 0; i < width; i++) {
|
|
|
|
|
auto c = components[i];
|
|
|
|
|
data.i[i] = fp ? expr_double (c) : expr_long (c);
|
|
|
|
|
if (negate[i]) {
|
|
|
|
|
data.i[i] = -data.i[i];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
type = &type_uint;
|
|
|
|
|
} else if (expl == suff_long || expl == suff_unsigned_long) {
|
|
|
|
|
for (int i = 0; i < width; i++) {
|
|
|
|
|
auto c = components[i];
|
|
|
|
|
data.l[i] = expr_long (c);
|
|
|
|
|
if (negate[i]) {
|
|
|
|
|
data.l[i] = -data.l[i];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
type = expl == suff_unsigned_long ? &type_ulong : &type_long;
|
[qfcc] Extend vector literal processing
With this, all vector widths and types are supported: 2, 3, 4 and int,
uint, long, ulong, float and double, along with support for suffixes to
make the type explicit: '1 2'd specifies a dvec2 constant, while '1 2 3'u
is a uivec3 constant. Default types are double (dvec2, dvec3, dvec4) for
literals with float-type components, and int (ivec2...) for those with
integer-type components.
2022-04-29 02:49:45 +00:00
|
|
|
|
}
|
|
|
|
|
type = vector_type (type, width);
|
2023-10-20 12:15:17 +00:00
|
|
|
|
tok->value.expr = new_value_expr (new_type_value (type, data.t),
|
|
|
|
|
expl == suff_implicit);
|
|
|
|
|
|
|
|
|
|
return VALUE;
|
[qfcc] Extend vector literal processing
With this, all vector widths and types are supported: 2, 3, 4 and int,
uint, long, ulong, float and double, along with support for suffixes to
make the type explicit: '1 2'd specifies a dvec2 constant, while '1 2 3'u
is a uivec3 constant. Default types are double (dvec2, dvec3, dvec4) for
literals with float-type components, and int (ivec2...) for those with
integer-type components.
2022-04-29 02:49:45 +00:00
|
|
|
|
}
|
2023-10-10 17:34:39 +00:00
|
|
|
|
|
2023-10-20 16:13:32 +00:00
|
|
|
|
static int
|
|
|
|
|
parse_string (rua_tok_t *tok, int type, yyscan_t scanner)
|
|
|
|
|
{
|
|
|
|
|
const char *str = make_string (tok->text, 0);
|
|
|
|
|
if (type == rua_char) {
|
|
|
|
|
if (str[1]) {
|
|
|
|
|
warning (0, "multibyte char constant");
|
|
|
|
|
}
|
|
|
|
|
tok->value.expr = new_int_expr (*str, false);
|
|
|
|
|
return VALUE;
|
|
|
|
|
} else {
|
|
|
|
|
tok->value.expr = new_string_expr (str);
|
|
|
|
|
return STRING;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-20 11:31:15 +00:00
|
|
|
|
static void
|
|
|
|
|
user_action (rua_tok_t *tok, rua_loc_t *loc, const char *text, size_t textlen)
|
|
|
|
|
{
|
|
|
|
|
if (textlen < sizeof (tok->text)) {
|
|
|
|
|
strncpy (tok->str_text, text, textlen);
|
|
|
|
|
tok->str_text[textlen] = 0;
|
|
|
|
|
tok->text = tok->str_text;
|
|
|
|
|
} else {
|
|
|
|
|
tok->text = save_string (text);
|
|
|
|
|
}
|
|
|
|
|
tok->textlen = textlen;
|
|
|
|
|
loc->first_line = loc->last_line;
|
|
|
|
|
loc->first_column = loc->last_column;
|
|
|
|
|
for(int i = 0; text[i] != '\0'; i++) {
|
|
|
|
|
if(text[i] == '\n') {
|
|
|
|
|
loc->last_line++;
|
|
|
|
|
loc->last_column = 1;
|
|
|
|
|
} else {
|
|
|
|
|
loc->last_column++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-20 12:15:17 +00:00
|
|
|
|
static int
|
|
|
|
|
qc_process (qc_yypstate *ps, int token, rua_tok_t *tok, yyscan_t scanner)
|
|
|
|
|
{
|
|
|
|
|
auto value = &tok->value;
|
|
|
|
|
auto loc = &tok->location;
|
|
|
|
|
|
|
|
|
|
switch (-token) {
|
|
|
|
|
case rua_number:
|
|
|
|
|
token = parse_number (tok, scanner);
|
|
|
|
|
if (token == VALUE && value->expr->implicit) {
|
|
|
|
|
if (is_long (get_type (value->expr))) {
|
|
|
|
|
pr_long_t v = expr_long (value->expr);
|
|
|
|
|
if (v < INT32_MIN || v > INT32_MAX) {
|
|
|
|
|
warning (0, "integer value truncated");
|
|
|
|
|
}
|
|
|
|
|
value->expr = new_int_expr (v, true);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case rua_vector:
|
|
|
|
|
token = parse_vector (tok, scanner);
|
|
|
|
|
break;
|
2023-10-20 16:13:32 +00:00
|
|
|
|
case rua_string:
|
|
|
|
|
case rua_char:
|
|
|
|
|
token = parse_string (tok, -token, scanner);
|
|
|
|
|
break;
|
2023-10-20 12:15:17 +00:00
|
|
|
|
}
|
|
|
|
|
if (token >= 0) {
|
|
|
|
|
return qc_yypush_parse (ps, token, value, loc, scanner);
|
|
|
|
|
}
|
|
|
|
|
return YYPUSH_MORE;
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-10 17:34:39 +00:00
|
|
|
|
int
|
|
|
|
|
qc_yyparse (FILE *in)
|
|
|
|
|
{
|
|
|
|
|
int status;
|
|
|
|
|
yyscan_t scanner;
|
|
|
|
|
qc_yypstate *ps = qc_yypstate_new ();
|
2023-10-20 11:31:15 +00:00
|
|
|
|
rua_tok_t tok = { .location = { 1, 1, 1, 1, pr.source_file }, };
|
|
|
|
|
rua_extra_t extra = {};
|
2023-10-10 17:34:39 +00:00
|
|
|
|
|
2023-10-20 11:31:15 +00:00
|
|
|
|
yylex_init_extra (&extra, &scanner);
|
2023-10-10 17:34:39 +00:00
|
|
|
|
yyset_in (in, scanner);
|
|
|
|
|
do {
|
2023-10-20 11:31:15 +00:00
|
|
|
|
int token = yylex (&tok, &tok.location, scanner);
|
2023-10-20 12:15:17 +00:00
|
|
|
|
status = qc_process (ps, token, &tok, scanner);
|
2023-10-10 17:34:39 +00:00
|
|
|
|
} while (status == YYPUSH_MORE);
|
|
|
|
|
|
|
|
|
|
yylex_destroy (scanner);
|
|
|
|
|
qc_yypstate_delete (ps);
|
|
|
|
|
return status;
|
2023-10-21 01:12:41 +00:00
|
|
|
|
(void) yy_top_state; // FIXME silence unused warning
|
2023-10-10 17:34:39 +00:00
|
|
|
|
}
|