Exemple #1
0
void parse(void) {

  parse_fail = 0;
  checked(char* token = parse_string());

  if ( *token == '\0' )           return;
  else if ( TOKEN_IS("SET"))      parse_set();
  else if ( TOKEN_IS("GET"))      parse_get();
  else if ( TOKEN_IS("HELLO"))    { }
  else if ( TOKEN_IS("COMMIT"))   eeprom_commit();

  //  else if ( TOKEN_IS("SELFTEST")) selftest_perform();
  else                            { parse_fail = 1; uart_puts_P(" UNKNOWN COMMAND"); }

#ifdef COMMANDLINE_DEBUG
  // string fully consumed?
  if ( *current_pos != '\0' )  {
	parse_fail = 1;
	uart_puts_P("too much input: "); 
	uart_puts(current_pos);
	uart_puts_P(NEWLINE);
  }
#endif

  if ( parse_fail ) uart_puts_P("FAIL"); 
  else uart_puts_P("OK");

  uart_puts_P(NEWLINE);

}
Exemple #2
0
int build_parse_set(Sentence sent, int cost, Parse_Options opts) {
    /* This is the top level call that computes the whole parse_set.  It
       points whole_set at the result.  It creates the necessary hash
       table (x_table) which will be freed at the same time the
       whole_set is freed.

       It also assumes that count() has been run, and that hash table is
       filled with the values thus computed.  Therefore this function
       must be structured just like parse() (the main function for
       count()).  
       
       If the number of linkages gets huge, then the counts can overflow.
       We check if this has happened when verifying the parse set.
       This routine returns TRUE iff overflowed occurred.
    */

    Parse_set * whole_set;

    local_sent = sent->word;
    islands_ok = opts->islands_ok;

    whole_set = 
        parse_set(NULL, NULL, -1, sent->length, NULL, NULL, cost+1, sent->parse_info);

    if ((whole_set != NULL) && (whole_set->current != NULL)) {
	whole_set->current = whole_set->first;
    }

    sent->parse_info->parse_set = whole_set;

    local_sent = NULL;
    return verify_set(sent->parse_info);  
}
int build_parse_set(Sentence sent, int cost, Parse_Options opts)
{
	Parse_set * whole_set;

	whole_set =
		parse_set(sent, NULL, NULL, -1, sent->length, NULL, NULL, cost+1,
		          opts->islands_ok, sent->parse_info);

	if ((whole_set != NULL) && (whole_set->current != NULL)) {
		whole_set->current = whole_set->first;
	}

	sent->parse_info->parse_set = whole_set;

	return verify_set(sent->parse_info);
}
Exemple #4
0
int assemble(struct _asm_context *asm_context)
{
  char token[TOKENLEN];
  int token_type;

  while(1)
  {
    token_type = tokens_get(asm_context, token, TOKENLEN);
#ifdef DEBUG
    printf("%d: <%d> %s\n", asm_context->line, token_type, token);
#endif
    if (token_type == TOKEN_EOF) break;

    if (token_type == TOKEN_EOL)
    {
      if (asm_context->macros.stack_ptr == 0) { asm_context->line++; }
    }
      else
    if (token_type == TOKEN_LABEL)
    {
      int param_count_temp;
      if (macros_lookup(&asm_context->macros, token, &param_count_temp) != NULL)
      {
        print_already_defined(asm_context, token);
        return -1;
      }

      if (symbols_append(&asm_context->symbols, token, asm_context->address / asm_context->bytes_per_address) == -1)
      {
        return -1;
      }
    }
      else
    if (token_type == TOKEN_POUND || IS_TOKEN(token,'.'))
    {
      token_type = tokens_get(asm_context, token, TOKENLEN);
#ifdef DEBUG
    printf("%d: <%d> %s\n", asm_context->line, token_type, token);
#endif
      if (token_type == TOKEN_EOF) break;

      if (strcasecmp(token, "define") == 0)
      {
        if (macros_parse(asm_context, IS_DEFINE) != 0) return -1;
      }
        else
      if (strcasecmp(token, "ifdef") == 0)
      {
        parse_ifdef(asm_context, 0);
      }
        else
      if (strcasecmp(token, "ifndef") == 0)
      {
        parse_ifdef(asm_context, 1);
      }
        else
      if (strcasecmp(token, "if") == 0)
      {
        parse_if(asm_context);
      }
        else
      if (strcasecmp(token, "endif") == 0)
      {
        if (asm_context->ifdef_count < 1)
        {
          printf("Error: unmatched .endif at %s:%d\n", asm_context->filename, asm_context->ifdef_count);
          return -1;
        }
        return 0;
      }
        else
      if (strcasecmp(token, "else") == 0)
      {
        if (asm_context->ifdef_count < 1)
        {
          printf("Error: unmatched .else at %s:%d\n", asm_context->filename, asm_context->ifdef_count);
          return -1;
        }
        return 2;
      }
        else
      if (strcasecmp(token, "include") == 0)
      {
        if (parse_include(asm_context) != 0) return -1;
      }
        else
      if (strcasecmp(token, "binfile") == 0)
      {
        if (parse_binfile(asm_context) != 0) return -1;
      }
        else
      if (strcasecmp(token, "code") == 0)
      {
        asm_context->segment = SEGMENT_CODE;
      }
        else
      if (strcasecmp(token, "bss") == 0)
      {
        asm_context->segment = SEGMENT_BSS;
      }
        else
      if (strcasecmp(token, "msp430_cpu4") == 0)
      {
        asm_context->msp430_cpu4 = 1;
      }
        else
      if (strcasecmp(token, "macro") == 0)
      {
        if (macros_parse(asm_context, IS_MACRO) != 0) return -1;
      }
        else
      if (strcasecmp(token, "pragma") == 0)
      {
        if (parse_pragma(asm_context) != 0) return -1;
      }
        else
      if (strcasecmp(token, "device") == 0)
      {
        if (parse_device(asm_context) != 0) return -1;
      }
        else
      if (strcasecmp(token, "set") == 0)
      {
        if (parse_set(asm_context) != 0) return -1;
      }
        else
      if (strcasecmp(token, "export") == 0)
      {
        if (parse_export(asm_context) != 0) return -1;
      }
        else
      if (strcasecmp(token, "equ") == 0 || strcasecmp(token, "def")==0)
      {
        if (parse_equ(asm_context) != 0) return -1;
      }
        else
      {
        int ret = check_for_directive(asm_context, token);
        if (ret == 2) break;
        if (ret == -1) return -1;
        if (ret != 1)
        {
          printf("Error: Unknown directive '%s' at %s:%d.\n", token, asm_context->filename, asm_context->line);
          return -1;
        }
      }
    }
      else
    if (token_type == TOKEN_STRING)
    {
      int ret = check_for_directive(asm_context, token);
      if (ret == 2) break;
      if (ret == -1) return -1;
      if (ret != 1) 
      {
        int start_address = asm_context->address;
        char token2[TOKENLEN];
        int token_type2;

        token_type2 = tokens_get(asm_context, token2, TOKENLEN);

        if (strcasecmp(token2, "equ") == 0)
        {
          //token_type2 = tokens_get(asm_context, token2, TOKENLEN);
          int ptr = 0;
          int ch = '\n';

          while(1)
          {
            ch = tokens_get_char(asm_context);
            if (ch == EOF || ch == '\n') break;
            if (ch == '*' && ptr > 0 && token2[ptr-1] == '/')
            {
              macros_strip_comment(asm_context);
              ptr--;
              continue;
            }

            token2[ptr++] = ch;
            if (ptr == TOKENLEN-1)
            {
              printf("Internal Error: token overflow at %s:%d.\n", __FILE__, __LINE__);
              return -1;
            }
          }
          token2[ptr] = 0;
          tokens_unget_char(asm_context, ch);
          macros_strip(token2);
          macros_append(asm_context, token, token2, 0);
        }
          else
        {
          tokens_push(asm_context, token2, token_type2);

          ret = asm_context->parse_instruction(asm_context, token);

          if (asm_context->pass == 2 &&
              asm_context->list != NULL &&
              asm_context->include_count == 0)
          {
            asm_context->list_output(asm_context, start_address);
            fprintf(asm_context->list, "\n");
          }

          if (ret < 0) return -1;

          if (asm_context->macros.stack_ptr == 0) { asm_context->line++; }
          asm_context->instruction_count++;

          if (asm_context->address > start_address)
          {
            asm_context->code_count += (asm_context->address - start_address);
          }
        }
      }
    }
      else
    {
      print_error_unexp(token, asm_context);
      return -1;
    }
  }

  if (asm_context->error == 1) { return -1; }

  return 0;
}
Exemple #5
0
static foreign_t
pl_new_order_table(term_t name, term_t options)
{ OrdTable t = malloc(sizeof(ordtable));
  term_t tail = PL_copy_term_ref(options);
  term_t head = PL_new_term_ref();

  exact_table(t);

  if ( !PL_get_atom(name, &t->name) )
  { free(t);
    return error(ERR_INSTANTIATION, "new_order_table/2", 1, name);
  }

  while(PL_get_list(tail, head, tail))
  { atom_t name;
    int arity;

    if ( PL_get_name_arity(head, &name, &arity) )
    { if ( name == ATOM_case_insensitive )
      { case_insensitive_table(t);
      } else if ( name == ATOM_iso_latin_1 )
      { iso_latin_1_table(t);
      } else if ( name == ATOM_iso_latin_1_case_insensitive )
      { iso_latin_1_case_table(t);
      } else if ( name == ATOM_copy && arity == 1 )
      { term_t a = PL_new_term_ref();
	OrdTable from;

	_PL_get_arg(1, head, a);
	if ( get_order_table(a, &from) )
	{ copy_table(t, from);
	} else
	{ free(t);
	  return FALSE;
	}
      } else if ( arity == 1 )
      { fid_t fid = PL_open_foreign_frame();
	term_t a = PL_new_term_ref();

	_PL_get_arg(1, head, a);
	if ( !parse_set(t, name, a) )
	  goto err1;

	PL_close_foreign_frame(fid);
      } else if ( name == ATOM_eq && arity == 2 )
      { fid_t fid = PL_open_foreign_frame();
	term_t c = PL_new_term_ref();
	int from, to;

	if ( !PL_get_arg(1, head, c) || !get_char(c, &from) ||
	     !PL_get_arg(2, head, c) || !get_char(c, &to) )
	{ free(t);
	  return FALSE;
	}

	ORD(t, from) = to;

	PL_close_foreign_frame(fid);
      } else
	goto err1;
    } else
    { err1:
      free(t);
      return error(ERR_INSTANTIATION, "new_order_table/2", 2, options);
    }
  }
  if ( !PL_get_nil(tail) )
    goto err1;

  register_table(t);

  PL_succeed;
}
/* Parser entry point.  Opens and parses the test sets in the given file.
 */
