/************************************************************************ ** dump_comment : while skipping a comment, output it. ************************************************************************/ void dump_comment() { if( ! Cflag ) { skip_1comment(); return; } myfwrite(L"/*", 2 * sizeof(WCHAR), 1, OUTPUTFILE); for(;;) { WCHAR c; switch(CHARMAP(c = GETCH())) { case LX_STAR: if(checkop(L'/')) { myfwrite(L"*/", 2 * sizeof(WCHAR), 1, OUTPUTFILE); return; } break; case LX_EOS: handle_eos(); continue; case LX_NL: Linenumber++; break; /* output below */ // must manually write '\r' with '\n' when writing 16-bit strings //case LX_CR: // continue; } myfwrite(&c, sizeof(WCHAR), 1, OUTPUTFILE); } }
/************************************************************************ ** checknl : check for newline, skipping carriage return if there is one. ** also increments Linenumber, so this should be used by routines which ** will not push the newline back in such a way that rawtok() will be invoked, ** find the newline and do another increment. ************************************************************************/ int checknl(void) { REG WCHAR c; for(;;) { c = GETCH(); if(c > L'\r') { UNGETCH(); return(FALSE); } switch(c) { case L'\n': Linenumber++; // must manually write '\r' with '\n' when writing 16-bit strings if( Prep ) { myfwrite(L"\r\n", 2 * sizeof(WCHAR), 1, OUTPUTFILE); } return(TRUE); break; case L'\r': continue; break; case EOS_CHAR: handle_eos(); PREVCH() = L'\\'; /* M00HACK - needs pushback */ continue; break; default: UNGETCH(); return(FALSE); break; } } }
/************************************************************************ ** skip_1comment : we're called when we're already in a comment. ** we're looking for the comment close. we also count newlines ** and output them if we're preprocessing. ************************************************************************/ void skip_1comment(void) { UINT c; for(;;) { c = GETCH(); if(c == L'*') { recheck: c = GETCH(); if(c == L'/') { /* end of comment */ return; } else if(c == L'*') { /* ** if we get another '*' go back and check for a slash */ goto recheck; } else if(c == EOS_CHAR) { handle_eos(); goto recheck; } } /* ** note we fall through here. we know this baby is not a '*' ** we used to unget the char and continue. since we check for ** another '*' inside the above test, we can fall through here ** without ungetting/getting and checking again. */ if(c <= L'\n') { /* ** hopefully, the above test is less expensive than doing two tests */ if(c == L'\n') { Linenumber++; if(Prep) { myfwrite(L"\r\n", 2 * sizeof(WCHAR), 1, OUTPUTFILE); } } else if(c == EOS_CHAR) { handle_eos(); } } } }
/************************************************************************ ** str_const : gather up a string constant ************************************************************************/ void str_const(VOID) { REG WCHAR c; REG PWCHAR p_buf; int not_warned_yet = TRUE; p_buf = yylval.yy_string.str_ptr = Macro_buffer; /* ** Is it possible that reading this string during a rescan will ** overwrite the expansion being rescanned? No, because a macro ** expansion is limited to the top half of Macro_buffer. ** For Macro_depth > 0, this is like copying the string from ** somewhere in the top half of Macro_buffer to the bottom half ** of Macro_buffer. ** Note that the restriction on the size of an expanded macro is ** stricter than the limit on an L_STRING length. An expanded ** macro is limited to around 1019 bytes, but an L_STRING is ** limited to 2043 bytes. */ for(;;) { switch(CHARMAP(c = GETCH())) { case LX_NL: UNGETCH(); strcpy (Msg_Text, GET_MSG (2001)); error(2001); /* ** FALLTHROUGH */ case LX_DQUOTE: *p_buf++ = L'\0'; yylval.yy_string.str_len = (USHORT)(p_buf-yylval.yy_string.str_ptr); return; break; case LX_EOS: if(handle_eos() != BACKSLASH_EOS) { continue; } if(InInclude) { break; } else { c = (WCHAR)escape(get_non_eof()); /* process escaped char */ } break; } if(p_buf - Macro_buffer > LIMIT_STRING_LENGTH) { if( not_warned_yet ) { strcpy (Msg_Text, GET_MSG (4009)); warning(4009); /* string too big, truncating */ not_warned_yet = FALSE; } } else { *p_buf++ = c; } } }
/************************************************************************ ** char_const : gather up a character constant ** we're called after finding the openning single quote. ************************************************************************/ token_t char_const(void) { REG WCHAR c; value_t value; token_t tok; tok = (token_t)(Jflag ? L_CUNSIGNED : L_CINTEGER); first_switch: switch(CHARMAP(c = GETCH())) { case LX_BACKSLASH: break; case LX_SQUOTE: strcpy (Msg_Text, GET_MSG (2137)); //"empty character constant" error(2137); value.v_long = 0; UNGETCH(); break; case LX_EOS: /* ??? assumes i/o buffering > 1 char */ if(handle_eos() != BACKSLASH_EOS) { goto first_switch; } value.v_long = escape(get_non_eof()); if( tok == L_CUNSIGNED ) { /* don't sign extend */ value.v_long &= 0xff; } break; case LX_NL: /* newline in character constant */ strcpy (Msg_Text, GET_MSG (2001)); error (2001); UNGETCH(); /* ** FALLTHROUGH */ default: value.v_long = c; break; } if((c = get_non_eof()) != L'\'') { strcpy (Msg_Text, GET_MSG (2015)); error (2015); /* too many chars in constant */ do { if(c == L'\n') { strcpy (Msg_Text, GET_MSG (2016)); error(2016); /* missing closing ' */ break; } } while((c = get_non_eof()) != L'\''); } yylval.yy_tree = build_const(tok, &value); return(tok); }
/************************************************************************ ** can_get_non_white: tries to get the next non white character ** using P1 rules for white space (NL included). If the end of ** an actual, or a rescan is found, this returns FALSE, so control ** can drop into one of the lexers. ************************************************************************/ int can_get_non_white(void) { int return_value = FALSE; int white_found = FALSE; for(;;) { switch(CHARMAP(GETCH())) { case LX_NL: if(On_pound_line) { UNGETCH(); goto leave_cgnw; } Linenumber++; /* ** FALLTHROUGH */ case LX_WHITE: case LX_CR: white_found = TRUE; break; case LX_EOS: { int eos_res; if((eos_res = handle_eos()) & (ACTUAL_EOS | RESCAN_EOS)) { goto leave_cgnw; } if(eos_res != BACKSLASH_EOS) { break; } } /* ** FALLTHROUGH */ default: UNGETCH(); return_value = TRUE; goto leave_cgnw; break; } } leave_cgnw: if(white_found) { if(Exp_ptr >= ELIMIT) { fatal_in_macro(10056); } if(*(Exp_ptr - 1) != ' ') { *Exp_ptr++ = ' '; } } return(return_value); /* could you get next non white? */ }
/************************************************************************ ** prep_string : outputs char/string constants when preprocessing only ************************************************************************/ void prep_string(REG WCHAR c) { REG WCHAR *p_buf; int term_char; p_buf = Reuse_W; term_char = c; *p_buf++ = c; /* save the open quote */ for(;;) { switch(CHARMAP(c = GETCH())) { case LX_DQUOTE: case LX_SQUOTE: if(c == (WCHAR)term_char) { *p_buf++ = (WCHAR)term_char;/* save the terminating quote */ goto out_of_loop; } break; case LX_BACKSLASH: *p_buf++ = c; break; case LX_CR: continue; case LX_NL: UNGETCH(); goto out_of_loop; case LX_EOS: if(c == L'\\') { *p_buf++ = c; c = get_non_eof(); break; } handle_eos(); continue; } *p_buf++ = c; if(p_buf >= &Reuse_W[MED_BUFFER - 1]) { *p_buf = L'\0'; myfwrite(Reuse_W, (size_t)(p_buf - Reuse_W) * sizeof(WCHAR), 1, OUTPUTFILE); p_buf = Reuse_W; } } out_of_loop: *p_buf = L'\0'; myfwrite(Reuse_W, (size_t)(p_buf - Reuse_W) * sizeof(WCHAR), 1, OUTPUTFILE); }
/************************************************************************ ** gather_chars : collect chars until a matching one is found. ** skip backslashed chars. moves the chars into the buffer, ** returns a ptr past the last char copied. ************************************************************************/ ptext_t gather_chars(REG ptext_t p, UCHAR match_c) { UCHAR c; *p++ = match_c; for(;;) { if(p > ELIMIT) { return(ELIMIT); } switch(CHARMAP(c = GETCH())) { case LX_NL: Msg_Temp = GET_MSG (2001); SET_MSG (Msg_Text, Msg_Temp); error(2001); UNGETCH(); c = match_c; /* ** FALLTHROUGH */ case LX_DQUOTE: case LX_SQUOTE: if(c == match_c) { *p++ = c; return(p); /* only way out */ } break; case LX_EOS: if(handle_eos() != BACKSLASH_EOS) { continue; } else { /* got backslash */ *p++ = '\\'; c = get_non_eof(); if((c == '\\') && (checknl())) { continue; } } break; case LX_LEADBYTE: *p++ = c; c = get_non_eof(); break; } *p++ = c; } }
/************************************************************************ ** get_non_eof : get a real char. ************************************************************************/ WCHAR get_non_eof(void) { WCHAR c; get_non_eof_again: while((c = GETCH()) <= L'\r') { if(c == L'\r') { continue; } else if(c != EOS_CHAR) { break; } if(Tiny_lexer_nesting > 0) { break; } handle_eos(); } if((c == L'\\') && (checknl())) { goto get_non_eof_again; } return(c); }
/************************************************************************ ** skip_cwhite : while the current character is whitespace or a comment. ** a newline is NOT whitespace. ************************************************************************/ WCHAR skip_cwhite(void) { REG WCHAR c; skip_cwhite_again: while((c = GETCH()) <= L'/') { /* many chars are above this */ if(c == L'/') { if( ! skip_comment()) { return(L'/'); } } else if(c > L' ') { /* char is between '!' and '.' */ return(c); } else { switch(CHARMAP(c)) { case LX_EOS: handle_eos(); break; case LX_WHITE: continue; break; case LX_CR: continue; break; default: return(c); break; } } } if((c == L'\\') && (checknl())) { goto skip_cwhite_again; } return(c); }
/************************************************************************ ** DumpSlashComment : while skipping a comment, output it. ************************************************************************/ void DumpSlashComment(VOID) { if( ! Cflag ) { skip_NLonly(); return; } myfwrite(L"//", 2 * sizeof(WCHAR), 1, OUTPUTFILE); for(;;) { WCHAR c; switch(CHARMAP(c = GETCH())) { // must manually write '\r' with '\n' when writing 16-bit strings //case LX_CR: // continue; case LX_EOS: handle_eos(); continue; case LX_NL: UNGETCH(); return; } myfwrite(&c, sizeof(WCHAR), 1, OUTPUTFILE); } }
/************************************************************************ ** get_actuals : Paren must already be found. If all the actuals can ** be read, the macro is pushed and expansion begins. Otherwise, ** this function is quickly exited and lets the tiny lexer take ** care of rescanning. ************************************************************************/ void get_actuals(pdefn_t pdef, int n_formals) { /* ** The only concern with this is that a rescan could finish while ** this is trying to collect actuals. When a rescan finishes, it ** may reset Act_ptr and Exp_ptr. Unless these are saved before the ** end of rescan is handled, the part of the actual collected so far ** would be lost. */ REG ptext_t start; UCHAR c; ptext_t actuals_start; int paste; int level; *Exp_ptr++ = PREVCH(); /* must be oparen */ level = 0; actuals_start = Act_ptr; while( level >= 0) { if(Exp_ptr >= ELIMIT) { fatal_in_macro(10056); } more_white: if( ! can_get_non_white()) { return; } if(CHARMAP(CHECKCH()) == LX_SLASH) { SKIPCH(); if(skip_comment()) { goto more_white; } else { start = Exp_ptr; *Exp_ptr++ = '/'; } } else { start = Exp_ptr; } paste = FALSE; for(;;) { switch(CHARMAP(c = GETCH())) { case LX_CPAREN: if(--level < 0) { goto leave_loop; } break; case LX_COMMA: /* ** if the comma is not at level == 0, it is part of ** a parenthesized list and not a delimiter */ if(level == 0) { goto leave_loop; } break; case LX_SLASH: if( ! skip_comment()) { break; } if(*(Exp_ptr - 1) == ' ') { continue; } c = ' '; break; case LX_CR: case LX_NL: case LX_WHITE: UNGETCH(); /* This char is valid white space */ if( ! can_get_non_white()) { return; } continue; break; case LX_OPAREN: ++level; break; case LX_DQUOTE: case LX_SQUOTE: Exp_ptr = gather_chars(Exp_ptr, c); continue; break; case LX_ID: *Exp_ptr++ = c; while(LXC_IS_IDENT(c = GETCH())) { if(Exp_ptr >= ELIMIT) { fatal_in_macro(10056); } *Exp_ptr++ = c; } if(CHARMAP(c) != LX_MACFORMAL) { UNGETCH(); continue; } paste = TRUE; /* ** FALLTHROUGH */ case LX_MACFORMAL: move_to_exp(do_macformal(&paste)); continue; break; case LX_STRFORMAL: move_to_exp_esc('"', do_strformal()); continue; break; case LX_CHARFORMAL: move_to_exp_esc('\'', do_strformal()); continue; break; case LX_EOS: /* ** Will saving this pointers create dead space in the ** buffers? Yes, but only temporarily. ** ** handle_eos() may reset Act_ptr and Exp_ptr to the ** beginning of the buffers if a rescan is finishing ** and Macro_depth is going to be 0. ANSI allows ** actuals to start within a macro defintion and be ** completed (further actuals and closing paren) later ** in the text. ** ** These buffer pointers will eventually be reset to ** the beginnings of their respective buffers when the ** macro for the actuals being collected right now ** finish rescan ** ** This is special handling for folks who use ** unbalanced parens in macro definitions */ { ptext_t Exp_save; ptext_t Act_save; int eos_res; Exp_save = Exp_ptr; Act_save = Act_ptr; if((eos_res = handle_eos()) & (ACTUAL_EOS | RESCAN_EOS)) { return; } Act_ptr = Act_save; Exp_ptr = Exp_save; if(eos_res == BACKSLASH_EOS) { /* ??? DFP QUESTION */ *Exp_ptr++ = c; /* save the \ */ c = get_non_eof(); /* get char following \ */ break; } } continue; break; } *Exp_ptr++ = c; } leave_loop: /* ** if the last character was whitespace, hose it */ if(CHARMAP(*(Exp_ptr - 1)) == LX_WHITE) { Exp_ptr--; } /* ** if Exp_ptr <= start, foo() was read, don't incr N_actuals */ if(Exp_ptr > start) { N_actuals++; move_to_actual(start, Exp_ptr); } *Exp_ptr++ = c; } P_actuals = actuals_start; if(n_formals < N_actuals) { Msg_Temp = GET_MSG (4002); SET_MSG (Msg_Text, Msg_Temp, Reuse_1); warning(4002); } else if(n_formals > N_actuals) { Msg_Temp = GET_MSG (4003); SET_MSG (Msg_Text, Msg_Temp, Reuse_1); warning(4003); } if(DEFN_TEXT(pdef)) { push_macro(pdef); expand_macro(); } else { /* ** the macro expands to nothing (no definition) ** This essentially means delete the macro and its actuals ** from the expanded text */ Act_ptr = P_actuals; /* reset pointer to get rid of actuals */ Exp_ptr = Save_Exp_ptr; /* delete macro & actuals from exp text */ } }
/************************************************************************ ** can_expand: tries to expand the macro passed to it - returns ** true if it succeeded in expanding it. It will only return FALSE ** if a macro name was found, a paren was expected, and a paren was ** not the next non white character. ************************************************************************/ int can_expand(pdefn_t pdef) { UCHAR c; int n_formals; int return_value = FALSE; Tiny_lexer_nesting = 0; Save_Exp_ptr = Exp_ptr; /* not necessarily EXP_BUFFER */ Macro_line = Linenumber; expand_name: P_actuals = Act_ptr; N_actuals = 0; n_formals = DEFN_NFORMALS(pdef); if( PRE_DEFINED(pdef) ) { push_macro(pdef); DEFN_EXPANDING(CURRENT_MACRO)++; if(rescan_expansion()) { return(TRUE); /* could expand macro */ } } else if( n_formals == 0 ) { return_value = TRUE; if(DEFN_TEXT(pdef)) { push_macro(pdef); expand_definition(); } else { /* ** Macro expands to nothing (no definition). Since it ** didn't have any actuals, Act_ptr is already correct. ** Exp_ptr must be changed however to delete the ** identifier from the expanded text. */ Exp_ptr = Save_Exp_ptr; } } else { if( n_formals == -1 ) { n_formals = 0; } name_comment_paren: if( can_get_non_white()) { if(CHARMAP(CHECKCH()) == LX_SLASH) { SKIPCH(); if(skip_comment()) { goto name_comment_paren; } else { UNGETCH(); } } if(CHARMAP(CHECKCH())==LX_OPAREN) { SKIPCH(); return_value = TRUE; get_actuals(pdef, n_formals); } else { /* ** #define xx(a) a ** xx bar(); ** don't lose white space between "xx" and "bar" */ ptext_t p = Exp_ptr; push_macro(pdef); DEFN_EXPANDING(CURRENT_MACRO)++; Exp_ptr = p; if( rescan_expansion() ) { return(FALSE); } } } else { } } /* ** makes sure a macro is being worked on. At this point, there will ** be a macro to expand, unless the macro expand_the_named_macro was ** passed had no definition text. If it had no defintion text, ** Tiny_lexer_nesting was not incremented. */ while(Tiny_lexer_nesting != 0) { if(Exp_ptr >= ELIMIT) { fatal_in_macro(10056); } switch(CHARMAP(c = GETCH())) { case LX_ID: case LX_MACFORMAL: Save_Exp_ptr = Exp_ptr; if(tl_getid(c) && ((pdef = get_defined())!= 0)) { if(DEFN_EXPANDING(pdef)) { /* ** the macro is already being expanded, so just ** write the do not expand marker and the ** identifier to the expand area. The do not ** expand marker is necessary so this macro ** doesn't get expanded on the rescan */ int len = Reuse_1_length - 1; *Exp_ptr++ = LX_NOEXPANDMARK; *Exp_ptr++ = ((UCHAR)len); } else { /* ** a legal identifier was read, it is defined, and ** it is not currently being expanded. This means ** there is reason to believe it can be expanded. */ goto expand_name; } } if(InIf &&(memcmp(Reuse_1, "defined", 8) ==0)) { do_defined(Reuse_1); } continue; break; case LX_NUMBER: /* getnum with Prep on to keep leading 0x on number */ { int Save_prep = Prep; Prep = TRUE; getnum(c); Prep = Save_prep; } continue; break; case LX_DOT: *Exp_ptr++ = '.'; dot_switch: switch(CHARMAP(c = GETCH())) { case LX_EOS: if(handle_eos() != BACKSLASH_EOS) { if(Tiny_lexer_nesting > 0) { goto dot_switch; } continue; } break; case LX_DOT: *Exp_ptr++ = '.'; if( ! checkop('.')) { break; /* error will be caught on rescan */ } *Exp_ptr++ = '.'; continue; break; case LX_NUMBER: *Exp_ptr++ = c; get_real(Exp_ptr); continue; } UNGETCH(); continue; case LX_CHARFORMAL: move_to_exp_esc('\'', do_strformal()); continue; break; case LX_STRFORMAL: move_to_exp_esc('"', do_strformal()); continue; break; case LX_DQUOTE: case LX_SQUOTE: /* ** gather_chars is called even though the error reported ** on overflow may need to be changed. */ Exp_ptr = gather_chars(Exp_ptr, c); continue; break; case LX_WHITE: while(LXC_IS_WHITE(GETCH())) { ; } UNGETCH(); c = ' '; break; case LX_EOS: if(handle_eos() == BACKSLASH_EOS) { *Exp_ptr++ = c; c = GETCH(); break; } continue; break; } *Exp_ptr++ = c; } return(return_value); }
/************************************************************************ ** get_definition : accumulate the macro definition, stops when it finds ** a newline (it uses it). returns a ptr to the end of the string it builds. ** builds the string in Macro_buffer. (given the start in P_defn_start) ************************************************************************/ int get_definition(void) { REG ptext_t p; UCHAR c; int stringize = FALSE; int charize = FALSE; p = P_defn_start; c = skip_cwhite(); for(;;) { chkbuf(p); switch(CHARMAP(c)) { case LX_EOS: if(handle_eos() == BACKSLASH_EOS) { /* got backslash EOS */ /* \<anything else> goes out as is. The <anything else> * character must be emitted now, so that * #define FOO(name) \name * . . . * FOO(bar) * * does NOT see occurence of name in the definition as an * occurence of the formal param and emit \bar when it is * expanded later,but if the definition is \nname it will * find name as a formal paramater and emit \nbar */ *p++ = c; /* put in backslash, break'll add new char */ c = get_non_eof(); } else { c = GETCH(); continue; } break; case LX_NL: /* only way out */ UNGETCH(); if(p == P_defn_start) { return(0); } chkbuf(p); *p++ = EOS_CHAR; *p++ = EOS_DEFINITION; /* tells handle_eos defn finished */ return(p - P_defn_start);/* p's last incr counts the 0*/ break; case LX_DQUOTE: case LX_SQUOTE: p = gather_chars(p, c); c = GETCH(); continue; break; case LX_POUND: split_op: switch(CHARMAP(GETCH())) { case LX_POUND: /* ** handle ## processing. cant be the first or the last. */ if(p == P_defn_start) { Msg_Temp = GET_MSG (2160); SET_MSG (Msg_Text, Msg_Temp); error(2160); /* ## not allowed as first entry */ continue; } if(*(p - 1) == ' ') { /* hose the last blank */ p--; } if(CHARMAP(c = skip_cwhite()) == LX_NL) { UNGETCH(); Msg_Temp = GET_MSG (2161); SET_MSG (Msg_Text, Msg_Temp); error(2161); continue; } /* this case does *not* fall through to LX_ID */ continue; break; case LX_EACH: charize = TRUE; break; case LX_EOS: if( handle_eos() != BACKSLASH_EOS ) { goto split_op; } /* ** FALLTHROUGH */ default: UNGETCH(); stringize = TRUE; break; } if(CHARMAP(c = skip_cwhite()) != LX_ID) { Msg_Temp = GET_MSG (2162); SET_MSG (Msg_Text, Msg_Temp); error(2162); /* must have id following */ continue; } /* ** FALLTHROUGH */ case LX_ID: { /* we have the start of an identifier - check it to see if * its an occurence of a formal parameter name. * we gather the id ourselves (instead of getid()) since this * wil save us from having to copy it to our string if it's * not a formal parameter. */ int n; ptext_t p_macformal; p_macformal = p; do { chkbuf(p); *p++ = c; get_more_id: c = GETCH(); } while(LXC_IS_IDENT(c)); if(CHARMAP(c) == LX_EOS) { if(handle_eos() != BACKSLASH_EOS) { goto get_more_id; } } *p = '\0'; /* term. string, but do not advance ptr */ if((n = is_macro_arg(p_macformal)) >= 1) { /* ** this is an occurance of formal 'n', replace the id with ** the special MAC character. */ p = p_macformal; if(stringize) { *p++ = LX_FORMALSTR; } else { if(charize) { *p++ = LX_FORMALCHAR; } else { *p++ = LX_FORMALMARK; } } *p++ = (UCHAR) n; } else if(charize || stringize) { Msg_Temp = GET_MSG (2162); SET_MSG (Msg_Text, Msg_Temp); error(2162); } stringize = FALSE; charize = FALSE; continue; /* we broke out of the loop with a new char */ } case LX_SLASH: if( ! skip_comment() ) { /* really is a slash */ break; } /* ** FALLTHROUGH */ case LX_CR: case LX_WHITE: /* ** this is white space, all contiguous whitespace is transformed ** to 1 blank. (hence the skip_cwhite() and the continue). */ if(CHARMAP(c = skip_cwhite()) != LX_NL) { *p++ = ' '; } continue; /* restart loop */ case LX_ILL: Msg_Temp = GET_MSG (2018); SET_MSG (Msg_Text, Msg_Temp, c); error(2018); c = GETCH(); continue; } *p++ = c; c = GETCH(); } }
/************************************************************************ ** BEGIN DEFINE A MACRO { ************************************************************************/ void define(void) { UCHAR c; if (! (LX_IS_IDENT(c = skip_cwhite())) ) { Msg_Temp = GET_MSG (2007); SET_MSG (Msg_Text, Msg_Temp); error (2007); /* #define syntax */ skip_cnew(); return; } getid(c); N_formals = 0; P_defn_start = Macro_buffer; /* ** the next character must be white space or an open paren */ first_switch: switch(CHARMAP(c = GETCH())) { case LX_OPAREN: /* we have formal parameters */ get_formals(); /* changes N_formals and fills Macro_buffer */ if(N_formals == 0) {/* empty formal list */ /* ** we must special case this since the expand() reads in the ** actual arguments iff there are formal parameters. thus if we ** #define foo() bar() ** . . . ** foo() ** will expand as ** bar()() ** we put the right paren in to fool the expander into looking ** for actuals. */ N_formals = -1; } break; case LX_WHITE: break; case LX_CR: goto first_switch; case LX_SLASH: if( ! skip_comment()) { Msg_Temp = GET_MSG (2008); SET_MSG (Msg_Text, Msg_Temp, '/'); error (2008); } break; case LX_NL: /* no definition */ UNGETCH(); definstall((ptext_t)0, 0, 0); return; break; case LX_EOS: if(handle_eos() != BACKSLASH_EOS) { goto first_switch; } /* got BACKSLASH_EOS */ /* ** FALLTHROUGH */ default: Msg_Temp = GET_MSG (2008); SET_MSG (Msg_Text, Msg_Temp, c); error (2008); /* unexpected character in macro definition */ } definstall(P_defn_start, get_definition(), N_formals); }
int fc_solve_initial_user_state_to_c( const char * string, fcs_state_with_locations_t * out_state, int freecells_num, int stacks_num, int decks_num #ifdef FCS_WITH_TALONS ,int talon_type #endif #ifdef INDIRECT_STACK_STATES , char * indirect_stacks_buffer #endif ) { fcs_state_with_locations_t ret_with_locations; int s,c; const char * str; fcs_card_t card; int first_line; int prefix_found; const char * const * prefixes; int i; int decks_index[4]; fcs_state_init( &ret_with_locations, stacks_num #ifdef INDIRECT_STACK_STATES , indirect_stacks_buffer #endif ); str = string; first_line = 1; #define ret (ret_with_locations.s) /* Handle the end of string - shouldn't happen */ #define handle_eos() \ { \ if ((*str) == '\0') \ { \ return FCS_USER_STATE_TO_C__PREMATURE_END_OF_INPUT; \ } \ } #ifdef FCS_WITH_TALONS if (talon_type == FCS_TALON_KLONDIKE) { fcs_klondike_talon_num_redeals_left(ret) = -1; } #endif for(s=0;s<stacks_num;s++) { /* Move to the next stack */ if (!first_line) { while((*str) != '\n') { handle_eos(); str++; } str++; } first_line = 0; prefixes = freecells_prefixes; prefix_found = 0; for(i=0;prefixes[i][0] != '\0'; i++) { if (!strncasecmp(str, prefixes[i], strlen(prefixes[i]))) { prefix_found = 1; str += strlen(prefixes[i]); break; } } if (prefix_found) { for(c=0;c<freecells_num;c++) { fcs_empty_freecell(ret, c); } for(c=0;c<freecells_num;c++) { if (c!=0) { while( ((*str) != ' ') && ((*str) != '\t') && ((*str) != '\n') && ((*str) != '\r') ) { handle_eos(); str++; } if ((*str == '\n') || (*str == '\r')) { break; } str++; } while ((*str == ' ') || (*str == '\t')) { str++; } if ((*str == '\r') || (*str == '\n')) break; if ((*str == '*') || (*str == '-')) { card = fcs_empty_card; } else { card = fcs_card_user2perl(str); } fcs_put_card_in_freecell(ret, c, card); } while (*str != '\n') { handle_eos(); str++; } s--; continue; } prefixes = foundations_prefixes; prefix_found = 0; for(i=0;prefixes[i][0] != '\0'; i++) { if (!strncasecmp(str, prefixes[i], strlen(prefixes[i]))) { prefix_found = 1; str += strlen(prefixes[i]); break; } } if (prefix_found) { int d; for(d=0;d<decks_num*4;d++) { fcs_set_foundation(ret, d, 0); } for(d=0;d<4;d++) { decks_index[d] = 0; } while (1) { while((*str == ' ') || (*str == '\t')) str++; if ((*str == '\n') || (*str == '\r')) break; d = fcs_u2p_suit(str); str++; while (*str == '-') str++; c = fcs_u2p_card_number(str); while ( (*str != ' ') && (*str != '\t') && (*str != '\n') && (*str != '\r') ) { handle_eos(); str++; } fcs_set_foundation(ret, (decks_index[d]*4+d), c); decks_index[d]++; if (decks_index[d] >= decks_num) { decks_index[d] = 0; } } s--; continue; } #ifdef FCS_WITH_TALONS prefixes = talon_prefixes; prefix_found = 0; for(i=0;prefixes[i][0] != '\0'; i++) { if (!strncasecmp(str, prefixes[i], strlen(prefixes[i]))) { prefix_found = 1; str += strlen(prefixes[i]); break; } } if (prefix_found) { /* Input the Talon */ int talon_size; talon_size = MAX_NUM_DECKS*52+16; ret.talon = malloc(sizeof(fcs_card_t)*talon_size); fcs_talon_pos(ret) = 0; for(c=0 ; c < talon_size ; c++) { /* Move to the next card */ if (c!=0) { while( ((*str) != ' ') && ((*str) != '\t') && ((*str) != '\n') && ((*str) != '\r') ) { handle_eos(); str++; } if ((*str == '\n') || (*str == '\r')) { break; } } while ((*str == ' ') || (*str == '\t')) { str++; } if ((*str == '\n') || (*str == '\r')) { break; } card = fcs_card_user2perl(str); fcs_put_card_in_talon(ret, c+(talon_type==FCS_TALON_KLONDIKE), card); } fcs_talon_len(ret) = c; if (talon_type == FCS_TALON_KLONDIKE) { int talon_len; talon_len = fcs_talon_len(ret); fcs_klondike_talon_len(ret) = talon_len; fcs_klondike_talon_stack_pos(ret) = -1; fcs_klondike_talon_queue_pos(ret) = 0; } s--; continue; } prefixes = num_redeals_prefixes; prefix_found = 0; for(i=0;prefixes[i][0] != '\0'; i++) { if (!strncasecmp(str, prefixes[i], strlen(prefixes[i]))) { prefix_found = 1; str += strlen(prefixes[i]); break; } } if (prefix_found) { while ((*str < '0') && (*str > '9') && (*str != '\n')) { handle_eos(); str++; } if (*str != '\n') { int num_redeals; num_redeals = atoi(str); if (talon_type == FCS_TALON_KLONDIKE) { fcs_klondike_talon_num_redeals_left(ret) = (num_redeals < 0) ? (-1) : ((num_redeals > 127) ? 127 : num_redeals) ; } } s--; continue; } #endif for(c=0 ; c < MAX_NUM_CARDS_IN_A_STACK ; c++) { /* Move to the next card */ if (c!=0) { while( ((*str) != ' ') && ((*str) != '\t') && ((*str) != '\n') && ((*str) != '\r') ) { handle_eos(); str++; } if ((*str == '\n') || (*str == '\r')) { break; } } while ((*str == ' ') || (*str == '\t')) { str++; } if ((*str == '\n') || (*str == '\r')) { break; } card = fcs_card_user2perl(str); fcs_push_card_into_stack(ret, s, card); } } *out_state = ret_with_locations; return FCS_USER_STATE_TO_C__SUCCESS; }