mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2025-02-25 13:11:00 +00:00
[qfcc] Improve language selection
Using a struct with function pointers instead of switching on an enum makes it much easier to add languages and, more importantly, sub-languages like glsl's shader stage variants.
This commit is contained in:
parent
bbb90ce27a
commit
4be1384701
6 changed files with 88 additions and 55 deletions
|
@ -117,9 +117,6 @@ extern pr_info_t pr;
|
||||||
|
|
||||||
const char *file_basename (const char *filename, int keepdot) __attribute__((pure));
|
const char *file_basename (const char *filename, int keepdot) __attribute__((pure));
|
||||||
|
|
||||||
int glsl_yyparse (FILE *in);
|
|
||||||
int qc_yyparse (FILE *in);
|
|
||||||
int qp_yyparse (FILE *in);
|
|
||||||
extern int pre_yydebug;
|
extern int pre_yydebug;
|
||||||
extern int glsl_yydebug;
|
extern int glsl_yydebug;
|
||||||
extern int qc_yydebug;
|
extern int qc_yydebug;
|
||||||
|
|
|
@ -170,5 +170,19 @@ int rua_parse (FILE *in, rua_parser_t *parser);
|
||||||
const char *rua_directive_get_key (const void *dir, void *unused) __attribute__((pure));
|
const char *rua_directive_get_key (const void *dir, void *unused) __attribute__((pure));
|
||||||
const char *rua_keyword_get_key (const void *dir, void *unused) __attribute__((pure));
|
const char *rua_keyword_get_key (const void *dir, void *unused) __attribute__((pure));
|
||||||
|
|
||||||
|
typedef struct language_s {
|
||||||
|
void (*init) (void);
|
||||||
|
int (*parse) (FILE *in);
|
||||||
|
int (*finish) (const char *file);
|
||||||
|
} language_t;
|
||||||
|
|
||||||
|
extern language_t lang_ruamoko;
|
||||||
|
extern language_t lang_glsl_comp;
|
||||||
|
extern language_t lang_glsl_vert;
|
||||||
|
extern language_t lang_glsl_tesc;
|
||||||
|
extern language_t lang_glsl_tese;
|
||||||
|
extern language_t lang_glsl_geom;
|
||||||
|
extern language_t lang_glsl_frag;
|
||||||
|
extern language_t lang_pascal;
|
||||||
|
|
||||||
#endif//__rua_lang_h
|
#endif//__rua_lang_h
|
||||||
|
|
|
@ -1329,7 +1329,7 @@ glsl_keyword_or_id (rua_val_t *lval, const char *token)
|
||||||
return GLSL_IDENTIFIER;
|
return GLSL_IDENTIFIER;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
static int
|
||||||
glsl_yyparse (FILE *in)
|
glsl_yyparse (FILE *in)
|
||||||
{
|
{
|
||||||
rua_parser_t parser = {
|
rua_parser_t parser = {
|
||||||
|
@ -1342,3 +1342,27 @@ glsl_yyparse (FILE *in)
|
||||||
glsl_yypstate_delete (parser.state);
|
glsl_yypstate_delete (parser.state);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
language_t lang_glsl_comp = {
|
||||||
|
.parse = glsl_yyparse,
|
||||||
|
};
|
||||||
|
|
||||||
|
language_t lang_glsl_vert = {
|
||||||
|
.parse = glsl_yyparse,
|
||||||
|
};
|
||||||
|
|
||||||
|
language_t lang_glsl_tesc = {
|
||||||
|
.parse = glsl_yyparse,
|
||||||
|
};
|
||||||
|
|
||||||
|
language_t lang_glsl_tese = {
|
||||||
|
.parse = glsl_yyparse,
|
||||||
|
};
|
||||||
|
|
||||||
|
language_t lang_glsl_geom = {
|
||||||
|
.parse = glsl_yyparse,
|
||||||
|
};
|
||||||
|
|
||||||
|
language_t lang_glsl_frag = {
|
||||||
|
.parse = glsl_yyparse,
|
||||||
|
};
|
||||||
|
|
|
@ -66,6 +66,7 @@
|
||||||
#include "tools/qfcc/include/emit.h"
|
#include "tools/qfcc/include/emit.h"
|
||||||
#include "tools/qfcc/include/expr.h"
|
#include "tools/qfcc/include/expr.h"
|
||||||
#include "tools/qfcc/include/function.h"
|
#include "tools/qfcc/include/function.h"
|
||||||
|
#include "tools/qfcc/include/grab.h"
|
||||||
#include "tools/qfcc/include/method.h"
|
#include "tools/qfcc/include/method.h"
|
||||||
#include "tools/qfcc/include/options.h"
|
#include "tools/qfcc/include/options.h"
|
||||||
#include "tools/qfcc/include/qfcc.h"
|
#include "tools/qfcc/include/qfcc.h"
|
||||||
|
@ -2978,7 +2979,7 @@ qc_keyword_or_id (QC_YYSTYPE *lval, const char *token)
|
||||||
return QC_NAME;
|
return QC_NAME;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
static int
|
||||||
qc_yyparse (FILE *in)
|
qc_yyparse (FILE *in)
|
||||||
{
|
{
|
||||||
rua_parser_t parser = {
|
rua_parser_t parser = {
|
||||||
|
@ -2991,3 +2992,17 @@ qc_yyparse (FILE *in)
|
||||||
qc_yypstate_delete (parser.state);
|
qc_yypstate_delete (parser.state);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int qc_finish (const char *file)
|
||||||
|
{
|
||||||
|
if (options.frames_files) {
|
||||||
|
write_frame_macros (va (0, "%s.frame", file_basename (file, 0)));
|
||||||
|
}
|
||||||
|
class_finish_module ();
|
||||||
|
return pr.error_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
language_t lang_ruamoko = {
|
||||||
|
.parse = qc_yyparse,
|
||||||
|
.finish = qc_finish,
|
||||||
|
};
|
||||||
|
|
|
@ -96,16 +96,9 @@ const char *progs_src;
|
||||||
|
|
||||||
pr_info_t pr;
|
pr_info_t pr;
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
lang_object,
|
|
||||||
lang_ruamoko,
|
|
||||||
lang_pascal,
|
|
||||||
lang_glsl,
|
|
||||||
} lang_t;
|
|
||||||
|
|
||||||
typedef struct ext_lang_s {
|
typedef struct ext_lang_s {
|
||||||
const char *ext;
|
const char *ext;
|
||||||
lang_t lang;
|
language_t *lang;
|
||||||
} ext_lang_t;
|
} ext_lang_t;
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
|
@ -378,30 +371,15 @@ setup_sym_file (const char *output_file)
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
compile_to_obj (const char *file, const char *obj, lang_t lang)
|
compile_to_obj (const char *file, const char *obj, language_t *lang)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
FILE *yyin;
|
FILE *yyin;
|
||||||
int (*yyparse) (FILE *in);
|
|
||||||
|
|
||||||
switch (lang) {
|
|
||||||
case lang_ruamoko:
|
|
||||||
yyparse = qc_yyparse;
|
|
||||||
break;
|
|
||||||
case lang_pascal:
|
|
||||||
yyparse = qp_yyparse;
|
|
||||||
break;
|
|
||||||
case lang_glsl:
|
|
||||||
yyparse = glsl_yyparse;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
internal_error (0, "unknown language enum");
|
|
||||||
}
|
|
||||||
|
|
||||||
yyin = preprocess_file (file, 0);
|
yyin = preprocess_file (file, 0);
|
||||||
if (options.preprocess_only || !yyin) {
|
if (options.preprocess_only || !yyin) {
|
||||||
if (yyin) {
|
if (yyin) {
|
||||||
return yyparse (yyin);
|
return lang->parse (yyin);
|
||||||
}
|
}
|
||||||
return !options.preprocess_only;
|
return !options.preprocess_only;
|
||||||
}
|
}
|
||||||
|
@ -411,7 +389,10 @@ compile_to_obj (const char *file, const char *obj, lang_t lang)
|
||||||
begin_compilation ();
|
begin_compilation ();
|
||||||
pr.comp_dir = save_cwd ();
|
pr.comp_dir = save_cwd ();
|
||||||
add_source_file (file);
|
add_source_file (file);
|
||||||
err = yyparse (yyin) || pr.error_count;
|
if (lang->init) {
|
||||||
|
lang->init ();
|
||||||
|
}
|
||||||
|
err = lang->parse (yyin) || pr.error_count;
|
||||||
fclose (yyin);
|
fclose (yyin);
|
||||||
if (cpp_name && !options.save_temps) {
|
if (cpp_name && !options.save_temps) {
|
||||||
if (unlink (tempname->str)) {
|
if (unlink (tempname->str)) {
|
||||||
|
@ -419,14 +400,12 @@ compile_to_obj (const char *file, const char *obj, lang_t lang)
|
||||||
exit (1);
|
exit (1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (options.frames_files) {
|
|
||||||
write_frame_macros (va (0, "%s.frame", file_basename (file, 0)));
|
|
||||||
}
|
|
||||||
if (!err) {
|
if (!err) {
|
||||||
qfo_t *qfo;
|
qfo_t *qfo;
|
||||||
|
|
||||||
class_finish_module ();
|
if (lang->finish) {
|
||||||
err = pr.error_count;
|
err = lang->finish (file);
|
||||||
|
}
|
||||||
if (!err) {
|
if (!err) {
|
||||||
debug_finish_module (obj);
|
debug_finish_module (obj);
|
||||||
}
|
}
|
||||||
|
@ -507,28 +486,28 @@ finish_link (void)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static __attribute__((pure)) lang_t
|
static __attribute__((pure)) language_t *
|
||||||
file_language (const char *file, const char *ext)
|
file_language (const char *file, const char *ext)
|
||||||
{
|
{
|
||||||
static ext_lang_t ext_lang[] = {
|
static ext_lang_t ext_lang[] = {
|
||||||
{".r", lang_ruamoko},
|
{".r", &lang_ruamoko},
|
||||||
{".c", lang_ruamoko},
|
{".c", &lang_ruamoko},
|
||||||
{".m", lang_ruamoko},
|
{".m", &lang_ruamoko},
|
||||||
{".qc", lang_ruamoko},
|
{".qc", &lang_ruamoko},
|
||||||
{".comp", lang_glsl},
|
{".comp", &lang_glsl_comp},
|
||||||
{".vert", lang_glsl},
|
{".vert", &lang_glsl_vert},
|
||||||
{".tesc", lang_glsl},
|
{".tesc", &lang_glsl_tesc},
|
||||||
{".tese", lang_glsl},
|
{".tese", &lang_glsl_tese},
|
||||||
{".geom", lang_glsl},
|
{".geom", &lang_glsl_geom},
|
||||||
{".frag", lang_glsl},
|
{".frag", &lang_glsl_frag},
|
||||||
{".pas", lang_pascal},
|
{".pas", &lang_pascal},
|
||||||
{".p", lang_pascal},
|
{".p", &lang_pascal},
|
||||||
{0, lang_object}, // unrecognized extension = object file
|
{nullptr, nullptr}, // unrecognized extension = object file
|
||||||
};
|
};
|
||||||
ext_lang_t *el;
|
ext_lang_t *el;
|
||||||
|
|
||||||
if (strncmp (file, "-l", 2) == 0)
|
if (strncmp (file, "-l", 2) == 0)
|
||||||
return lang_object;
|
return nullptr;
|
||||||
for (el = ext_lang; el->ext; el++)
|
for (el = ext_lang; el->ext; el++)
|
||||||
if (strcmp (ext, el->ext) == 0)
|
if (strcmp (ext, el->ext) == 0)
|
||||||
break;
|
break;
|
||||||
|
@ -540,7 +519,6 @@ separate_compile (void)
|
||||||
{
|
{
|
||||||
const char **file, *ext;
|
const char **file, *ext;
|
||||||
const char **temp_files;
|
const char **temp_files;
|
||||||
lang_t lang;
|
|
||||||
dstring_t *output_file;
|
dstring_t *output_file;
|
||||||
dstring_t *extension;
|
dstring_t *extension;
|
||||||
int err = 0;
|
int err = 0;
|
||||||
|
@ -579,7 +557,8 @@ separate_compile (void)
|
||||||
dstring_appendstr (output_file, ".qfo");
|
dstring_appendstr (output_file, ".qfo");
|
||||||
}
|
}
|
||||||
// need *file for checking -lfoo
|
// need *file for checking -lfoo
|
||||||
if ((lang = file_language (*file, extension->str)) != lang_object) {
|
auto lang = file_language (*file, extension->str);
|
||||||
|
if (lang) {
|
||||||
if (options.verbosity >= 1)
|
if (options.verbosity >= 1)
|
||||||
printf ("%s %s\n", *file, output_file->str);
|
printf ("%s %s\n", *file, output_file->str);
|
||||||
temp_files[i++] = save_string (output_file->str);
|
temp_files[i++] = save_string (output_file->str);
|
||||||
|
@ -690,7 +669,7 @@ compile_file (const char *filename)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
FILE *yyin;
|
FILE *yyin;
|
||||||
int (*yyparse) (FILE *in) = qc_yyparse;
|
int (*yyparse) (FILE *in) = lang_ruamoko.parse;
|
||||||
|
|
||||||
yyin = preprocess_file (filename, 0);
|
yyin = preprocess_file (filename, 0);
|
||||||
if (options.preprocess_only || !yyin)
|
if (options.preprocess_only || !yyin)
|
||||||
|
|
|
@ -307,7 +307,7 @@ convert_relop (const char *relop)
|
||||||
internal_error (0, "bad relop %s", relop);
|
internal_error (0, "bad relop %s", relop);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
static int
|
||||||
qp_yyparse (FILE *in)
|
qp_yyparse (FILE *in)
|
||||||
{
|
{
|
||||||
int status;
|
int status;
|
||||||
|
@ -328,6 +328,10 @@ qp_yyparse (FILE *in)
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
language_t lang_pascal = {
|
||||||
|
.parse = qp_yyparse,
|
||||||
|
};
|
||||||
|
|
||||||
static void
|
static void
|
||||||
update_loc (rua_loc_t *loc, size_t textlen)
|
update_loc (rua_loc_t *loc, size_t textlen)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in a new issue