struct TestFile *parse_test_file(const char *path)
{
    struct TestFile *tf = NEW0(struct TestFile);

    tf->fd = open(path, O_RDONLY);
    if (tf->fd == -1) {
        fprintf(stderr, "Opening file %s: %s\n", path, strerror(errno));
        return NULL;
    }
    tf->path = path;

    if (fstat(tf->fd, &tf->statbuf)) {
        fprintf(stderr, "Stat file %s: %s\n", path, strerror(errno));
        goto close_it;
    }
    if (tf->statbuf.st_size < 1) {
        fprintf(stderr, "File %s is empty!\n", path);
        goto close_it;
    }

    tf->file_buf =
        (char *)mmap(NULL, tf->statbuf.st_size, PROT_READ, MAP_SHARED, tf->fd, 0);
    if (!tf->file_buf) {
        fprintf(stderr, "Mapping file %s: %s\n", path, strerror(errno));
        goto close_it;
    }
    tf->file_end = tf->file_buf + tf->statbuf.st_size;

    if (!next_line(tf)) {
        syntax_error(tf);
        goto close_it;
    }

    for (;;) {
        size_t toklen;
        char *token = next_token(tf, &toklen);
        if (same_token("set", 3, token, toklen)) {
            struct TestSet *set = parse_set(tf);
            if (!set) // parse failure already reported
                goto close_it;
            set->next = tf->sets;
            tf->sets = set;
        } else if (token == END_OF_LINE) {
            if (!next_line(tf)) { // EOF
                if (!tf->sets) {
                    goto no_sets;
                }
                goto done;
            }
            // else swallow blank line
        } else {
no_sets:
            fail(tf, tf->read_pos, "expected a test set");
            goto close_it;
        }
    }

