bool CMaExpander::ReadToken(CToken *token) { bool retval; retval = ::ReadToken(tc, &pos, token, &gex, for_include); if( gex.GetError() != NULL ) throw &gex; return retval; }
static bool get_token(TCC_CONTEXT *tc, const char **line, CToken *token, bool for_include) { bool retval; CException *ex = new CException; retval = ::ReadToken(tc, line, token, ex, for_include); if( ex->GetError() != NULL ) throw ex; delete ex; return retval; }
static void handle_define(TCC_CONTEXT *tc, sym_t mid, CMacro *ma) { enum { STA_OKAY, STA_LEFT_PARENTHESIS, STA_PARAMETER, STA_SEPERATOR, STA_TRIDOT, } state; const char *line = ma->line; CToken token; if( ! get_token(tc, &line, &token, false) ) return; if(token.attr == CToken::TA_IDENT) { if(*line == '(') { CC_ARRAY<sym_t> para_list; XCHAR *xc; const char *last_pos; sym_t last_para = SSID_INVALID; bool has_va_args = false; state = STA_LEFT_PARENTHESIS; line++; while( get_token(tc, &line, &token, false) ) { switch(state) { case STA_LEFT_PARENTHESIS: if( token.id == SSID_RIGHT_PARENTHESIS) { state = STA_OKAY; goto okay; } else if(token.attr == CToken::TA_IDENT) { para_list.push_back(token.id); state = STA_SEPERATOR; } else if(token.id == SSID_TRIDOT) { state = STA_TRIDOT; continue; } else { gEx.format("\"%s\" may not appear in macro parameter list", TR(tc,token.id)); goto error; } break; case STA_SEPERATOR: if(token.id == SSID_RIGHT_PARENTHESIS) { state = STA_OKAY; goto okay; } else if(token.id == SSID_COMMA) state = STA_PARAMETER; else if(token.id == SSID_TRIDOT) { state = STA_TRIDOT; } else { gEx = "macro parameters must be comma-separated"; goto error; } break; case STA_PARAMETER: if(token.id == SSID_TRIDOT) { state = STA_TRIDOT; continue; } else if(token.attr == CToken::TA_IDENT) { para_list.push_back(token.id); state = STA_SEPERATOR; } else { gEx = "parameter name missing"; goto error; } break; case STA_TRIDOT: if(token.id != SSID_RIGHT_PARENTHESIS) { gEx = "missing ')' in macro parameter list"; throw &gEx; } has_va_args = true; if(last_para == SSID_COMMA || last_para == SSID_LEFT_PARENTHESIS) { para_list.push_back(SSID_VA_ARGS); last_para = SSID_VA_ARGS; } goto okay; default: assert(0); } last_para = token.id; } if(state != STA_OKAY) { gEx = "missing ')' in macro parameter list"; throw &gEx; } okay: xc = (XCHAR*) malloc(sizeof(XCHAR) * strlen(line) + 4); ma->id = mid; ma->parsed = xc; ma->nr_args = para_list.size(); ma->va_args = has_va_args; skip_blanks(line); last_pos = line; sym_t prev_sid = SSID_INVALID; while( ReadToken(tc, &line, &token, &gEx, false) ) { if(gEx.GetError() != NULL) throw (&gEx); if(token.id == SSID_DUAL_SHARP) { if(xc == ma->parsed) { gEx = "'##' cannot appear at either end of a macro expansion"; goto error; } else if( IS_MA_PAR0(*(xc-1)) ) *(xc-1) |= XF_MA_PAR2; } if(prev_sid == SSID_DUAL_SHARP) { XCHAR *yc = xc - 3; while( yc >= ma->parsed && (*yc == '\t' || *yc == ' ') ) yc--; xc = yc + 1; assert(*xc == '#' || *xc == ' ' || *xc == '\t'); } if( token.attr == CToken::TA_IDENT ) { int magic = 0; int16_t para_ord; static const XCHAR xflags[3] = { XF_MA_PAR0, XF_MA_PAR1, XF_MA_PAR2 }; if( has_va_args && (token.id == last_para || token.id == SSID_VA_ARGS) ) para_ord = ma->nr_args - 1; else para_ord = find(token.id, para_list); if(prev_sid == SSID_SHARP) { if(para_ord < 0) { gEx = "'#' is not followed by a macro parameter"; goto error; } magic = 1; xc--; } else if(prev_sid == SSID_DUAL_SHARP) { magic = 2; } if(para_ord < 0) goto do_cat; *xc++ = para_ord | xflags[magic]; } else { do_cat: if(prev_sid == SSID_DUAL_SHARP) { skip_blanks(last_pos); } join(&xc, last_pos, line); } last_pos = line; prev_sid = token.id; } /*end while*/ *xc = 0; } else { XCHAR *xc; xc = (XCHAR*) malloc(sizeof(XCHAR) * strlen(line) + 4); ma->id = mid; ma->parsed = xc; ma->nr_args = CMacro::OL_M; skip_blanks(line); while(1) { char c = *line; if( iseol(c) ) { *xc = '\0'; break; } *xc = c; xc++, line++; } } } // dump(ma->parsed); return; error: throw &gEx; }