#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "rkconv.h"
int malloc_count = 0;
Rule::Rule()
{
lhs = NULL;
rhs = NULL;
follow = NULL;
}
Rule::~Rule()
{
if (lhs){
delete[] lhs;
}
if (rhs){
delete[] rhs;
}
if (follow){
delete[] follow;
}
}
Rule &Rule::operator=(RkRule &r)
{
if (r.lhs){
lhs = new char[strlen(r.lhs)+1];
strcpy (lhs, r.lhs);
} else {
lhs = NULL;
}
if (r.rhs){
rhs = new char[strlen(r.rhs)+1];
strcpy (rhs, r.rhs);
} else {
rhs = NULL;
}
if (r.follow){
follow = new char[strlen(r.follow)+1];
strcpy (follow, r.follow);
} else {
follow = NULL;
}
return *this;
}
RuleSet::RuleSet(RkRule *rule)
{
int i;
for (nr_rules = 0; rule[nr_rules].lhs; nr_rules++)
;
this->rule = new Rule [nr_rules];
for (i = 0; i < nr_rules; i++){
this->rule[i] = rule[i];
}
}
RuleSet::~RuleSet()
{
delete[] rule;
}
RKMap::RKMap(RkRule *rule)
{
rs = new RuleSet(rule);
cl = new SlrClosure(rs, rs->get_nr_rules());
refcount = 0;
}
RKMap::~RKMap()
{
delete rs;
}
void RKMap::print(FILE *fp,char *prefix)
{
cl->print(fp, prefix);
}
void RKMap::convert_batch (char* src, char* dst)
{
cl->convert_batch(src, dst);
}
int RKMap::get_refcount()
{
return refcount;
}
int RKMap::inc_refcount()
{
return ++refcount;
}
int RKMap::dec_refcount()
{
return --refcount;
}
SlrClosure* RKMap::get_init(void){
return cl;
}
SlrClosure::SlrClosure (RuleSet* rule, int nr_rule,
Rule* cur_rule,size_t pflen)
{
int i;
char c;
Rule* r;
malloc_count++;
// prefix
if (cur_rule){
prefix = new char[pflen+1];
strncpy(prefix, cur_rule->lhs, pflen);
prefix[pflen] = 0;
} else {
prefix = "";
}
// r
this->r = (Rule*)NULL;
// is_reduction_only
is_reduction_only = true;
// next
memset (next, 0, sizeof next);
/* pflen == strlen(prefix) を保証しておくこと */
for (i = 0; i < nr_rule; i++){
r = rule->get_rule()+i;
if (strncmp(prefix, r->lhs, pflen))
continue;
if (strlen(r->lhs) == pflen){ /* 還元 */
this->r = r;
if (this->r->follow){
is_reduction_only = false;
}
} else { /* 継続 */
is_reduction_only = false;
c = r->lhs[pflen];
if (!next[c]){
next[c] = new SlrClosure (rule, nr_rule, r, pflen+1);
}
}
}
}
SlrClosure::~SlrClosure(void)
{
int i;
delete[] prefix;
for (i = 0; i < 128; i++){
if (next[i])
delete next[i];
}
}
#define PREFIX fprintf (fp, "%s", prefix);
void SlrClosure::print(FILE* fp, char* prefix)
{
int i;
char buf[1000];
PREFIX fprintf (fp, "[%p] prefix:%s\n", this, prefix);
if (r){
PREFIX fprintf (fp, " reduction: %s->%s\n",
r->lhs, r->rhs);
} else {
PREFIX fprintf (fp, " reduction: (none)\n");
}
PREFIX fprintf (fp, " reduction_only: %d\n",
is_reduction_only);
for (i = 0; i < 128; i++){
if (next[i]){
sprintf (buf, "%s(%c)", prefix, i);
next[i]->print(fp, buf);
}
}
}
char *SlrClosure::convert_reduction(char* dst, Rule* r)
{
strcpy(dst, r->rhs);
dst += strlen(dst);
return dst;
}
void SlrClosure::convert_batch(char* src, char* dst)
{
SlrClosure* cur = this;
char* p = src;
char* q = dst;
do {
retry:
if (cur->next[*p]) {
cur = cur->next[*p];
if (cur->is_reduction_only){
q = convert_reduction(q, cur->r);
cur = this;
}
} else if (cur->r &&
(!cur->r->follow || strchr(cur->r->follow, *p))) {
q = convert_reduction(q, cur->r);
cur = this;
goto retry;
} else if (cur != this){
cur = this;
goto retry;
} else {
}
} while (*(++p));
if (cur->r && !cur->r->follow){
convert_reduction(q, cur->r);
}
}
SlrClosure* SlrClosure::convert_iterative(char c, char* dst, SlrClosure* cl)
{
*dst = '\0';
if (next[c]){
if (next[c]->is_reduction_only){
dst = convert_reduction(dst, next[c]->r);
return cl;
}
return next[c];
} else if (r && (!r->follow || strchr(r->follow, c))){
dst = convert_reduction(dst, r);
return cl->convert_iterative(c, dst, cl); // retry
} else if (this != cl){
return cl->convert_iterative(c, dst, cl); // retry
}
return cl;
}
/// class RKConv
RKConv::RKConv()
{
map = NULL;
cur = NULL;
flush();
}
bool RKConv::push_key(int cin)
{
char dst[10];
char c = cin & 0x7F;
if (!cur)
return false;
cur = map->convert_iterative(c, dst, cur);
if ( !euc_to_cchar(dst) && !is_pending()){
return false;
}
return true;
}
void RKConv::flush()
{
if (map)
cur = map->get_init();
outQ.erase(outQ.begin(), outQ.end());
}
cchar RKConv::get_cchar()
{
cchar ret = 0;
std::list<cchar>::iterator i = outQ.begin();
if (i != outQ.end()){
ret = *i;
outQ.pop_front();
}
return ret;
}
RKMap* RKConv::select_map(RKMap* m)
{
RKMap* oldmap = map;
const char* p = "";
if (cur)
p = cur->get_prefix();
map = m;
cur = m->get_init();
while (*p)
push_key (*(p++));
map->inc_refcount();
if (oldmap)
oldmap->dec_refcount();
return oldmap;
}
void RKConv::print_map(FILE* fp, char* prefix)
{
map->print(fp, prefix);
}
char* RKConv::get_pending_char(char* buf, size_t size)
{
if (!cur)
return NULL;
if (strlen(cur->get_prefix()) >= size)
return NULL;
strcpy(buf, cur->get_prefix());
return buf;
}
bool RKConv::is_pending()
{
if (!cur || strlen(cur->get_prefix()) == 0){
return false;
}
return true;
}
bool RKConv::back_space()
{
char buf[10];
if ( get_pending_char(buf,10)){
int l = strlen(buf);
int i;
flush();
for ( i = 0 ; i < l-1 ; i++){
push_key(buf[i]);
}
return l>0;
}
return false;
}
// private
bool RKConv::euc_to_cchar(char* q)
{
cchar c;
unsigned char* p = (unsigned char*)q;
bool bConv = false;
while (*p){
c = (*(p+1) | (((unsigned int) *p)<<8)) & 0x7F7F;
outQ.push_back(c);
p += 2;
bConv = true;
}
return bConv;
}
/*
* Local variables:
* c-indent-level: 4
* c-basic-offset: 4
* End:
*/
syntax highlighted by Code2HTML, v. 0.9.1