 close_it:
    if (tf->sets) {
        free_sets(tf->sets);
        tf->sets = NULL;
    }
    close_testfile(tf);
 done:
    return tf;
}
Exemple #7
0
Parse_set * parse_set(Disjunct *ld, Disjunct *rd, int lw, int rw, 
		      Connector *le, Connector *re, int cost, Parse_info * pi) {
    /* returns NULL if there are no ways to parse, or returns a pointer
       to a set structure representing all the ways to parse */

    Disjunct * d, * dis;
    int start_word, end_word, w;
    int lcost, rcost, Lmatch, Rmatch;
    int i, j;
    Parse_set *ls[4], *rs[4], *lset, *rset;
    Parse_choice * a_choice;

    Match_node * m, *m1;
    X_table_connector *xt;
    int count;

    assert(cost >= 0, "parse_set() called with cost < 0.");

    count = table_lookup(lw, rw, le, re, cost);

    /*
      assert(count >= 0, "parse_set() called on params that were not in the table.");
      Actually, we can't assert this, because of the pseudocount technique that's
      used in count().  It's not the case that every call to parse_set() has already
      been put into the table.
     */

    if ((count == 0) || (count == -1)) return NULL;
    
    xt = x_table_pointer(lw, rw, le, re, cost, pi);

    if (xt == NULL) {
	xt = x_table_store(lw, rw, le, re, cost, empty_set(), pi);
	/* start it out with the empty set of options */
	/* this entry must be updated before we return */
    } else {
	return xt->set;  /* we've already computed it */
    }

    xt->set->count = count;  /* the count we already computed */
    /* this count is non-zero */
    
    if (rw == 1+lw) return xt->set;
    if ((le == NULL) && (re == NULL)) {
	if (!islands_ok && (lw != -1)) {
	    return xt->set;
	}
	if (cost == 0) {
	    return xt->set;
	} else {
	    w = lw+1;
	    for (dis = local_sent[w].d; dis != NULL; dis = dis->next) {
		if (dis->left == NULL) {
		    rs[0] = parse_set(dis, NULL, w, rw, dis->right, NULL, cost-1, pi);
		    if (rs[0] == NULL) continue;
		    a_choice = make_choice(dummy_set(), lw, w, NULL, NULL,
					   rs[0], w, rw, NULL, NULL,
					   NULL, NULL, NULL);
		    put_choice_in_set(xt->set, a_choice);
		}
	    }
	    rs[0] = parse_set(NULL, NULL, w, rw, NULL, NULL, cost-1, pi); 
	    if (rs[0] != NULL) {
		a_choice = make_choice(dummy_set(), lw, w, NULL, NULL,
				       rs[0], w, rw, NULL, NULL,
				       NULL, NULL, NULL);
		put_choice_in_set(xt->set, a_choice);
	    }
	    return xt->set;
	}
    }
    
    if (le == NULL) {
	start_word = lw+1;
    } else {
	start_word = le->word;

    }

    if (re == NULL) {
	end_word = rw-1;
    } else {
	end_word = re->word;
    }
    
    for (w=start_word; w <= end_word; w++) {
	m1 = m = form_match_list(w, le, lw, re, rw); 
	for (; m!=NULL; m=m->next) {
	    d = m->d;
	    for (lcost = 0; lcost <= cost; lcost++) {
		rcost = cost-lcost;
		/* now lcost and rcost are the costs we're assigning to those parts respectively */

		/* Now, we determine if (based on table only) we can see that
		   the current range is not parsable. */

		Lmatch = (le != NULL) && (d->left != NULL) && match(le, d->left, lw, w);
		Rmatch = (d->right != NULL) && (re != NULL) && match(d->right, re, w, rw);
		for (i=0; i<4; i++) {ls[i] = rs[i] = NULL;}
		if (Lmatch) {
		    ls[0] = parse_set(ld, d, lw, w, le->next, d->left->next, lcost, pi);
		    if (le->multi) ls[1] = parse_set(ld, d, lw, w, le, d->left->next, lcost, pi);
		    if (d->left->multi) ls[2] = parse_set(ld, d, lw, w, le->next, d->left, lcost, pi);
		    if (le->multi && d->left->multi) ls[3] = parse_set(ld, d, lw, w, le, d->left, lcost, pi);
		}
		if (Rmatch) {
		    rs[0] = parse_set(d, rd, w, rw, d->right->next, re->next, rcost, pi);
		    if (d->right->multi) rs[1] = parse_set(d, rd, w,rw,d->right,re->next, rcost, pi);
		    if (re->multi) rs[2] = parse_set(d, rd, w, rw, d->right->next, re, rcost, pi);
		    if (d->right->multi && re->multi) rs[3] = parse_set(d, rd, w, rw, d->right, re, rcost, pi);
		}

		for (i=0; i<4; i++) {
		    /* this ordering is probably not consistent with that needed to use list_links */
		    if (ls[i] == NULL) continue;
		    for (j=0; j<4; j++) {
			if (rs[j] == NULL) continue;
			a_choice = make_choice(ls[i], lw, w, le, d->left,
					       rs[j], w, rw, d->right, re,
					       ld, d, rd);
			put_choice_in_set(xt->set, a_choice);
		    }
		}
		
		if (ls[0] != NULL || ls[1] != NULL || ls[2] != NULL || ls[3] != NULL) {
		    /* evaluate using the left match, but not the right */
		    rset = parse_set(d, rd, w, rw, d->right, re, rcost, pi);
		    if (rset != NULL) {
			for (i=0; i<4; i++) {
			    if (ls[i] == NULL) continue;
			    /* this ordering is probably not consistent with that needed to use list_links */
			    a_choice = make_choice(ls[i], lw, w, le, d->left,
						   rset, w, rw, NULL /* d->right */, re,  /* the NULL indicates no link*/
						   ld, d, rd);
			    put_choice_in_set(xt->set, a_choice);
			}
		    }
		}
		if ((le == NULL) && (rs[0] != NULL || rs[1] != NULL || rs[2] != NULL || rs[3] != NULL)) {
		    /* evaluate using the right match, but not the left */
		    lset = parse_set(ld, d, lw, w, le, d->left, lcost, pi);

		    if (lset != NULL) {
			for (i=0; i<4; i++) {
			    if (rs[i] == NULL) continue;
			    /* this ordering is probably not consistent with that needed to use list_links */
			    a_choice = make_choice(lset, lw, w, NULL /* le */, d->left,  /* NULL indicates no link */
						   rs[i], w, rw, d->right, re,
						   ld, d, rd);
			    put_choice_in_set(xt->set, a_choice);
			}
		    }
		}
	    }
	}
	put_match_list(m1);
    }
    xt->set->current = xt->set->first;
    return xt->set;
}
Exemple #8
0
/* Parse an incoming message. Note that the protocol might have sent this
 * directly over the network (ie. TIPC) or might have wrapped it around (ie.
 * TCP). Here we only deal with the clean, stripped, non protocol-specific
 * message. */
