/*{{{  #includes*/
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>

#include <local/bool.h>

#define PARSECOND_C

#include "keybind.h"
/*}}}  */

/*{{{  parse_cond*/
/*{{{  l_parse_cond*/
private TOKEN* l_parse_cond(TOKEN *buff,tokens to,bool allow_comma, bool *ret_used)
{
  for (;;)
   { switch(to) {
       /*{{{  comma*/
       case COMMA:
        { if (allow_comma)
           /*{{{  ignore it*/
           { to=get_token(FALSE);
             continue;
           }
           /*}}}  */
          else
           /*{{{  error*/
           { error_po();
             fprintf(stderr,M_NOTEST);
             return(0);
           }
           /*}}}  */
        }
       /*}}}  */
       /*{{{  single tests*/
       case EDITING:         *buff++ = M_EDITING;            break;
       case TEST_FILED:      *buff++ = M_FILED_FOLD;         break;
       case TEST_FOLD_LINE:  *buff++ = M_CLOSED_FOLD;        break;
       case TEST_BEGIN_FOLD: *buff++ = M_BEGIN_FOLD_COMMENT; break;
       case TEST_END_FOLD:   *buff++ = M_END_FOLD_COMMENT;   break;
       case TEST_TEXT:       *buff++ = M_TEXTLINE;           break;
       case TEST_TOP:        *buff++ = M_TOP_OF_FOLD;        break;
       case TEST_BOTTOM:     *buff++ = M_BOT_OF_FOLD;        break;
       case TEST_BEGIN_LINE: *buff++ = M_BEGIN_OF_LINE;      break;
       case TEST_END_LINE:   *buff++ = M_END_OF_LINE;        break;
       case TEST_CHANGED:    *buff++ = M_CHANGED;            break;
       case TEST_OVER:       *buff++ = M_TEST_OVER;          break;
       case TEST_VIEW:       *buff++ = M_TEST_VIEW;          break;
       case TEST_AUTO:       *buff++ = M_TEST_AUTO;          break;
       case TEST_ECHO:       *buff++ = M_TEST_ECHO;          break;
       /*}}}  */
       /*{{{  test with one counter/term argument*/
       case TEST_CHAR_LOW_C:
       case TEST_CHAR_HIGH_C:
       case TEST_CHAR_C:
       case TEST_BEHIND_COUNTER:
       case COUNTER_NULL:
       case C_POSITIV:
        { tokens token=name_to_var(get_token(FALSE),new_vars_enabled);
          bool d=FALSE;

          if (token!=VARIABLE)
           { if (!(buff=parse_term(token,buff,dummy_var(0),ret_used))) return(0);
             d=TRUE;
           }
          *buff++ = (to==COUNTER_NULL)        ? M_NULL_COUNTER :
                    (to==TEST_CHAR_C)         ? M_TEST_CC :
                    (to==TEST_CHAR_HIGH_C)    ? M_TEST_H_CC :
                    (to==TEST_CHAR_LOW_C)     ? M_TEST_L_CC :
                    (to==TEST_BEHIND_COUNTER) ? M_BEHIND_COUNTER_X_POS :
                                                M_POSITIV_COUNTER;
          *buff++=(TOKEN)(d?dummy_var(0):tk_var->no);
          break;
        }
       /*}}}  */
       /*{{{  testset*/
       case TEST_CHAR_SET:
         *buff++ = M_TEST_CHAR_SET;
         if ((*buff++ = get_set())==UNDEFINED_SET) return(0);
         break;
       /*}}}  */
       /*{{{  tests with one char argument*/
       case TEST_LANG:
       case TEST_CHAR:
       case TEST_CHAR_LOW:
       case TEST_CHAR_HIGH:
         *buff++ = (to==TEST_CHAR)      ? M_TEST_CHAR :
                   (to==TEST_CHAR_LOW)  ? M_TEST_CHAR_LOW :
                   (to==TEST_LANG)      ? M_LANGUAGE :
                                          M_TEST_CHAR_HIGH;
         /*{{{  parse the char*/
         if ((to=get_token(TRUE))!=CHAR) {
           if (to!=ERROR) {
             error_po();
             fprintf(stderr,M_TCNEEDSCHAR);
           }
           return(0);
         }
         /*}}}  */
         if (*(buff-1)==M_LANGUAGE)
            *buff++ = (TOKEN) (toupper(tk_char));
         else
            *buff++ = (TOKEN) tk_char;
         break;
       /*}}}  */
       /*{{{  not condition*/
       case NOT:
         if (begin_parse()) return(0);
         if (!(buff=l_parse_cond(buff,get_token(FALSE),FALSE,ret_used)))
            return(0);
         *buff++ = M_NOT;
         if (end_parse(M_WANTEND)) return(0);
         break;
       /*}}}  */
       /*{{{  and/or (c[,c...])*/
       case AND:
       case OR: {
         TOKEN jmp= to==AND ? M_JMP_FALSE : M_JMP_TRUE;
         TOKEN *bp=0;

         if (begin_parse()) return(0);
         if (!(buff=l_parse_cond(buff,get_token(FALSE),TRUE,ret_used)))
            return(0);
         bp=buff;
         /*{{{  scan all and-arguments up to )*/
         while ((to=get_token(FALSE))!=END) {
           if (!(buff=generate_jmp(jmp,buff,bp))) return(0);
           if (!(buff=l_parse_cond(buff,to,TRUE,ret_used))) return(0);
         }
         /*}}}  */
         if (to!=END) {
           error_po();
           fprintf(stderr,M_WANTEND);
           return(0);
         }
         /*{{{  backpatch the jumps*/
         if (!generate_jmp(jmp,bp,buff)) return(0);
         /*}}}  */
         break;
       }
       /*}}}  */
       /*{{{  pre*/
       case PRE: {
         bool dummy;

         if (!(buff=parse_macro(buff,&dummy))) return(0);
         if (!(buff=l_parse_cond(buff,get_token(FALSE),FALSE,ret_used)))
            return(0);
         break;
       }
       /*}}}  */
       case ERROR: return(0);
       /*{{{  lastmessage*/
       case LASTMES:
        { *buff++ = M_LASTMES;
          if (get_token(FALSE)==NAME)
           /*{{{  look for msg*/
           { int x=0;

             while (msg_list[x])
                if (strcmp(tk_string,msg_list[x])) x++; else break;
             if (msg_list[x]) { *buff++ = x+1; break; }
           }
           /*}}}  */
          error_po();
          fprintf(stderr,M_NOTEST);
          return(0);
        }
       /*}}}  */
       /*{{{  variable: compile it like ``not(counter-0 variable)''*/
       case VARIABLE:
         *buff++ = M_NULL_COUNTER;
         *buff++ = (TOKEN) tk_var->no;
         *buff++ = M_NOT;
         break;
       /*}}}  */
       /*{{{  default use it as term*/
       default:
          if (!(buff=parse_term(to,buff,dummy_var(0),ret_used))) return(0);
          *buff++ = M_NULL_COUNTER;
          *buff++ = (TOKEN) dummy_var(0);
          *buff++ = M_NOT;
          break;
       /*}}}  */
     }
     return(buff);
   }
}
/*}}}  */

public TOKEN *parse_cond(TOKEN *buff,bool *ret_used)
{ return(l_parse_cond(buff,name_to_var(get_token(FALSE),new_vars_enabled),FALSE,ret_used)); }
/*}}}  */
