X-Git-Url: https://de.git.xonotic.org/?a=blobdiff_plain;f=lexer.h;h=f75dff6232d4b7ea72aaac132284731006884fa9;hb=refs%2Fheads%2FTimePath%2Fparser;hp=75fb83e9320fc159d432819c408b3abf339270c7;hpb=c41ef65cc92193e9b685cc123ca9d4de9d142756;p=xonotic%2Fgmqcc.git diff --git a/lexer.h b/lexer.h index 75fb83e..f75dff6 100644 --- a/lexer.h +++ b/lexer.h @@ -1,141 +1,188 @@ -/* - * Copyright (C) 2012, 2013 - * 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; - -struct token_s { - int ttype; - - char *value; - - union { - vector v; - int i; - double f; - int t; /* type */ - } constval; - -#if 0 - struct token_s *next; - struct token_s *prev; -#endif - - lex_ctx ctx; +#include "gmqcc.h" + +#define TOKENS(X) \ + /* Other tokens which we can return: */ \ + X(NONE, =0) \ + X(CR, = '\r') \ + X(LF, = '\n') \ + X(WS, = ' ') \ + X(BACKSLASH, = '\\') \ + X(HASH, = '#') \ + X(DOLLAR, = '$') \ + X(DOT, = '.') \ + X(COMMA, = ',') \ + X(COLON, = ':') \ + X(SEMICOLON, = ';') \ + X(AND, = '&') \ + X(OR, = '|') \ + X(XOR, = '^') \ + X(BITNOT, = '~') \ + X(NOT, = '!') \ + X(LT, = '<') \ + X(GT, = '>') \ + X(EQ, = '=') \ + X(MUL, = '*') \ + X(DIV, = '/') \ + X(MOD, = '%') \ + X(ADD, = '+') \ + X(SUB, = '-') \ + X(QUOT_SINGLE, = '\'') \ + X(QUOT_DOUBLE, = '"') \ + X(QUESTION, = '?') \ + X(BRACE_OPEN, = '{') \ + X(BRACE_CLOSE, = '}') \ + X(BRACKET_OPEN, = '[') \ + X(BRACKET_CLOSE, = ']') \ + X(PAREN_OPEN, = '(') \ + X(PAREN_CLOSE, = ')') \ + X(START, = 128) \ + X(IDENT, ) \ + X(TYPENAME, ) \ + X(OPERATOR, ) \ + X(OP_AND, ) \ + X(OP_CROSS, ) \ + X(OP_LE, ) \ + X(OP_GE, ) \ + X(OP_LSH, ) \ + X(OP_RSH, ) \ + /* loop */ \ + X(KEYWORD, ) \ + /* 3 dots, ... */ \ + X(DOTS, ) \ + /* [[ */ \ + X(ATTRIBUTE_OPEN, ) \ + /* ]] */ \ + X(ATTRIBUTE_CLOSE, ) \ + /* for the ftepp only */ \ + X(VA_ARGS, ) \ + /* for the ftepp only */ \ + X(VA_ARGS_ARRAY, ) \ + /* to get the count of vaargs */ \ + X(VA_COUNT, ) \ + /* not the typename but an actual "string" */ \ + X(STRINGCONST, ) \ + X(CHARCONST, ) \ + X(VECTORCONST, ) \ + X(INTCONST, ) \ + X(FLOATCONST, ) \ + X(WHITE, ) \ + X(EOL, ) \ + /* if we add additional tokens before this, the exposed API \ + * should not be broken anyway, but EOF/ERROR/... should \ + * still be at the bottom \ + */ \ + X(END, = 1024) \ + /* We use '< ERROR', so FATAL must come after it and any \ + * other error related tokens as well \ + */ \ + X(ERROR, ) \ + /* internal error, eg out of memory */ \ + X(FATAL, ) \ + /**/ + +enum Token : int { // todo: enum class +#define X(id, val) id val, + TOKENS(X) +#undef X }; -#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 - * - */ -enum { - /* Other tokens which we can return: */ - TOKEN_NONE = 0, - TOKEN_START = 128, - - TOKEN_IDENT, +inline const char *TokenName(Token t) { + switch (t) { + default: + return "UNKNOWN"; +#define X(id, val) case Token::id: return #id; + TOKENS(X) +#undef X + } +} - TOKEN_TYPENAME, +struct cvec { + std::string value; - TOKEN_OPERATOR, + explicit cvec() = default; - TOKEN_KEYWORD, /* loop */ + char *mut() { + return &value[0]; + } - TOKEN_DOTS, /* 3 dots, ... */ + const char *c_str() { + return value.c_str(); + } - TOKEN_ATTRIBUTE_OPEN, /* [[ */ - TOKEN_ATTRIBUTE_CLOSE, /* ]] */ + void shrinkto(size_t i) { + value.resize(i); + } - TOKEN_VA_ARGS, /* for the ftepp only */ - TOKEN_VA_ARGS_ARRAY, /* for the ftepp only */ + void shrinkby(size_t i) { + value.resize(value.size() - i); + } - TOKEN_STRINGCONST, /* not the typename but an actual "string" */ - TOKEN_CHARCONST, - TOKEN_VECTORCONST, - TOKEN_INTCONST, - TOKEN_FLOATCONST, - - TOKEN_WHITE, - TOKEN_EOL, - - TOKEN_EOF, + void push(char it) { + value.push_back(it); + } +}; - /* We use '< TOKEN_ERROR', so TOKEN_FATAL must come after it and any - * other error related tokens as well - */ - TOKEN_ERROR, - TOKEN_FATAL /* internal error, eg out of memory */ +struct token { + Token ttype; + cvec value; + union { + vec3_t v; + int i; + qcfloat_t f; + qc_type t; /* type */ + } constval; + lex_ctx_t ctx; }; -typedef struct { - char *name; - int value; -} frame_macro; +struct frame_macro { + std::string name; + int value; +}; -typedef struct lex_file_s { - FILE *file; +struct lex_file { + FILE *file; const char *open_string; - size_t open_string_length; - size_t open_string_pos; + 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 */ + char *name; + size_t line; + size_t sline; /* line at the start of a token */ + size_t column; - int peek[256]; - size_t peekpos; + std::array peek; + size_t peekpos; - bool eof; + bool eof; - token tok; /* not a pointer anymore */ + 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; + bool noops:1; + bool nodigraphs:1; /* used when lexing string constants */ + bool preprocessing:1; /* whitespace and EOLs become actual tokens */ + bool mergelines:1; /* backslash at the end of a line escapes the newline */ + } flags; /* sizeof == 1 */ int framevalue; frame_macro *frames; - char *modelname; + std::string 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); +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); + +Token lex_do(lex_file *lex); + +void lex_cleanup(); /* Parser * @@ -149,183 +196,188 @@ enum { #define OP_SUFFIX 1 #define OP_PREFIX 2 -typedef struct { - const char *op; +struct oper_info { + const char *op; unsigned int operands; unsigned int id; unsigned int assoc; - signed int prec; + signed int prec; unsigned int flags; -} oper_info; + bool folds; +}; -#define opid1(a) (a) -#define opid2(a,b) ((a<<8)|b) -#define opid3(a,b,c) ((a<<16)|(b<<8)|c) +/* + * Explicit uint8_t casts since the left operand of shift operator cannot + * be negative, even though it won't happen, this supresses the future + * possibility. + */ +#define opid1(a) ((uint8_t)a) +#define opid2(a, b) (((uint8_t)a<<8) |(uint8_t)b) +#define opid3(a, b, c) (((uint8_t)a<<16)|((uint8_t)b<<8)|(uint8_t)c) static const oper_info c_operators[] = { - { "(", 0, opid1('('), ASSOC_LEFT, 99, OP_PREFIX}, /* paren expression - non function call */ + {"(", 0, opid1('('), ASSOC_LEFT, 99, OP_PREFIX, false}, /* paren expression - non function call */ + {"_length", 1, opid3('l', 'e', 'n'), ASSOC_RIGHT, 98, OP_PREFIX, true}, - { "++", 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, opid3('S', '+', '+'), ASSOC_LEFT, 17, OP_SUFFIX, false}, + {"--", 1, opid3('S', '-', '-'), ASSOC_LEFT, 17, OP_SUFFIX, false}, + {".", 2, opid1('.'), ASSOC_LEFT, 17, 0, false}, + {"(", 0, opid1('('), ASSOC_LEFT, 17, 0, false}, /* function call */ + {"[", 2, opid1('['), ASSOC_LEFT, 17, 0, false}, /* 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, 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 }, */ + {"++", 1, opid3('+', '+', 'P'), ASSOC_RIGHT, 16, OP_PREFIX, false}, + {"--", 1, opid3('-', '-', 'P'), ASSOC_RIGHT, 16, OP_PREFIX, false}, - { "*", 2, opid1('*'), ASSOC_LEFT, 13, 0 }, - { "/", 2, opid1('/'), ASSOC_LEFT, 13, 0 }, - { "%", 2, opid1('%'), ASSOC_LEFT, 13, 0 }, + {"**", 2, opid2('*', '*'), ASSOC_RIGHT, 14, 0, true}, + {"!", 1, opid2('!', 'P'), ASSOC_RIGHT, 14, OP_PREFIX, true}, + {"~", 1, opid2('~', 'P'), ASSOC_RIGHT, 14, OP_PREFIX, true}, + {"+", 1, opid2('+', 'P'), ASSOC_RIGHT, 14, OP_PREFIX, false}, + {"-", 1, opid2('-', 'P'), ASSOC_RIGHT, 14, OP_PREFIX, true}, +/* { "&", 1, opid2('&','P'), ASSOC_RIGHT, 14, OP_PREFIX, false}, */ - { "+", 2, opid1('+'), ASSOC_LEFT, 12, 0 }, - { "-", 2, opid1('-'), ASSOC_LEFT, 12, 0 }, + {"*", 2, opid1('*'), ASSOC_LEFT, 13, 0, true}, + {"/", 2, opid1('/'), ASSOC_LEFT, 13, 0, true}, + {"%", 2, opid1('%'), ASSOC_LEFT, 13, 0, true}, + {"><", 2, opid2('>', '<'), ASSOC_LEFT, 13, 0, true}, - { "<<", 2, opid2('<','<'), ASSOC_LEFT, 11, 0 }, - { ">>", 2, opid2('>','>'), ASSOC_LEFT, 11, 0 }, + {"+", 2, opid1('+'), ASSOC_LEFT, 12, 0, true}, + {"-", 2, opid1('-'), ASSOC_LEFT, 12, 0, true}, - { "<", 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, 11, 0, true}, + {">>", 2, opid2('>', '>'), ASSOC_LEFT, 11, 0, true}, - { "==", 2, opid2('=','='), ASSOC_LEFT, 9, 0 }, - { "!=", 2, opid2('!','='), ASSOC_LEFT, 9, 0 }, + {"<", 2, opid1('<'), ASSOC_LEFT, 10, 0, false}, + {">", 2, opid1('>'), ASSOC_LEFT, 10, 0, false}, + {"<=>", 2, opid3('<', '=', '>'), ASSOC_LEFT, 10, 0, true}, + {"<=", 2, opid2('<', '='), ASSOC_LEFT, 10, 0, false}, + {">=", 2, opid2('>', '='), ASSOC_LEFT, 10, 0, false}, - { "&", 2, opid1('&'), ASSOC_LEFT, 8, 0 }, + {"==", 2, opid2('=', '='), ASSOC_LEFT, 9, 0, true}, + {"!=", 2, opid2('!', '='), ASSOC_LEFT, 9, 0, true}, - { "^", 2, opid1('^'), ASSOC_LEFT, 7, 0 }, + {"&", 2, opid1('&'), ASSOC_LEFT, 8, 0, true}, - { "|", 2, opid1('|'), ASSOC_LEFT, 6, 0 }, + {"^", 2, opid1('^'), ASSOC_LEFT, 7, 0, true}, - { "&&", 2, opid2('&','&'), ASSOC_LEFT, 5, 0 }, + {"|", 2, opid1('|'), ASSOC_LEFT, 6, 0, true}, - { "||", 2, opid2('|','|'), ASSOC_LEFT, 4, 0 }, + {"&&", 2, opid2('&', '&'), ASSOC_LEFT, 5, 0, true}, - { "?", 3, opid2('?',':'), ASSOC_RIGHT, 3, 0 }, + {"||", 2, opid2('|', '|'), ASSOC_LEFT, 4, 0, true}, - { "=", 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 }, - { "&~=", 2, opid3('&','~','='), ASSOC_RIGHT, 2, 0 }, + {"?", 3, opid2('?', ':'), ASSOC_RIGHT, 3, 0, true}, - { ":", 0, opid2(':','?'), ASSOC_RIGHT, 1, 0 }, + {"=", 2, opid1('='), ASSOC_RIGHT, 2, 0, false}, + {"+=", 2, opid2('+', '='), ASSOC_RIGHT, 2, 0, false}, + {"-=", 2, opid2('-', '='), ASSOC_RIGHT, 2, 0, false}, + {"*=", 2, opid2('*', '='), ASSOC_RIGHT, 2, 0, false}, + {"/=", 2, opid2('/', '='), ASSOC_RIGHT, 2, 0, false}, + {"%=", 2, opid2('%', '='), ASSOC_RIGHT, 2, 0, false}, + {">>=", 2, opid3('>', '>', '='), ASSOC_RIGHT, 2, 0, false}, + {"<<=", 2, opid3('<', '<', '='), ASSOC_RIGHT, 2, 0, false}, + {"&=", 2, opid2('&', '='), ASSOC_RIGHT, 2, 0, false}, + {"^=", 2, opid2('^', '='), ASSOC_RIGHT, 2, 0, false}, + {"|=", 2, opid2('|', '='), ASSOC_RIGHT, 2, 0, false}, - { ",", 2, opid1(','), ASSOC_LEFT, 0, 0 } + {":", 0, opid2(':', '?'), ASSOC_RIGHT, 1, 0, false}, + + {",", 2, opid1(','), ASSOC_LEFT, 0, 0, false} }; -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, opid2('<','<'), ASSOC_LEFT, 11, 0 }, - { ">>", 2, opid2('>','>'), ASSOC_LEFT, 11, 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 } + {"(", 0, opid1('('), ASSOC_LEFT, 99, OP_PREFIX, false}, /* paren expression - non function call */ + + {"++", 1, opid3('S', '+', '+'), ASSOC_LEFT, 15, OP_SUFFIX, false}, + {"--", 1, opid3('S', '-', '-'), ASSOC_LEFT, 15, OP_SUFFIX, false}, + {".", 2, opid1('.'), ASSOC_LEFT, 15, 0, false}, + {"(", 0, opid1('('), ASSOC_LEFT, 15, 0, false}, /* function call */ + {"[", 2, opid1('['), ASSOC_LEFT, 15, 0, false}, /* array subscript */ + + {"!", 1, opid2('!', 'P'), ASSOC_RIGHT, 14, OP_PREFIX, true}, + {"+", 1, opid2('+', 'P'), ASSOC_RIGHT, 14, OP_PREFIX, false}, + {"-", 1, opid2('-', 'P'), ASSOC_RIGHT, 14, OP_PREFIX, true}, + {"++", 1, opid3('+', '+', 'P'), ASSOC_RIGHT, 14, OP_PREFIX, false}, + {"--", 1, opid3('-', '-', 'P'), ASSOC_RIGHT, 14, OP_PREFIX, false}, + + {"*", 2, opid1('*'), ASSOC_LEFT, 13, 0, true}, + {"/", 2, opid1('/'), ASSOC_LEFT, 13, 0, true}, + {"&", 2, opid1('&'), ASSOC_LEFT, 13, 0, true}, + {"|", 2, opid1('|'), ASSOC_LEFT, 13, 0, true}, + + {"+", 2, opid1('+'), ASSOC_LEFT, 12, 0, true}, + {"-", 2, opid1('-'), ASSOC_LEFT, 12, 0, true}, + + {"<<", 2, opid2('<', '<'), ASSOC_LEFT, 11, 0, true}, + {">>", 2, opid2('>', '>'), ASSOC_LEFT, 11, 0, true}, + + {"<", 2, opid1('<'), ASSOC_LEFT, 10, 0, false}, + {">", 2, opid1('>'), ASSOC_LEFT, 10, 0, false}, + {"<=", 2, opid2('<', '='), ASSOC_LEFT, 10, 0, false}, + {">=", 2, opid2('>', '='), ASSOC_LEFT, 10, 0, false}, + {"==", 2, opid2('=', '='), ASSOC_LEFT, 10, 0, true}, + {"!=", 2, opid2('!', '='), ASSOC_LEFT, 10, 0, true}, + + {"?", 3, opid2('?', ':'), ASSOC_RIGHT, 9, 0, true}, + + {"=", 2, opid1('='), ASSOC_RIGHT, 8, 0, false}, + {"+=", 2, opid2('+', '='), ASSOC_RIGHT, 8, 0, false}, + {"-=", 2, opid2('-', '='), ASSOC_RIGHT, 8, 0, false}, + {"*=", 2, opid2('*', '='), ASSOC_RIGHT, 8, 0, false}, + {"/=", 2, opid2('/', '='), ASSOC_RIGHT, 8, 0, false}, + {"%=", 2, opid2('%', '='), ASSOC_RIGHT, 8, 0, false}, + {"&=", 2, opid2('&', '='), ASSOC_RIGHT, 8, 0, false}, + {"|=", 2, opid2('|', '='), ASSOC_RIGHT, 8, 0, false}, + {"&~=", 2, opid3('&', '~', '='), ASSOC_RIGHT, 8, 0, false}, + + {"&&", 2, opid2('&', '&'), ASSOC_LEFT, 5, 0, true}, + {"||", 2, opid2('|', '|'), ASSOC_LEFT, 5, 0, true}, + + /* Leave precedence 3 for : with -fcorrect-ternary */ + {",", 2, opid1(','), ASSOC_LEFT, 2, 0, false}, + {":", 0, opid2(':', '?'), ASSOC_RIGHT, 1, 0, false} }; -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 }, + {"(", 0, opid1('('), ASSOC_LEFT, 99, OP_PREFIX, false}, /* paren expression - non function call */ + + {".", 2, opid1('.'), ASSOC_LEFT, 15, 0, false}, + {"(", 0, opid1('('), ASSOC_LEFT, 15, 0, false}, /* function call */ + {"[", 2, opid1('['), ASSOC_LEFT, 15, 0, false}, /* array subscript */ + + {"!", 1, opid2('!', 'P'), ASSOC_RIGHT, 14, OP_PREFIX, true}, + {"+", 1, opid2('+', 'P'), ASSOC_RIGHT, 14, OP_PREFIX, false}, + {"-", 1, opid2('-', 'P'), ASSOC_RIGHT, 14, OP_PREFIX, true}, + + {"*", 2, opid1('*'), ASSOC_LEFT, 13, 0, true}, + {"/", 2, opid1('/'), ASSOC_LEFT, 13, 0, true}, + {"&", 2, opid1('&'), ASSOC_LEFT, 13, 0, true}, + {"|", 2, opid1('|'), ASSOC_LEFT, 13, 0, true}, + + {"+", 2, opid1('+'), ASSOC_LEFT, 12, 0, true}, + {"-", 2, opid1('-'), ASSOC_LEFT, 12, 0, true}, + + {"<", 2, opid1('<'), ASSOC_LEFT, 10, 0, false}, + {">", 2, opid1('>'), ASSOC_LEFT, 10, 0, false}, + {"<=", 2, opid2('<', '='), ASSOC_LEFT, 10, 0, false}, + {">=", 2, opid2('>', '='), ASSOC_LEFT, 10, 0, false}, + {"==", 2, opid2('=', '='), ASSOC_LEFT, 10, 0, true}, + {"!=", 2, opid2('!', '='), ASSOC_LEFT, 10, 0, true}, + + {"=", 2, opid1('='), ASSOC_RIGHT, 8, 0, false}, + {"+=", 2, opid2('+', '='), ASSOC_RIGHT, 8, 0, false}, + {"-=", 2, opid2('-', '='), ASSOC_RIGHT, 8, 0, false}, + {"*=", 2, opid2('*', '='), ASSOC_RIGHT, 8, 0, false}, + {"/=", 2, opid2('/', '='), ASSOC_RIGHT, 8, 0, false}, + {"%=", 2, opid2('%', '='), ASSOC_RIGHT, 8, 0, false}, + {"&=", 2, opid2('&', '='), ASSOC_RIGHT, 8, 0, false}, + {"|=", 2, opid2('|', '='), ASSOC_RIGHT, 8, 0, false}, + + {"&&", 2, opid2('&', '&'), ASSOC_LEFT, 5, 0, true}, + {"||", 2, opid2('|', '|'), ASSOC_LEFT, 5, 0, true}, + + {",", 2, opid1(','), ASSOC_LEFT, 2, 0, false}, }; -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, ...); +extern size_t operator_count; #endif