int parse_message(struct req_info *req,
		const unsigned char *buf, size_t len)
{
	uint32_t hdr, ver, id;
	uint16_t cmd, flags;
	const unsigned char *payload;
	size_t psize;

	/* The header is:
	 * 4 bytes	Version + ID
	 * 2 bytes	Command
	 * 2 bytes	Flags
	 * Variable 	Payload
	 */

	hdr = * ((uint32_t *) buf);
	hdr = htonl(hdr);

	/* FIXME: little endian-only */
	ver = (hdr & 0xF0000000) >> 28;
	id = hdr & 0x0FFFFFFF;
	req->id = id;

	cmd = ntohs(* ((uint16_t *) buf + 2));
	flags = ntohs(* ((uint16_t *) buf + 3));

	if (ver != PROTO_VER) {
		stats.net_version_mismatch++;
		req->reply_err(req, ERR_VER);
		return 0;
	}

	/* We define payload as the stuff after buf. But be careful because
	 * there might be none (if len == 1). Doing the pointer arithmetic
	 * isn't problematic, but accessing the payload should be done only if
	 * we know we have enough data. */
	payload = buf + 8;
	psize = len - 8;

	/* Store the id encoded in network byte order, so that we don't have
	 * to calculate it at send time. */
	req->id = htonl(id);
	req->cmd = cmd;
	req->flags = flags;
	req->payload = payload;
	req->psize = psize;

	if (cmd == REQ_GET) {
		parse_get(req);
	} else if (cmd == REQ_SET) {
		parse_set(req);
	} else if (cmd == REQ_DEL) {
		parse_del(req);
	} else if (cmd == REQ_CAS) {
		parse_cas(req);
	} else if (cmd == REQ_INCR) {
		parse_incr(req);
	} else if (cmd == REQ_FIRSTKEY) {
		parse_firstkey(req);
	} else if (cmd == REQ_NEXTKEY) {
		parse_nextkey(req);
	} else if (cmd == REQ_STATS) {
		parse_stats(req);
	} else {
		stats.net_unk_req++;
		req->reply_err(req, ERR_UNKREQ);
	}

	return 1;
}
Exemple #9
0
int main(int argc, char* argv[]) {
    if (!(argc == 3 ||
        (argc == 4 &&
         std::string(argv[3]).compare("-s") == 0))) {
        std::cerr << "Usage: " << argv[0]
                  << " ScoreFile OutputFile "
                  << " [-s] "
                  << std::endl;
        return 1;
    }

    std::ifstream in_str(argv[1]);
    if (!in_str) {
        std::cerr << "Could not open " << argv[1] << " to read.\n";
        return 1;
    }

    std::ofstream out_str(argv[2]);
    if (!out_str) {
        std::cerr << "Could not open " << argv[2] << " to write.\n";
        return 1;
    }
    // read in the file and update the data
    std::string line;
    std::vector<std::string> tokens;
    std::vector<Player> players;
    unsigned int max_name_len = std::string("player").size();
    while (std::getline(in_str, line)) {
        tokens = split(line, ' ');
        if (tokens.size() < 5) {
            std::cerr << "Wrong input format in file " << argv[1] << ".\n";
            return 1;
        }
        int winner;
        int loser;
        if (!find_player(players, tokens[0], tokens[1], winner)) {
            players.push_back(Player(tokens[0], tokens[1]));
            winner = players.size() - 1;
        }
        if (!find_player(players, tokens[3], tokens[4], loser)) {
            players.push_back(Player(tokens[3], tokens[4]));
            loser = players.size() - 1;
        }
        max_name_len = std::max(std::max(max_name_len,
                          players[winner].name_length()),
                          players[loser].name_length());
        // update the match win/lose information
        players[winner].win_match_by(1);
        players[loser].lose_match_by(1);
        // handle the sets information
        for (unsigned int i = 5; i < tokens.size(); i++) {
            int games_won;
            int games_lost;
            parse_set(tokens[i], games_won, games_lost);
            // update the game win/lose information
            players[winner].win_game_by(games_won);
            players[loser].win_game_by(games_lost);
            players[winner].lose_game_by(games_lost);
            players[loser].lose_game_by(games_won);
            // update the surprise match where
            // winner loses first set or
            // loser wins first set.
            if (i == 5 && games_won < games_lost) {
                // a match winner loses first set
                players[winner].surprise_match_by(1);
                players[winner].lose_win_match_by(1);
                // a match loser wins first set
                players[loser].surprise_match_by(1);
                players[loser].win_lose_match_by(1);
            }
        }
    }
    // output the match information
    std::sort(players.begin(), players.end(), more_matches);
    out_str << "MATCH STATISTICS" << std::endl;
    output_header(out_str, max_name_len);
    for (unsigned int i = 0; i < players.size(); i++) {
        players[i].output_match(out_str,
                                max_name_len);
    }

    out_str << std::endl;
    std::sort(players.begin(), players.end(), more_games);
    out_str << "GAME STATISTICS" << std::endl;
    output_header(out_str, max_name_len);
    for (unsigned int i = 0; i < players.size(); i++) {
        players[i].output_game(out_str,
                               max_name_len);
    }
    // with a 4th argument, output the surprise ranking
    // of all players
    if (argc == 4 && std::string(argv[3]).compare("-s") == 0) {
        out_str << std::endl;
        std::sort(players.begin(), players.end(), more_surprises);
        out_str << "SURPRISE STATISTICS" << std::endl;
        output_header(out_str, max_name_len);
        for (unsigned int i = 0; i < players.size(); i++) {
            players[i].output_surprise(out_str, max_name_len);
        }
    }
}
Exemple #10
0
int
frec_proc_heur(heur_t *h, const wchar_t *regex, size_t len, int cflags)
{
	int errcode;
	parser_state state;

	errcode = init_state(&state, regex, len, cflags);
	if (errcode != REG_OK)
		goto err;

	DEBUG_PRINT("enter");

	/*
	 * Process the pattern char-by-char.
	 *
	 * state.procidx: position in regex
	 * state.heur: buffer for the fragment being extracted
	 * state.heurpos: buffer position
	 */
	for (state.procidx = 0; state.procidx < state.len; state.procidx++) {
		switch (state.regex[state.procidx]) {

		/*
		 * BRE/ERE: Bracketed expression ends the segment or the
		 * brackets are treated as normal if at least the opening
		 * bracket is escaped.
		 */
		case L'[':
			if (state.escaped) {
				store_char(&state);
				continue;
			} else {
				if (parse_set(&state) == REG_BADPAT)
					return REG_BADPAT;
				state.tlen = (state.tlen == -1) ? -1 : state.tlen + 1;
				errcode = end_segment(&state, false);
				if (errcode != REG_OK)
					goto err;
			}
			continue;

		/*
		 * If a repetition marker, erases the repeting character
		 * and terminates the segment, otherwise treated as a normal
		 * character.
		 * BRE: repetition marker if ESCAPED.
		 * ERE: repetition marker if NOT ESCAPED.
		 */
		case L'{':
			/* Be more permissive at the beginning of the pattern */
			if (state.escaped && (state.procidx == 1)) {
				store_char(&state);
				continue;
			} else if (state.procidx == 0) {
				store_char(&state);
				continue;
			}

			if (state.escaped ^ state.ere) {
				drop_last_char(&state);
				parse_unit(&state, L'{', L'}');
				errcode = end_segment(&state, true);
				if (errcode != REG_OK)
					goto err;
			} else {
				store_char(&state);
				continue;
			}
			continue;

		/*
		 * Terminates the current segment if used for a subexpression,
		 * otherwise treated as a normal character.
		 * BRE: subexpression if ESCAPED.
		 * ERE: subexpression if NOT ESCAPED.
		 */
		case L'(':
			if (state.escaped ^ state.ere) {
				parse_unit(&state, L'(', L')');
				errcode = end_segment(&state, true);
				if (errcode != REG_OK)
					goto err;
			} else {
				store_char(&state);
				continue;
			}
			continue;

		/*
		 * Sets escaped flag.
		 * Escaped escape is treated as a normal character.
		 * (This is also the GNU behaviour.)
		 */
		case L'\\':
			if (state.escaped) {
				store_char(&state);
				continue;
			} else
				state.escaped = true;
			continue;

		/*
		 * BRE: If not the first character and not escaped, erases the
		 * last character and terminates the segment.
		 * Otherwise treated as a normal character.
		 * ERE: Skipped if first character (GNU), rest is like in BRE.
		 */
		case L'*':
			/* Be more permissive at the beginning of the pattern */
			if (state.escaped || (!state.ere && (state.procidx == 0))) {
				store_char(&state);
				continue;
			} else {
				drop_last_char(&state);
				errcode = end_segment(&state, true);
				if (errcode != REG_OK)
					goto err;
			}
			continue;

		/*
		 * BRE: it is a normal character, behavior is undefined
		 * when escaped.
		 * ERE: it is special unless escaped. Terminate segment
		 * when not escaped. Last character is not removed because it
		 * must occur at least once. It is skipped when first
		 * character (GNU).
		 */
		case L'+':
			/* Be more permissive at the beginning of the pattern */
			if (state.ere && (state.procidx == 0))
				continue;
			else if (state.ere ^ state.escaped) {
				errcode = end_segment(&state, true);
				if (errcode != REG_OK)
					goto err;
			} else {
				store_char(&state);
				continue;
			}
			continue;

		/*
		 * BRE: it is a normal character, behavior is undefined
		 * when escaped.
		 * ERE: it is special unless escaped. Terminate segment
		 * when not escaped. Last character is removed. Skipped when
		 * first character (GNU).
		 */
		case L'?':
			/* Be more permissive at the beginning of the pattern */
			if (state.ere && (state.procidx == 0))
				continue;
			if (state.ere ^ state.escaped) {
				drop_last_char(&state);
				errcode = end_segment(&state, true);
				if (errcode != REG_OK)
					goto err;
			} else {
				store_char(&state);
				continue;
			}
			continue;

		/*
		 * BRE: it is a normal character, behavior is undefined
		 * when escaped.
		 * ERE: alternation marker; unsupported.
		 */
		case L'|':
			if (state.ere ^ state.escaped) {
				errcode = REG_BADPAT;
				goto err;
			} else {
				store_char(&state);
				continue;
			}
			continue;

		/*
		 * BRE/ERE: matches any single character; normal character
		 * if escaped.
		 */
		case L'.':
			if (state.escaped) {
				store_char(&state);
				continue;
			} else {
				state.has_dot = true;
				state.tlen = (state.tlen == -1) ? -1 : state.tlen + 1;
				errcode = end_segment(&state, false);
				if (errcode != REG_OK)
					goto err;
			}
			continue;

		case L'\n':
			state.has_lf = true;
			store_char(&state);
			continue;

		/*
		 * If escaped, terminates segment.
		 * Otherwise adds current character to the current segment
		 * by copying it to the temporary space.
		 */
		default:
			if (state.escaped) {
				if (state.regex[state.procidx] == L'n') {
					state.has_lf = true;
					store(&state, L'\n');
					continue;
				}
				errcode = end_segment(&state, true);
				if (errcode != REG_OK)
					goto err;
			} else {
				store_char(&state);
				continue;
			}
			continue;
		}
	}

	if (state.heurpos > 0) {
		errcode = end_segment(&state, false);
		if (errcode != REG_OK)
			goto err;
	}

	h->heur = malloc(sizeof(fastmatch_t));
	if (!h->heur) {
		errcode = REG_ESPACE;
		goto err;
	}

	errcode = fill_heuristics(&state, h);
	if (errcode != REG_OK)
		goto err;

	errcode = REG_OK;

err:
	if ((errcode != REG_OK) && (h->heur != NULL))
		frec_free_fast(h->heur);

	free_state(&state);
	return (errcode);
}