X-Git-Url: https://git.xonotic.org/?p=xonotic%2Fgmqcc.git;a=blobdiff_plain;f=lexer.h;h=e3ba96f1ff8f91ef2af20310720d2e42036d7878;hp=f23c1a631b89ad03594da89f4785e38b52f6004d;hb=53fd019780bc33c28c7d41aa046c4b74ed65b01f;hpb=9314157be58c7195bf8eacc762ba7ba83c7f50fc diff --git a/lexer.h b/lexer.h index f23c1a6..e3ba96f 100644 --- a/lexer.h +++ b/lexer.h @@ -1,5 +1,27 @@ -#ifndef GMQCC_LEXER_HDR_ -#define GMQCC_LEXER_HDR_ +/* + * Copyright (C) 2012 + * Wolfgang Bumiller + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#ifndef GMQCC_LEXER_HDR +#define GMQCC_LEXER_HDR typedef struct token_s token; @@ -8,7 +30,7 @@ typedef struct token_s token; struct token_s { int ttype; - MEM_VECTOR_MAKE(char, value); + char *value; union { vector v; @@ -17,17 +39,21 @@ struct token_s { int t; /* type */ } constval; +#if 0 struct token_s *next; struct token_s *prev; +#endif lex_ctx ctx; }; +#if 0 token* token_new(); void token_delete(token*); token* token_copy(const token *cp); void token_delete_all(token *t); token* token_copy_all(const token *cp); +#endif /* Lexer * @@ -45,12 +71,17 @@ enum { TOKEN_KEYWORD, /* loop */ + TOKEN_DOTS, /* 3 dots, ... */ + TOKEN_STRINGCONST, /* not the typename but an actual "string" */ TOKEN_CHARCONST, TOKEN_VECTORCONST, TOKEN_INTCONST, TOKEN_FLOATCONST, + TOKEN_WHITE, + TOKEN_EOL, + TOKEN_EOF, /* We use '< TOKEN_ERROR', so TOKEN_FATAL must come after it and any @@ -60,29 +91,17 @@ enum { TOKEN_FATAL /* internal error, eg out of memory */ }; -static const char *_tokennames[] = { - "TOKEN_START", - "TOKEN_IDENT", - "TOKEN_TYPENAME", - "TOKEN_OPERATOR", - "TOKEN_KEYWORD", - "TOKEN_STRINGCONST", - "TOKEN_CHARCONST", - "TOKEN_VECTORCONST", - "TOKEN_INTCONST", - "TOKEN_FLOATCONST", - "TOKEN_EOF", - "TOKEN_ERROR", - "TOKEN_FATAL", -}; -typedef int -_all_tokennames_added_[ - ((TOKEN_FATAL - TOKEN_START + 1) == - (sizeof(_tokennames)/sizeof(_tokennames[0]))) - ? 1 : -1]; +typedef struct { + char *name; + int value; +} frame_macro; typedef struct { FILE *file; + const char *open_string; + size_t open_string_length; + size_t open_string_pos; + char *name; size_t line; size_t sline; /* line at the start of a token */ @@ -90,18 +109,29 @@ typedef struct { char peek[256]; size_t peekpos; - token *tok; + bool eof; + + token tok; /* not a pointer anymore */ struct { bool noops; + bool nodigraphs; /* used when lexing string constants */ + bool preprocessing; /* whitespace and EOLs become actual tokens */ + bool mergelines; /* backslash at the end of a line escapes the newline */ } flags; -} lex_file; -MEM_VECTOR_PROTO(lex_file, char, token); + int framevalue; + frame_macro *frames; + char *modelname; + + size_t push_line; +} lex_file; lex_file* lex_open (const char *file); +lex_file* lex_open_string(const char *str, size_t len, const char *name); void lex_close(lex_file *lex); int lex_do (lex_file *lex); +void lex_cleanup(void); /* Parser * @@ -117,92 +147,177 @@ enum { typedef struct { const char *op; + unsigned int operands; unsigned int id; unsigned int assoc; - unsigned int prec; + signed int prec; unsigned int flags; } oper_info; -static const oper_info operators[] = { - { "++", 1, ASSOC_LEFT, 16, OP_SUFFIX}, - { "--", 2, ASSOC_LEFT, 16, OP_SUFFIX}, - - { ".", 10, ASSOC_LEFT, 15, 0 }, - - { "!", 21, ASSOC_RIGHT, 14, 0 }, - { "~", 22, ASSOC_RIGHT, 14, 0 }, - { "+", 23, ASSOC_RIGHT, 14, OP_PREFIX }, - { "-", 24, ASSOC_RIGHT, 14, OP_PREFIX }, - { "++", 25, ASSOC_RIGHT, 14, OP_PREFIX }, - { "--", 26, ASSOC_RIGHT, 14, OP_PREFIX }, -/* { "&", 27, ASSOC_RIGHT, 14, OP_PREFIX }, */ - - { "*", 30, ASSOC_LEFT, 13, 0 }, - { "/", 31, ASSOC_LEFT, 13, 0 }, - { "%", 32, ASSOC_LEFT, 13, 0 }, +#define opid1(a) (a) +#define opid2(a,b) ((a<<8)|b) +#define opid3(a,b,c) ((a<<16)|(b<<8)|c) - { "+", 40, ASSOC_LEFT, 12, 0 }, - { "-", 41, ASSOC_LEFT, 12, 0 }, +static const oper_info c_operators[] = { + { "(", 0, opid1('('), ASSOC_LEFT, 99, OP_PREFIX}, /* paren expression - non function call */ - { "<<", 50, ASSOC_LEFT, 11, 0 }, - { ">>", 51, ASSOC_LEFT, 11, 0 }, + { "++", 1, opid3('S','+','+'), ASSOC_LEFT, 15, OP_SUFFIX}, + { "--", 1, opid3('S','-','-'), ASSOC_LEFT, 15, OP_SUFFIX}, + { ".", 2, opid1('.'), ASSOC_LEFT, 15, 0 }, + { "(", 0, opid1('('), ASSOC_LEFT, 15, 0 }, /* function call */ + { "[", 2, opid1('['), ASSOC_LEFT, 15, 0 }, /* array subscript */ - { "<", 60, ASSOC_LEFT, 10, 0 }, - { ">", 61, ASSOC_LEFT, 10, 0 }, - { "<=", 62, ASSOC_LEFT, 10, 0 }, - { ">=", 63, ASSOC_LEFT, 10, 0 }, + { "!", 1, opid2('!', 'P'), ASSOC_RIGHT, 14, OP_PREFIX }, + { "~", 1, opid2('~', 'P'), ASSOC_RIGHT, 14, OP_PREFIX }, + { "+", 1, opid2('+','P'), ASSOC_RIGHT, 14, OP_PREFIX }, + { "-", 1, opid2('-','P'), ASSOC_RIGHT, 14, OP_PREFIX }, + { "++", 1, opid3('+','+','P'), ASSOC_RIGHT, 14, OP_PREFIX }, + { "--", 1, opid3('-','-','P'), ASSOC_RIGHT, 14, OP_PREFIX }, +/* { "&", 1, opid2('&','P'), ASSOC_RIGHT, 14, OP_PREFIX }, */ - { "==", 70, ASSOC_LEFT, 9, 0 }, - { "!=", 71, ASSOC_LEFT, 9, 0 }, + { "*", 2, opid1('*'), ASSOC_LEFT, 13, 0 }, + { "/", 2, opid1('/'), ASSOC_LEFT, 13, 0 }, + { "%", 2, opid1('%'), ASSOC_LEFT, 13, 0 }, - { "&", 80, ASSOC_LEFT, 8, 0 }, + { "+", 2, opid1('+'), ASSOC_LEFT, 12, 0 }, + { "-", 2, opid1('-'), ASSOC_LEFT, 12, 0 }, - { "^", 90, ASSOC_LEFT, 7, 0 }, + { "<<", 2, opid2('<','<'), ASSOC_LEFT, 11, 0 }, + { ">>", 2, opid2('>','>'), ASSOC_LEFT, 11, 0 }, - { "|", 100, ASSOC_LEFT, 6, 0 }, + { "<", 2, opid1('<'), ASSOC_LEFT, 10, 0 }, + { ">", 2, opid1('>'), ASSOC_LEFT, 10, 0 }, + { "<=", 2, opid2('<','='), ASSOC_LEFT, 10, 0 }, + { ">=", 2, opid2('>','='), ASSOC_LEFT, 10, 0 }, - { "&&", 110, ASSOC_LEFT, 5, 0 }, + { "==", 2, opid2('=','='), ASSOC_LEFT, 9, 0 }, + { "!=", 2, opid2('!','='), ASSOC_LEFT, 9, 0 }, - { "||", 120, ASSOC_LEFT, 4, 0 }, + { "&", 2, opid1('&'), ASSOC_LEFT, 8, 0 }, - { "?", 130, ASSOC_RIGHT, 3, 0 }, + { "^", 2, opid1('^'), ASSOC_LEFT, 7, 0 }, - { "=", 140, ASSOC_RIGHT, 2, 0 }, - { "+=", 141, ASSOC_RIGHT, 2, 0 }, - { "-=", 142, ASSOC_RIGHT, 2, 0 }, - { "*=", 143, ASSOC_RIGHT, 2, 0 }, - { "/=", 144, ASSOC_RIGHT, 2, 0 }, - { "%=", 145, ASSOC_RIGHT, 2, 0 }, - { ">>=", 146, ASSOC_RIGHT, 2, 0 }, - { "<<=", 147, ASSOC_RIGHT, 2, 0 }, - { "&=", 148, ASSOC_RIGHT, 2, 0 }, - { "^=", 149, ASSOC_RIGHT, 2, 0 }, - { "|=", 150, ASSOC_RIGHT, 2, 0 }, -}; - -typedef struct -{ - lex_file *lex; - int error; - lex_ctx ctx; - - token *tokens; - token *lastok; + { "|", 2, opid1('|'), ASSOC_LEFT, 6, 0 }, - token *tok; /* current token */ + { "&&", 2, opid2('&','&'), ASSOC_LEFT, 5, 0 }, - MEM_VECTOR_MAKE(ast_value*, globals); -} parse_file; + { "||", 2, opid2('|','|'), ASSOC_LEFT, 4, 0 }, -MEM_VECTOR_PROTO(parse_file, ast_value*, globals); + { "?", 3, opid2('?',':'), ASSOC_RIGHT, 3, 0 }, -parse_file* parse_open(const char *file); -void parse_file_close(parse_file*); + { "=", 2, opid1('='), ASSOC_RIGHT, 2, 0 }, + { "+=", 2, opid2('+','='), ASSOC_RIGHT, 2, 0 }, + { "-=", 2, opid2('-','='), ASSOC_RIGHT, 2, 0 }, + { "*=", 2, opid2('*','='), ASSOC_RIGHT, 2, 0 }, + { "/=", 2, opid2('/','='), ASSOC_RIGHT, 2, 0 }, + { "%=", 2, opid2('%','='), ASSOC_RIGHT, 2, 0 }, + { ">>=", 2, opid3('>','>','='), ASSOC_RIGHT, 2, 0 }, + { "<<=", 2, opid3('<','<','='), ASSOC_RIGHT, 2, 0 }, + { "&=", 2, opid2('&','='), ASSOC_RIGHT, 2, 0 }, + { "^=", 2, opid2('^','='), ASSOC_RIGHT, 2, 0 }, + { "|=", 2, opid2('|','='), ASSOC_RIGHT, 2, 0 }, -bool parse(parse_file*); + { ":", 3, opid2(':','?'), ASSOC_RIGHT, 1, 0 }, -bool parse_iskey(parse_file *self, const char *ident); + { ",", 2, opid1(','), ASSOC_LEFT, 0, 0 } +}; +static const size_t c_operator_count = (sizeof(c_operators) / sizeof(c_operators[0])); + +static const oper_info fte_operators[] = { + { "(", 0, opid1('('), ASSOC_LEFT, 99, OP_PREFIX}, /* paren expression - non function call */ + + { "++", 1, opid3('S','+','+'), ASSOC_LEFT, 15, OP_SUFFIX}, + { "--", 1, opid3('S','-','-'), ASSOC_LEFT, 15, OP_SUFFIX}, + { ".", 2, opid1('.'), ASSOC_LEFT, 15, 0 }, + { "(", 0, opid1('('), ASSOC_LEFT, 15, 0 }, /* function call */ + { "[", 2, opid1('['), ASSOC_LEFT, 15, 0 }, /* array subscript */ + + { "!", 1, opid2('!', 'P'), ASSOC_RIGHT, 14, OP_PREFIX }, + { "+", 1, opid2('+','P'), ASSOC_RIGHT, 14, OP_PREFIX }, + { "-", 1, opid2('-','P'), ASSOC_RIGHT, 14, OP_PREFIX }, + { "++", 1, opid3('+','+','P'), ASSOC_RIGHT, 14, OP_PREFIX }, + { "--", 1, opid3('-','-','P'), ASSOC_RIGHT, 14, OP_PREFIX }, + + { "*", 2, opid1('*'), ASSOC_LEFT, 13, 0 }, + { "/", 2, opid1('/'), ASSOC_LEFT, 13, 0 }, + { "&", 2, opid1('&'), ASSOC_LEFT, 13, 0 }, + { "|", 2, opid1('|'), ASSOC_LEFT, 13, 0 }, + + { "+", 2, opid1('+'), ASSOC_LEFT, 12, 0 }, + { "-", 2, opid1('-'), ASSOC_LEFT, 12, 0 }, + + { "<", 2, opid1('<'), ASSOC_LEFT, 10, 0 }, + { ">", 2, opid1('>'), ASSOC_LEFT, 10, 0 }, + { "<=", 2, opid2('<','='), ASSOC_LEFT, 10, 0 }, + { ">=", 2, opid2('>','='), ASSOC_LEFT, 10, 0 }, + { "==", 2, opid2('=','='), ASSOC_LEFT, 10, 0 }, + { "!=", 2, opid2('!','='), ASSOC_LEFT, 10, 0 }, + + { "?", 3, opid2('?',':'), ASSOC_RIGHT, 9, 0 }, + + { "=", 2, opid1('='), ASSOC_RIGHT, 8, 0 }, + { "+=", 2, opid2('+','='), ASSOC_RIGHT, 8, 0 }, + { "-=", 2, opid2('-','='), ASSOC_RIGHT, 8, 0 }, + { "*=", 2, opid2('*','='), ASSOC_RIGHT, 8, 0 }, + { "/=", 2, opid2('/','='), ASSOC_RIGHT, 8, 0 }, + { "%=", 2, opid2('%','='), ASSOC_RIGHT, 8, 0 }, + { "&=", 2, opid2('&','='), ASSOC_RIGHT, 8, 0 }, + { "|=", 2, opid2('|','='), ASSOC_RIGHT, 8, 0 }, + { "&~=", 2, opid3('&','~','='), ASSOC_RIGHT, 8, 0 }, + + { "&&", 2, opid2('&','&'), ASSOC_LEFT, 5, 0 }, + { "||", 2, opid2('|','|'), ASSOC_LEFT, 5, 0 }, + + /* Leave precedence 3 for : with -fcorrect-ternary */ + { ",", 2, opid1(','), ASSOC_LEFT, 2, 0 }, + { ":", 0, opid2(':','?'), ASSOC_RIGHT, 1, 0 } +}; +static const size_t fte_operator_count = (sizeof(fte_operators) / sizeof(fte_operators[0])); + +static const oper_info qcc_operators[] = { + { "(", 0, opid1('('), ASSOC_LEFT, 99, OP_PREFIX}, /* paren expression - non function call */ + + { ".", 2, opid1('.'), ASSOC_LEFT, 15, 0 }, + { "(", 0, opid1('('), ASSOC_LEFT, 15, 0 }, /* function call */ + { "[", 2, opid1('['), ASSOC_LEFT, 15, 0 }, /* array subscript */ + + { "!", 1, opid2('!', 'P'), ASSOC_RIGHT, 14, OP_PREFIX }, + { "+", 1, opid2('+','P'), ASSOC_RIGHT, 14, OP_PREFIX }, + { "-", 1, opid2('-','P'), ASSOC_RIGHT, 14, OP_PREFIX }, + + { "*", 2, opid1('*'), ASSOC_LEFT, 13, 0 }, + { "/", 2, opid1('/'), ASSOC_LEFT, 13, 0 }, + { "&", 2, opid1('&'), ASSOC_LEFT, 13, 0 }, + { "|", 2, opid1('|'), ASSOC_LEFT, 13, 0 }, + + { "+", 2, opid1('+'), ASSOC_LEFT, 12, 0 }, + { "-", 2, opid1('-'), ASSOC_LEFT, 12, 0 }, + + { "<", 2, opid1('<'), ASSOC_LEFT, 10, 0 }, + { ">", 2, opid1('>'), ASSOC_LEFT, 10, 0 }, + { "<=", 2, opid2('<','='), ASSOC_LEFT, 10, 0 }, + { ">=", 2, opid2('>','='), ASSOC_LEFT, 10, 0 }, + { "==", 2, opid2('=','='), ASSOC_LEFT, 10, 0 }, + { "!=", 2, opid2('!','='), ASSOC_LEFT, 10, 0 }, + + { "=", 2, opid1('='), ASSOC_RIGHT, 8, 0 }, + { "+=", 2, opid2('+','='), ASSOC_RIGHT, 8, 0 }, + { "-=", 2, opid2('-','='), ASSOC_RIGHT, 8, 0 }, + { "*=", 2, opid2('*','='), ASSOC_RIGHT, 8, 0 }, + { "/=", 2, opid2('/','='), ASSOC_RIGHT, 8, 0 }, + { "%=", 2, opid2('%','='), ASSOC_RIGHT, 8, 0 }, + { "&=", 2, opid2('&','='), ASSOC_RIGHT, 8, 0 }, + { "|=", 2, opid2('|','='), ASSOC_RIGHT, 8, 0 }, + + { "&&", 2, opid2('&','&'), ASSOC_LEFT, 5, 0 }, + { "||", 2, opid2('|','|'), ASSOC_LEFT, 5, 0 }, + + { ",", 2, opid1(','), ASSOC_LEFT, 2, 0 }, +}; +static const size_t qcc_operator_count = (sizeof(qcc_operators) / sizeof(qcc_operators[0])); +extern const oper_info *operators; +extern size_t operator_count; void lexerror(lex_file*, const char *fmt, ...); #endif