version 1.14, 2014/01/10 11:19:31 |
version 1.15, 2014/03/08 01:05:39 |
|
|
|
|
#include "defs.h" |
#include "defs.h" |
|
|
typedef |
typedef struct shorts { |
struct shorts |
struct shorts *next; |
{ |
short value; |
struct shorts *next; |
} shorts; |
short value; |
|
} |
|
shorts; |
|
|
|
int tokensetsize; |
int tokensetsize; |
short *lookaheads; |
short *lookaheads; |
|
|
void |
void |
lalr(void) |
lalr(void) |
{ |
{ |
tokensetsize = WORDSIZE(ntokens); |
tokensetsize = WORDSIZE(ntokens); |
|
|
set_state_table(); |
set_state_table(); |
set_accessing_symbol(); |
set_accessing_symbol(); |
set_shift_table(); |
set_shift_table(); |
set_reduction_table(); |
set_reduction_table(); |
set_maxrhs(); |
set_maxrhs(); |
initialize_LA(); |
initialize_LA(); |
set_goto_map(); |
set_goto_map(); |
initialize_F(); |
initialize_F(); |
build_relations(); |
build_relations(); |
compute_FOLLOWS(); |
compute_FOLLOWS(); |
compute_lookaheads(); |
compute_lookaheads(); |
free_derives(); |
free_derives(); |
free_nullable(); |
free_nullable(); |
} |
} |
|
|
|
|
void |
void |
set_state_table(void) |
set_state_table(void) |
{ |
{ |
core *sp; |
core *sp; |
|
|
state_table = NEW2(nstates, core *); |
state_table = NEW2(nstates, core *); |
for (sp = first_state; sp; sp = sp->next) |
for (sp = first_state; sp; sp = sp->next) |
state_table[sp->number] = sp; |
state_table[sp->number] = sp; |
} |
} |
|
|
|
|
void |
void |
set_accessing_symbol(void) |
set_accessing_symbol(void) |
{ |
{ |
core *sp; |
core *sp; |
|
|
accessing_symbol = NEW2(nstates, short); |
accessing_symbol = NEW2(nstates, short); |
for (sp = first_state; sp; sp = sp->next) |
for (sp = first_state; sp; sp = sp->next) |
accessing_symbol[sp->number] = sp->accessing_symbol; |
accessing_symbol[sp->number] = sp->accessing_symbol; |
} |
} |
|
|
|
|
void |
void |
set_shift_table(void) |
set_shift_table(void) |
{ |
{ |
shifts *sp; |
shifts *sp; |
|
|
shift_table = NEW2(nstates, shifts *); |
shift_table = NEW2(nstates, shifts *); |
for (sp = first_shift; sp; sp = sp->next) |
for (sp = first_shift; sp; sp = sp->next) |
shift_table[sp->number] = sp; |
shift_table[sp->number] = sp; |
} |
} |
|
|
|
|
void |
void |
set_reduction_table(void) |
set_reduction_table(void) |
{ |
{ |
reductions *rp; |
reductions *rp; |
|
|
reduction_table = NEW2(nstates, reductions *); |
reduction_table = NEW2(nstates, reductions *); |
for (rp = first_reduction; rp; rp = rp->next) |
for (rp = first_reduction; rp; rp = rp->next) |
reduction_table[rp->number] = rp; |
reduction_table[rp->number] = rp; |
} |
} |
|
|
|
|
void |
void |
set_maxrhs(void) |
set_maxrhs(void) |
{ |
{ |
short *itemp; |
short *itemp; |
short *item_end; |
short *item_end; |
int length; |
int length; |
int max; |
int max; |
|
|
length = 0; |
length = 0; |
max = 0; |
max = 0; |
item_end = ritem + nitems; |
item_end = ritem + nitems; |
for (itemp = ritem; itemp < item_end; itemp++) |
for (itemp = ritem; itemp < item_end; itemp++) { |
{ |
if (*itemp >= 0) { |
if (*itemp >= 0) |
length++; |
{ |
} else { |
length++; |
if (length > max) max = length; |
|
length = 0; |
|
} |
} |
} |
else |
|
{ |
|
if (length > max) max = length; |
|
length = 0; |
|
} |
|
} |
|
|
|
maxrhs = max; |
maxrhs = max; |
} |
} |
|
|
|
|
void |
void |
initialize_LA(void) |
initialize_LA(void) |
{ |
{ |
int i, j, k; |
int i, j, k; |
reductions *rp; |
reductions *rp; |
|
|
lookaheads = NEW2(nstates + 1, short); |
lookaheads = NEW2(nstates + 1, short); |
|
|
k = 0; |
k = 0; |
for (i = 0; i < nstates; i++) |
for (i = 0; i < nstates; i++) { |
{ |
lookaheads[i] = k; |
lookaheads[i] = k; |
rp = reduction_table[i]; |
rp = reduction_table[i]; |
if (rp) |
if (rp) |
k += rp->nreds; |
k += rp->nreds; |
} |
} |
lookaheads[nstates] = k; |
lookaheads[nstates] = k; |
|
|
|
LA = NEW2(k * tokensetsize, unsigned); |
LA = NEW2(k * tokensetsize, unsigned); |
LAruleno = NEW2(k, short); |
LAruleno = NEW2(k, short); |
lookback = NEW2(k, shorts *); |
lookback = NEW2(k, shorts *); |
|
|
k = 0; |
k = 0; |
for (i = 0; i < nstates; i++) |
for (i = 0; i < nstates; i++) { |
{ |
rp = reduction_table[i]; |
rp = reduction_table[i]; |
if (rp) { |
if (rp) |
for (j = 0; j < rp->nreds; j++) { |
{ |
LAruleno[k] = rp->rules[j]; |
for (j = 0; j < rp->nreds; j++) |
k++; |
{ |
} |
LAruleno[k] = rp->rules[j]; |
} |
k++; |
|
} |
|
} |
} |
} |
|
} |
} |
|
|
void |
void |
set_goto_map(void) |
set_goto_map(void) |
{ |
{ |
shifts *sp; |
shifts *sp; |
int i; |
int i; |
int symbol; |
int symbol; |
int k; |
int k; |
short *temp_map; |
short *temp_map; |
int state2; |
int state2; |
int state1; |
int state1; |
|
|
goto_map = NEW2(nvars + 1, short) - ntokens; |
goto_map = NEW2(nvars + 1, short) - ntokens; |
temp_map = NEW2(nvars + 1, short) - ntokens; |
temp_map = NEW2(nvars + 1, short) - ntokens; |
|
|
ngotos = 0; |
ngotos = 0; |
for (sp = first_shift; sp; sp = sp->next) |
for (sp = first_shift; sp; sp = sp->next) { |
{ |
for (i = sp->nshifts - 1; i >= 0; i--) { |
for (i = sp->nshifts - 1; i >= 0; i--) |
symbol = accessing_symbol[sp->shift[i]]; |
{ |
|
symbol = accessing_symbol[sp->shift[i]]; |
|
|
|
if (ISTOKEN(symbol)) break; |
if (ISTOKEN(symbol)) break; |
|
|
if (ngotos == MAXSHORT) |
if (ngotos == MAXSHORT) |
fatal("too many gotos"); |
fatal("too many gotos"); |
|
|
ngotos++; |
ngotos++; |
goto_map[symbol]++; |
goto_map[symbol]++; |
} |
} |
} |
} |
|
|
k = 0; |
k = 0; |
for (i = ntokens; i < nsyms; i++) |
for (i = ntokens; i < nsyms; i++) { |
{ |
temp_map[i] = k; |
temp_map[i] = k; |
k += goto_map[i]; |
k += goto_map[i]; |
} |
} |
|
|
|
for (i = ntokens; i < nsyms; i++) |
for (i = ntokens; i < nsyms; i++) |
goto_map[i] = temp_map[i]; |
goto_map[i] = temp_map[i]; |
|
|
goto_map[nsyms] = ngotos; |
goto_map[nsyms] = ngotos; |
temp_map[nsyms] = ngotos; |
temp_map[nsyms] = ngotos; |
|
|
from_state = NEW2(ngotos, short); |
from_state = NEW2(ngotos, short); |
to_state = NEW2(ngotos, short); |
to_state = NEW2(ngotos, short); |
|
|
for (sp = first_shift; sp; sp = sp->next) |
for (sp = first_shift; sp; sp = sp->next) { |
{ |
state1 = sp->number; |
state1 = sp->number; |
for (i = sp->nshifts - 1; i >= 0; i--) { |
for (i = sp->nshifts - 1; i >= 0; i--) |
state2 = sp->shift[i]; |
{ |
symbol = accessing_symbol[state2]; |
state2 = sp->shift[i]; |
|
symbol = accessing_symbol[state2]; |
|
|
|
if (ISTOKEN(symbol)) break; |
if (ISTOKEN(symbol)) break; |
|
|
k = temp_map[symbol]++; |
k = temp_map[symbol]++; |
from_state[k] = state1; |
from_state[k] = state1; |
to_state[k] = state2; |
to_state[k] = state2; |
|
} |
} |
} |
} |
|
|
|
free(temp_map + ntokens); |
free(temp_map + ntokens); |
} |
} |
|
|
|
|
|
|
int |
int |
map_goto(int state, int symbol) |
map_goto(int state, int symbol) |
{ |
{ |
int high; |
int high; |
int low; |
int low; |
int middle; |
int middle; |
int s; |
int s; |
|
|
low = goto_map[symbol]; |
low = goto_map[symbol]; |
high = goto_map[symbol + 1]; |
high = goto_map[symbol + 1]; |
|
|
for (;;) |
for (;;) { |
{ |
assert(low <= high); |
assert(low <= high); |
middle = (low + high) >> 1; |
middle = (low + high) >> 1; |
s = from_state[middle]; |
s = from_state[middle]; |
if (s == state) |
if (s == state) |
return (middle); |
return (middle); |
else if (s < state) |
else if (s < state) |
low = middle + 1; |
low = middle + 1; |
else |
else |
high = middle - 1; |
high = middle - 1; |
} |
} |
|
} |
} |
|
|
|
|
void |
void |
initialize_F(void) |
initialize_F(void) |
{ |
{ |
int i; |
int i; |
int j; |
int j; |
int k; |
int k; |
shifts *sp; |
shifts *sp; |
short *edge; |
short *edge; |
unsigned *rowp; |
unsigned *rowp; |
short *rp; |
short *rp; |
short **reads; |
short **reads; |
int nedges; |
int nedges; |
int stateno; |
int stateno; |
int symbol; |
int symbol; |
int nwords; |
int nwords; |
|
|
nwords = ngotos * tokensetsize; |
nwords = ngotos * tokensetsize; |
F = NEW2(nwords, unsigned); |
F = NEW2(nwords, unsigned); |
|
|
reads = NEW2(ngotos, short *); |
reads = NEW2(ngotos, short *); |
edge = NEW2(ngotos + 1, short); |
edge = NEW2(ngotos + 1, short); |
nedges = 0; |
nedges = 0; |
|
|
rowp = F; |
rowp = F; |
for (i = 0; i < ngotos; i++) |
for (i = 0; i < ngotos; i++) { |
{ |
stateno = to_state[i]; |
stateno = to_state[i]; |
sp = shift_table[stateno]; |
sp = shift_table[stateno]; |
|
|
|
if (sp) |
if (sp) { |
{ |
k = sp->nshifts; |
k = sp->nshifts; |
|
|
|
for (j = 0; j < k; j++) |
for (j = 0; j < k; j++) { |
{ |
symbol = accessing_symbol[sp->shift[j]]; |
symbol = accessing_symbol[sp->shift[j]]; |
if (ISVAR(symbol)) |
if (ISVAR(symbol)) |
break; |
break; |
SETBIT(rowp, symbol); |
SETBIT(rowp, symbol); |
} |
} |
|
|
|
for (; j < k; j++) |
for (; j < k; j++) { |
{ |
symbol = accessing_symbol[sp->shift[j]]; |
symbol = accessing_symbol[sp->shift[j]]; |
if (nullable[symbol]) |
if (nullable[symbol]) |
edge[nedges++] = map_goto(stateno, symbol); |
edge[nedges++] = map_goto(stateno, symbol); |
} |
} |
|
|
if (nedges) { |
if (nedges) |
reads[i] = rp = NEW2(nedges + 1, short); |
{ |
|
reads[i] = rp = NEW2(nedges + 1, short); |
|
|
|
for (j = 0; j < nedges; j++) |
for (j = 0; j < nedges; j++) |
rp[j] = edge[j]; |
rp[j] = edge[j]; |
|
|
rp[nedges] = -1; |
rp[nedges] = -1; |
nedges = 0; |
nedges = 0; |
} |
} |
|
} |
|
|
|
rowp += tokensetsize; |
} |
} |
|
|
rowp += tokensetsize; |
SETBIT(F, 0); |
} |
digraph(reads); |
|
|
SETBIT(F, 0); |
for (i = 0; i < ngotos; i++) { |
digraph(reads); |
if (reads[i]) |
|
free(reads[i]); |
|
} |
|
|
for (i = 0; i < ngotos; i++) |
free(reads); |
{ |
free(edge); |
if (reads[i]) |
|
free(reads[i]); |
|
} |
|
|
|
free(reads); |
|
free(edge); |
|
} |
} |
|
|
|
|
void |
void |
build_relations(void) |
build_relations(void) |
{ |
{ |
int i; |
int i; |
int j; |
int j; |
int k; |
int k; |
short *rulep; |
short *rulep; |
short *rp; |
short *rp; |
shifts *sp; |
shifts *sp; |
int length; |
int length; |
int nedges; |
int nedges; |
int done; |
int done; |
int state1; |
int state1; |
int stateno; |
int stateno; |
int symbol1; |
int symbol1; |
int symbol2; |
int symbol2; |
short *shortp; |
short *shortp; |
short *edge; |
short *edge; |
short *states; |
short *states; |
short **new_includes; |
short **new_includes; |
|
|
includes = NEW2(ngotos, short *); |
includes = NEW2(ngotos, short *); |
edge = NEW2(ngotos + 1, short); |
edge = NEW2(ngotos + 1, short); |
states = NEW2(maxrhs + 1, short); |
states = NEW2(maxrhs + 1, short); |
|
|
for (i = 0; i < ngotos; i++) |
for (i = 0; i < ngotos; i++) { |
{ |
nedges = 0; |
nedges = 0; |
state1 = from_state[i]; |
state1 = from_state[i]; |
symbol1 = accessing_symbol[to_state[i]]; |
symbol1 = accessing_symbol[to_state[i]]; |
|
|
|
for (rulep = derives[symbol1]; *rulep >= 0; rulep++) |
for (rulep = derives[symbol1]; *rulep >= 0; rulep++) { |
{ |
length = 1; |
length = 1; |
states[0] = state1; |
states[0] = state1; |
stateno = state1; |
stateno = state1; |
|
|
|
for (rp = ritem + rrhs[*rulep]; *rp >= 0; rp++) |
for (rp = ritem + rrhs[*rulep]; *rp >= 0; rp++) { |
{ |
symbol2 = *rp; |
symbol2 = *rp; |
sp = shift_table[stateno]; |
sp = shift_table[stateno]; |
k = sp->nshifts; |
k = sp->nshifts; |
|
|
|
for (j = 0; j < k; j++) |
for (j = 0; j < k; j++) { |
{ |
stateno = sp->shift[j]; |
stateno = sp->shift[j]; |
if (accessing_symbol[stateno] == symbol2) |
if (accessing_symbol[stateno] == symbol2) break; |
break; |
} |
} |
|
|
states[length++] = stateno; |
states[length++] = stateno; |
} |
} |
|
|
add_lookback_edge(stateno, *rulep, i); |
add_lookback_edge(stateno, *rulep, i); |
|
|
length--; |
length--; |
done = 0; |
done = 0; |
while (!done) |
while (!done) { |
{ |
done = 1; |
done = 1; |
rp--; |
rp--; |
if (ISVAR(*rp)) { |
if (ISVAR(*rp)) |
stateno = states[--length]; |
{ |
edge[nedges++] = map_goto(stateno, *rp); |
stateno = states[--length]; |
if (nullable[*rp] && length > 0) |
edge[nedges++] = map_goto(stateno, *rp); |
done = 0; |
if (nullable[*rp] && length > 0) done = 0; |
} |
|
} |
} |
} |
} |
|
} |
|
|
|
if (nedges) |
if (nedges) { |
{ |
includes[i] = shortp = NEW2(nedges + 1, short); |
includes[i] = shortp = NEW2(nedges + 1, short); |
for (j = 0; j < nedges; j++) |
for (j = 0; j < nedges; j++) |
shortp[j] = edge[j]; |
shortp[j] = edge[j]; |
shortp[nedges] = -1; |
shortp[nedges] = -1; |
} |
} |
} |
} |
|
|
|
new_includes = transpose(includes, ngotos); |
new_includes = transpose(includes, ngotos); |
|
|
for (i = 0; i < ngotos; i++) |
for (i = 0; i < ngotos; i++) |
if (includes[i]) |
if (includes[i]) |
free(includes[i]); |
free(includes[i]); |
|
|
free(includes); |
free(includes); |
|
|
includes = new_includes; |
includes = new_includes; |
|
|
free(edge); |
free(edge); |
free(states); |
free(states); |
} |
} |
|
|
void |
void |
add_lookback_edge(int stateno, int ruleno, int gotono) |
add_lookback_edge(int stateno, int ruleno, int gotono) |
{ |
{ |
int i, k; |
int i, k; |
int found; |
int found; |
shorts *sp; |
shorts *sp; |
|
|
i = lookaheads[stateno]; |
i = lookaheads[stateno]; |
k = lookaheads[stateno + 1]; |
k = lookaheads[stateno + 1]; |
found = 0; |
found = 0; |
while (!found && i < k) |
while (!found && i < k) { |
{ |
if (LAruleno[i] == ruleno) |
if (LAruleno[i] == ruleno) |
found = 1; |
found = 1; |
else |
else |
++i; |
++i; |
} |
} |
assert(found); |
assert(found); |
|
|
|
sp = NEW(shorts); |
sp = NEW(shorts); |
sp->next = lookback[i]; |
sp->next = lookback[i]; |
sp->value = gotono; |
sp->value = gotono; |
lookback[i] = sp; |
lookback[i] = sp; |
} |
} |
|
|
|
|
|
|
short ** |
short ** |
transpose(short **R, int n) |
transpose(short **R, int n) |
{ |
{ |
short **new_R; |
short **new_R; |
short **temp_R; |
short **temp_R; |
short *nedges; |
short *nedges; |
short *sp; |
short *sp; |
int i; |
int i; |
int k; |
int k; |
|
|
nedges = NEW2(n, short); |
nedges = NEW2(n, short); |
|
|
for (i = 0; i < n; i++) |
for (i = 0; i < n; i++) { |
{ |
sp = R[i]; |
sp = R[i]; |
if (sp) { |
if (sp) |
while (*sp >= 0) |
{ |
nedges[*sp++]++; |
while (*sp >= 0) |
} |
nedges[*sp++]++; |
|
} |
} |
} |
|
|
|
new_R = NEW2(n, short *); |
new_R = NEW2(n, short *); |
temp_R = NEW2(n, short *); |
temp_R = NEW2(n, short *); |
|
|
for (i = 0; i < n; i++) |
for (i = 0; i < n; i++) { |
{ |
k = nedges[i]; |
k = nedges[i]; |
if (k > 0) { |
if (k > 0) |
sp = NEW2(k + 1, short); |
{ |
new_R[i] = sp; |
sp = NEW2(k + 1, short); |
temp_R[i] = sp; |
new_R[i] = sp; |
sp[k] = -1; |
temp_R[i] = sp; |
} |
sp[k] = -1; |
|
} |
} |
} |
|
|
|
free(nedges); |
free(nedges); |
|
|
for (i = 0; i < n; i++) |
for (i = 0; i < n; i++) { |
{ |
sp = R[i]; |
sp = R[i]; |
if (sp) { |
if (sp) |
while (*sp >= 0) |
{ |
*temp_R[*sp++]++ = i; |
while (*sp >= 0) |
} |
*temp_R[*sp++]++ = i; |
|
} |
} |
} |
|
|
|
free(temp_R); |
free(temp_R); |
|
|
return (new_R); |
return (new_R); |
} |
} |
|
|
|
|
void |
void |
compute_FOLLOWS(void) |
compute_FOLLOWS(void) |
{ |
{ |
digraph(includes); |
digraph(includes); |
} |
} |
|
|
void |
void |
compute_lookaheads(void) |
compute_lookaheads(void) |
{ |
{ |
int i, n; |
int i, n; |
unsigned *fp1, *fp2, *fp3; |
unsigned *fp1, *fp2, *fp3; |
shorts *sp, *next; |
shorts *sp, *next; |
unsigned *rowp; |
unsigned *rowp; |
|
|
rowp = LA; |
rowp = LA; |
n = lookaheads[nstates]; |
n = lookaheads[nstates]; |
for (i = 0; i < n; i++) |
for (i = 0; i < n; i++) { |
{ |
fp3 = rowp + tokensetsize; |
fp3 = rowp + tokensetsize; |
for (sp = lookback[i]; sp; sp = sp->next) { |
for (sp = lookback[i]; sp; sp = sp->next) |
fp1 = rowp; |
{ |
fp2 = F + tokensetsize * sp->value; |
fp1 = rowp; |
while (fp1 < fp3) |
fp2 = F + tokensetsize * sp->value; |
*fp1++ |= *fp2++; |
while (fp1 < fp3) |
} |
*fp1++ |= *fp2++; |
rowp = fp3; |
} |
} |
rowp = fp3; |
|
} |
|
|
|
for (i = 0; i < n; i++) |
for (i = 0; i < n; i++) |
for (sp = lookback[i]; sp; sp = next) |
for (sp = lookback[i]; sp; sp = next) { |
{ |
next = sp->next; |
next = sp->next; |
free(sp); |
free(sp); |
} |
} |
|
|
|
free(lookback); |
free(lookback); |
free(F); |
free(F); |
} |
} |
|
|
void |
void |
digraph(short **relation) |
digraph(short **relation) |
{ |
{ |
int i; |
int i; |
|
|
infinity = ngotos + 2; |
infinity = ngotos + 2; |
INDEX = NEW2(ngotos + 1, short); |
INDEX = NEW2(ngotos + 1, short); |
VERTICES = NEW2(ngotos + 1, short); |
VERTICES = NEW2(ngotos + 1, short); |
top = 0; |
top = 0; |
R = relation; |
R = relation; |
|
|
memset(INDEX, 0, ngotos * sizeof(short)); |
memset(INDEX, 0, ngotos * sizeof(short)); |
for (i = 0; i < ngotos; i++) |
for (i = 0; i < ngotos; i++) |
if (R[i]) |
if (R[i]) |
traverse(i); |
traverse(i); |
|
|
free(INDEX); |
free(INDEX); |
free(VERTICES); |
free(VERTICES); |
} |
} |
|
|
|
|
void |
void |
traverse(int i) |
traverse(int i) |
{ |
{ |
unsigned *fp1; |
unsigned *fp1; |
unsigned *fp2; |
unsigned *fp2; |
unsigned *fp3; |
unsigned *fp3; |
int j; |
int j; |
short *rp; |
short *rp; |
|
|
int height; |
int height; |
unsigned *base; |
unsigned *base; |
|
|
VERTICES[++top] = i; |
VERTICES[++top] = i; |
INDEX[i] = height = top; |
INDEX[i] = height = top; |
|
|
base = F + i * tokensetsize; |
base = F + i * tokensetsize; |
fp3 = base + tokensetsize; |
fp3 = base + tokensetsize; |
|
|
rp = R[i]; |
rp = R[i]; |
if (rp) |
if (rp) { |
{ |
while ((j = *rp++) >= 0) { |
while ((j = *rp++) >= 0) |
if (INDEX[j] == 0) |
{ |
traverse(j); |
if (INDEX[j] == 0) |
|
traverse(j); |
|
|
|
if (INDEX[i] > INDEX[j]) |
if (INDEX[i] > INDEX[j]) |
INDEX[i] = INDEX[j]; |
INDEX[i] = INDEX[j]; |
|
|
fp1 = base; |
fp1 = base; |
fp2 = F + j * tokensetsize; |
fp2 = F + j * tokensetsize; |
|
|
while (fp1 < fp3) |
while (fp1 < fp3) |
*fp1++ |= *fp2++; |
*fp1++ |= *fp2++; |
|
} |
} |
} |
} |
|
|
|
if (INDEX[i] == height) |
if (INDEX[i] == height) { |
{ |
for (;;) { |
for (;;) |
j = VERTICES[top--]; |
{ |
INDEX[j] = infinity; |
j = VERTICES[top--]; |
|
INDEX[j] = infinity; |
|
|
|
if (i == j) |
if (i == j) |
break; |
break; |
|
|
fp1 = base; |
fp1 = base; |
fp2 = F + j * tokensetsize; |
fp2 = F + j * tokensetsize; |
|
|
while (fp1 < fp3) |
while (fp1 < fp3) |
*fp2++ = *fp1++; |
*fp2++ = *fp1++; |
|
} |
} |
} |
} |
|
} |
} |