1 : /* GRAPHITE2 LICENSING
2 :
3 : Copyright 2010, SIL International
4 : All rights reserved.
5 :
6 : This library is free software; you can redistribute it and/or modify
7 : it under the terms of the GNU Lesser General Public License as published
8 : by the Free Software Foundation; either version 2.1 of License, or
9 : (at your option) any later version.
10 :
11 : This program is distributed in the hope that it will be useful,
12 : but WITHOUT ANY WARRANTY; without even the implied warranty of
13 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 : Lesser General Public License for more details.
15 :
16 : You should also have received a copy of the GNU Lesser General Public
17 : License along with this library in the file named "LICENSE".
18 : If not, write to the Free Software Foundation, 51 Franklin Street,
19 : Suite 500, Boston, MA 02110-1335, USA or visit their web page on the
20 : internet at http://www.fsf.org/licenses/lgpl.html.
21 :
22 : Alternatively, the contents of this file may be used under the terms of the
23 : Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
24 : License, as published by the Free Software Foundation, either version 2
25 : of the License or (at your option) any later version.
26 : */
27 : #pragma once
28 : // This file will be pulled into and integrated into a machine implmentation
29 : // DO NOT build directly and under no circumstances every #include headers in
30 : // here or you will break the direct_machine.
31 : //
32 : // Implementers' notes
33 : // ==================
34 : // You have access to a few primitives and the full C++ code:
35 : // declare_params(n) Tells the interpreter how many bytes of parameter
36 : // space to claim for this instruction uses and
37 : // initialises the param pointer. You *must* before the
38 : // first use of param.
39 : // use_params(n) Claim n extra bytes of param space beyond what was
40 : // claimed using delcare_param.
41 : // param A const byte pointer for the parameter space claimed by
42 : // this instruction.
43 : // binop(op) Implement a binary operation on the stack using the
44 : // specified C++ operator.
45 : // NOT_IMPLEMENTED Any instruction body containing this will exit the
46 : // program with an assertion error. Instructions that are
47 : // not implemented should also be marked NILOP in the
48 : // opcodes tables this will cause the code class to spot
49 : // them in a live code stream and throw a runtime_error
50 : // instead.
51 : // push(n) Push the value n onto the stack.
52 : // pop() Pop the top most value and return it.
53 : //
54 : // You have access to the following named fast 'registers':
55 : // sp = The pointer to the current top of stack, the last value
56 : // pushed.
57 : // seg = A reference to the Segment this code is running over.
58 : // is = The current slot index
59 : // isb = The original base slot index at the start of this rule
60 : // isf = The first positioned slot
61 : // isl = The last positioned slot
62 : // ip = The current instruction pointer
63 : // endPos = Position of advance of last cluster
64 :
65 :
66 : // #define NOT_IMPLEMENTED assert(false)
67 : #define NOT_IMPLEMENTED
68 :
69 : #define binop(op) const int32 a = pop(); *sp = int32(*sp) op a
70 : #define use_params(n) dp += n
71 :
72 : #define declare_params(n) const byte * param = dp; \
73 : use_params(n);
74 :
75 : #define push(n) { *++sp = n; }
76 : #define pop() (*sp--)
77 : #define slotat(x) (map[(x)])
78 : #define DIE { is=seg.last(); EXIT(1); }
79 : #define POSITIONED 1
80 :
81 : STARTOP(nop)
82 : do {} while (0);
83 0 : ENDOP
84 :
85 : STARTOP(push_byte)
86 0 : declare_params(1);
87 0 : push(int8(*param));
88 0 : ENDOP
89 :
90 : STARTOP(push_byte_u)
91 0 : declare_params(1);
92 0 : push(uint8(*param));
93 0 : ENDOP
94 :
95 : STARTOP(push_short)
96 0 : declare_params(2);
97 0 : const int16 r = int16(param[0]) << 8
98 0 : | uint8(param[1]);
99 0 : push(r);
100 0 : ENDOP
101 :
102 : STARTOP(push_short_u)
103 0 : declare_params(2);
104 0 : const uint16 r = uint16(param[0]) << 8
105 0 : | uint8(param[1]);
106 0 : push(r);
107 0 : ENDOP
108 :
109 : STARTOP(push_long)
110 0 : declare_params(4);
111 0 : const int32 r = int32(param[0]) << 24
112 0 : | uint32(param[1]) << 16
113 0 : | uint32(param[2]) << 8
114 0 : | uint8(param[3]);
115 0 : push(r);
116 0 : ENDOP
117 :
118 : STARTOP(add)
119 0 : binop(+);
120 0 : ENDOP
121 :
122 : STARTOP(sub)
123 0 : binop(-);
124 0 : ENDOP
125 :
126 : STARTOP(mul)
127 0 : binop(*);
128 0 : ENDOP
129 :
130 : STARTOP(div_)
131 0 : if (*sp == 0) DIE;
132 0 : binop(/);
133 0 : ENDOP
134 :
135 : STARTOP(min)
136 0 : const int32 a = pop(), b = *sp;
137 0 : if (a < b) *sp = a;
138 0 : ENDOP
139 :
140 : STARTOP(max)
141 0 : const int32 a = pop(), b = *sp;
142 0 : if (a > b) *sp = a;
143 0 : ENDOP
144 :
145 : STARTOP(neg)
146 0 : *sp = uint32(-int32(*sp));
147 0 : ENDOP
148 :
149 : STARTOP(trunc8)
150 0 : *sp = uint8(*sp);
151 0 : ENDOP
152 :
153 : STARTOP(trunc16)
154 0 : *sp = uint16(*sp);
155 0 : ENDOP
156 :
157 : STARTOP(cond)
158 0 : const uint32 f = pop(), t = pop(), c = pop();
159 0 : push(c ? t : f);
160 0 : ENDOP
161 :
162 : STARTOP(and_)
163 0 : binop(&&);
164 0 : ENDOP
165 :
166 : STARTOP(or_)
167 0 : binop(||);
168 0 : ENDOP
169 :
170 : STARTOP(not_)
171 0 : *sp = !*sp;
172 0 : ENDOP
173 :
174 : STARTOP(equal)
175 0 : binop(==);
176 0 : ENDOP
177 :
178 : STARTOP(not_eq_)
179 0 : binop(!=);
180 0 : ENDOP
181 :
182 : STARTOP(less)
183 0 : binop(<);
184 0 : ENDOP
185 :
186 : STARTOP(gtr)
187 0 : binop(>);
188 0 : ENDOP
189 :
190 : STARTOP(less_eq)
191 0 : binop(<=);
192 0 : ENDOP
193 :
194 : STARTOP(gtr_eq)
195 0 : binop(>=);
196 0 : ENDOP
197 :
198 : STARTOP(next)
199 0 : if (map - &smap[0] >= int(smap.size())) DIE
200 0 : if (is)
201 : {
202 0 : if (is == smap.highwater())
203 0 : smap.highpassed(true);
204 0 : is = is->next();
205 : }
206 0 : ++map;
207 0 : ENDOP
208 :
209 : STARTOP(next_n)
210 0 : use_params(1);
211 : NOT_IMPLEMENTED;
212 : //declare_params(1);
213 : //const size_t num = uint8(*param);
214 0 : ENDOP
215 :
216 : //STARTOP(copy_next)
217 : // if (is) is = is->next();
218 : // ++map;
219 : // ENDOP
220 :
221 : STARTOP(put_glyph_8bit_obs)
222 0 : declare_params(1);
223 0 : const unsigned int output_class = uint8(*param);
224 0 : is->setGlyph(&seg, seg.getClassGlyph(output_class, 0));
225 0 : ENDOP
226 :
227 : STARTOP(put_subs_8bit_obs)
228 0 : declare_params(3);
229 0 : const int slot_ref = int8(param[0]);
230 0 : const unsigned int input_class = uint8(param[1]),
231 0 : output_class = uint8(param[2]);
232 : uint16 index;
233 0 : slotref slot = slotat(slot_ref);
234 0 : if (slot)
235 : {
236 0 : index = seg.findClassIndex(input_class, slot->gid());
237 0 : is->setGlyph(&seg, seg.getClassGlyph(output_class, index));
238 : }
239 0 : ENDOP
240 :
241 : STARTOP(put_copy)
242 0 : declare_params(1);
243 0 : const int slot_ref = int8(*param);
244 0 : if (is && (slot_ref ||is != *map))
245 : {
246 0 : int16 *tempUserAttrs = is->userAttrs();
247 0 : slotref ref = slotat(slot_ref);
248 0 : if (ref)
249 : {
250 0 : memcpy(tempUserAttrs, ref->userAttrs(), seg.numAttrs() * sizeof(uint16));
251 0 : Slot *prev = is->prev();
252 0 : Slot *next = is->next();
253 0 : memcpy(is, slotat(slot_ref), sizeof(Slot));
254 0 : is->userAttrs(tempUserAttrs);
255 0 : is->next(next);
256 0 : is->prev(prev);
257 0 : is->sibling(NULL);
258 : }
259 0 : is->markCopied(false);
260 0 : is->markDeleted(false);
261 : }
262 0 : ENDOP
263 :
264 : STARTOP(insert)
265 0 : Slot *newSlot = seg.newSlot();
266 0 : Slot *iss = is;
267 0 : while (iss && iss->isDeleted()) iss = iss->next();
268 0 : if (!iss)
269 : {
270 0 : if (seg.last())
271 : {
272 0 : seg.last()->next(newSlot);
273 0 : newSlot->prev(seg.last());
274 0 : newSlot->before(seg.last()->before());
275 0 : seg.last(newSlot);
276 : }
277 : else
278 : {
279 0 : seg.first(newSlot);
280 0 : seg.last(newSlot);
281 : }
282 : }
283 0 : else if (iss->prev())
284 : {
285 0 : iss->prev()->next(newSlot);
286 0 : newSlot->prev(iss->prev());
287 0 : newSlot->before(iss->prev()->after());
288 : }
289 : else
290 : {
291 0 : newSlot->prev(NULL);
292 0 : newSlot->before(iss->before());
293 0 : seg.first(newSlot);
294 : }
295 0 : newSlot->next(iss);
296 0 : if (iss)
297 : {
298 0 : iss->prev(newSlot);
299 0 : newSlot->originate(iss->original());
300 0 : newSlot->after(iss->before());
301 : }
302 0 : else if (newSlot->prev())
303 : {
304 0 : newSlot->originate(newSlot->prev()->original());
305 0 : newSlot->after(newSlot->prev()->after());
306 : }
307 : else
308 : {
309 0 : newSlot->originate(seg.defaultOriginal());
310 : }
311 0 : is = newSlot;
312 0 : seg.extendLength(1);
313 0 : if (map != &smap[-1])
314 0 : --map;
315 0 : ENDOP
316 :
317 : STARTOP(delete_)
318 0 : if (!is) DIE
319 0 : is->markDeleted(true);
320 0 : if (is->prev())
321 0 : is->prev()->next(is->next());
322 : else
323 0 : seg.first(is->next());
324 :
325 0 : if (is->next())
326 0 : is->next()->prev(is->prev());
327 : else
328 0 : seg.last(is->prev());
329 :
330 0 : if (is == smap.highwater())
331 0 : smap.highwater(is->next());
332 0 : if (is->prev())
333 0 : is = is->prev();
334 0 : seg.extendLength(-1);
335 0 : ENDOP
336 :
337 : STARTOP(assoc)
338 0 : declare_params(1);
339 0 : unsigned int num = uint8(*param);
340 0 : const int8 * assocs = reinterpret_cast<const int8 *>(param+1);
341 0 : use_params(num);
342 0 : int max = -1;
343 0 : int min = -1;
344 :
345 0 : while (num-- > 0)
346 : {
347 0 : int sr = *assocs++;
348 0 : slotref ts = slotat(sr);
349 0 : if (ts && (min == -1 || ts->before() < min)) min = ts->before();
350 0 : if (ts && ts->after() > max) max = ts->after();
351 : }
352 0 : if (min > -1) // implies max > -1
353 : {
354 0 : is->before(min);
355 0 : is->after(max);
356 : }
357 0 : ENDOP
358 :
359 : STARTOP(cntxt_item)
360 : // It turns out this is a cunningly disguised condition forward jump.
361 0 : declare_params(3);
362 0 : const int is_arg = int8(param[0]);
363 0 : const size_t iskip = uint8(param[1]),
364 0 : dskip = uint8(param[2]);
365 :
366 0 : if (mapb + is_arg != map)
367 : {
368 0 : ip += iskip;
369 0 : dp += dskip;
370 0 : push(true);
371 : }
372 0 : ENDOP
373 :
374 : STARTOP(attr_set)
375 0 : declare_params(1);
376 0 : const attrCode slat = attrCode(uint8(*param));
377 0 : const int val = int(pop());
378 0 : is->setAttr(&seg, slat, 0, val, smap);
379 0 : ENDOP
380 :
381 : STARTOP(attr_add)
382 0 : declare_params(1);
383 0 : const attrCode slat = attrCode(uint8(*param));
384 0 : const int val = int(pop());
385 0 : if ((slat == gr_slatPosX || slat == gr_slatPosY) && (flags & POSITIONED) == 0)
386 : {
387 0 : seg.positionSlots(0, *smap.begin(), *(smap.end()-1));
388 0 : flags |= POSITIONED;
389 : }
390 0 : int res = is->getAttr(&seg, slat, 0);
391 0 : is->setAttr(&seg, slat, 0, val + res, smap);
392 0 : ENDOP
393 :
394 : STARTOP(attr_sub)
395 0 : declare_params(1);
396 0 : const attrCode slat = attrCode(uint8(*param));
397 0 : const int val = int(pop());
398 0 : if ((slat == gr_slatPosX || slat == gr_slatPosY) && (flags & POSITIONED) == 0)
399 : {
400 0 : seg.positionSlots(0, *smap.begin(), *(smap.end()-1));
401 0 : flags |= POSITIONED;
402 : }
403 0 : int res = is->getAttr(&seg, slat, 0);
404 0 : is->setAttr(&seg, slat, 0, res - val, smap);
405 0 : ENDOP
406 :
407 : STARTOP(attr_set_slot)
408 0 : declare_params(1);
409 0 : const attrCode slat = attrCode(uint8(*param));
410 0 : const int val = int(pop()) + (map - smap.begin())*int(slat == gr_slatAttTo);
411 0 : is->setAttr(&seg, slat, 0, val, smap);
412 0 : ENDOP
413 :
414 : STARTOP(iattr_set_slot)
415 0 : declare_params(2);
416 0 : const attrCode slat = attrCode(uint8(param[0]));
417 0 : const size_t idx = uint8(param[1]);
418 0 : const int val = int(pop()) + (map - smap.begin())*int(slat == gr_slatAttTo);
419 0 : is->setAttr(&seg, slat, idx, val, smap);
420 0 : ENDOP
421 :
422 : STARTOP(push_slot_attr)
423 0 : declare_params(2);
424 0 : const attrCode slat = attrCode(uint8(param[0]));
425 0 : const int slot_ref = int8(param[1]);
426 0 : if ((slat == gr_slatPosX || slat == gr_slatPosY) && (flags & POSITIONED) == 0)
427 : {
428 0 : seg.positionSlots(0, *smap.begin(), *(smap.end()-1));
429 0 : flags |= POSITIONED;
430 : }
431 0 : slotref slot = slotat(slot_ref);
432 0 : if (slot)
433 : {
434 0 : int res = slot->getAttr(&seg, slat, 0);
435 0 : push(res);
436 : }
437 0 : ENDOP
438 :
439 : STARTOP(push_glyph_attr_obs)
440 0 : declare_params(2);
441 0 : const unsigned int glyph_attr = uint8(param[0]);
442 0 : const int slot_ref = int8(param[1]);
443 0 : slotref slot = slotat(slot_ref);
444 0 : if (slot)
445 0 : push(seg.glyphAttr(slot->gid(), glyph_attr));
446 0 : ENDOP
447 :
448 : STARTOP(push_glyph_metric)
449 0 : declare_params(3);
450 0 : const unsigned int glyph_attr = uint8(param[0]);
451 0 : const int slot_ref = int8(param[1]);
452 0 : const signed int attr_level = uint8(param[2]);
453 0 : slotref slot = slotat(slot_ref);
454 0 : if (slot)
455 0 : push(seg.getGlyphMetric(slot, glyph_attr, attr_level));
456 0 : ENDOP
457 :
458 : STARTOP(push_feat)
459 0 : declare_params(2);
460 0 : const unsigned int feat = uint8(param[0]);
461 0 : const int slot_ref = int8(param[1]);
462 0 : slotref slot = slotat(slot_ref);
463 0 : if (slot)
464 : {
465 0 : uint8 fid = seg.charinfo(slot->original())->fid();
466 0 : push(seg.getFeature(fid, feat));
467 : }
468 0 : ENDOP
469 :
470 : STARTOP(push_att_to_gattr_obs)
471 0 : declare_params(2);
472 0 : const unsigned int glyph_attr = uint8(param[0]);
473 0 : const int slot_ref = int8(param[1]);
474 0 : slotref slot = slotat(slot_ref);
475 0 : if (slot)
476 : {
477 0 : slotref att = slot->attachedTo();
478 0 : if (att) slot = att;
479 0 : push(seg.glyphAttr(slot->gid(), glyph_attr));
480 : }
481 0 : ENDOP
482 :
483 : STARTOP(push_att_to_glyph_metric)
484 0 : declare_params(3);
485 0 : const unsigned int glyph_attr = uint8(param[0]);
486 0 : const int slot_ref = int8(param[1]);
487 0 : const signed int attr_level = uint8(param[2]);
488 0 : slotref slot = slotat(slot_ref);
489 0 : if (slot)
490 : {
491 0 : slotref att = slot->attachedTo();
492 0 : if (att) slot = att;
493 0 : push(seg.getGlyphMetric(slot, glyph_attr, attr_level));
494 : }
495 0 : ENDOP
496 :
497 : STARTOP(push_islot_attr)
498 0 : declare_params(3);
499 0 : const attrCode slat = attrCode(uint8(param[0]));
500 0 : const int slot_ref = int8(param[1]),
501 0 : idx = uint8(param[2]);
502 0 : if ((slat == gr_slatPosX || slat == gr_slatPosY) && (flags & POSITIONED) == 0)
503 : {
504 0 : seg.positionSlots(0, *smap.begin(), *(smap.end()-1));
505 0 : flags |= POSITIONED;
506 : }
507 0 : slotref slot = slotat(slot_ref);
508 0 : if (slot)
509 : {
510 0 : int res = slot->getAttr(&seg, slat, idx);
511 0 : push(res);
512 : }
513 0 : ENDOP
514 :
515 : #if 0
516 : STARTOP(push_iglyph_attr) // not implemented
517 : NOT_IMPLEMENTED;
518 : ENDOP
519 : #endif
520 :
521 : STARTOP(pop_ret)
522 0 : const uint32 ret = pop();
523 0 : EXIT(ret);
524 : ENDOP
525 :
526 : STARTOP(ret_zero)
527 0 : EXIT(0);
528 : ENDOP
529 :
530 : STARTOP(ret_true)
531 0 : EXIT(1);
532 : ENDOP
533 :
534 : STARTOP(iattr_set)
535 0 : declare_params(2);
536 0 : const attrCode slat = attrCode(uint8(param[0]));
537 0 : const size_t idx = uint8(param[1]);
538 0 : const int val = int(pop());
539 0 : is->setAttr(&seg, slat, idx, val, smap);
540 0 : ENDOP
541 :
542 : STARTOP(iattr_add)
543 0 : declare_params(2);
544 0 : const attrCode slat = attrCode(uint8(param[0]));
545 0 : const size_t idx = uint8(param[1]);
546 0 : const int val = int(pop());
547 0 : if ((slat == gr_slatPosX || slat == gr_slatPosY) && (flags & POSITIONED) == 0)
548 : {
549 0 : seg.positionSlots(0, *smap.begin(), *(smap.end()-1));
550 0 : flags |= POSITIONED;
551 : }
552 0 : int res = is->getAttr(&seg, slat, idx);
553 0 : is->setAttr(&seg, slat, idx, val + res, smap);
554 0 : ENDOP
555 :
556 : STARTOP(iattr_sub)
557 0 : declare_params(2);
558 0 : const attrCode slat = attrCode(uint8(param[0]));
559 0 : const size_t idx = uint8(param[1]);
560 0 : const int val = int(pop());
561 0 : if ((slat == gr_slatPosX || slat == gr_slatPosY) && (flags & POSITIONED) == 0)
562 : {
563 0 : seg.positionSlots(0, *smap.begin(), *(smap.end()-1));
564 0 : flags |= POSITIONED;
565 : }
566 0 : int res = is->getAttr(&seg, slat, idx);
567 0 : is->setAttr(&seg, slat, idx, res - val, smap);
568 0 : ENDOP
569 :
570 : STARTOP(push_proc_state)
571 : // declare_params(1);
572 : // unsigned int pstate = uint8(*param);
573 : // pstate = 0; // This is here to stop the compiler bleating about unused
574 : // variables.
575 : // TODO; Implement body
576 0 : use_params(1);
577 0 : push(1);
578 0 : ENDOP
579 :
580 : STARTOP(push_version)
581 0 : push(0x00030000);
582 0 : ENDOP
583 :
584 : STARTOP(put_subs)
585 0 : declare_params(5);
586 0 : const int slot_ref = int8(param[0]);
587 0 : const unsigned int input_class = uint8(param[1]) << 8
588 0 : | uint8(param[2]);
589 0 : const unsigned int output_class = uint8(param[3]) << 8
590 0 : | uint8(param[4]);
591 0 : slotref slot = slotat(slot_ref);
592 0 : if (slot)
593 : {
594 0 : int index = seg.findClassIndex(input_class, slot->gid());
595 0 : is->setGlyph(&seg, seg.getClassGlyph(output_class, index));
596 : }
597 0 : ENDOP
598 :
599 : #if 0
600 : STARTOP(put_subs2) // not implemented
601 : NOT_IMPLEMENTED;
602 : ENDOP
603 :
604 : STARTOP(put_subs3) // not implemented
605 : NOT_IMPLEMENTED;
606 : ENDOP
607 : #endif
608 :
609 : STARTOP(put_glyph)
610 0 : declare_params(2);
611 0 : const unsigned int output_class = uint8(param[0]) << 8
612 0 : | uint8(param[1]);
613 0 : is->setGlyph(&seg, seg.getClassGlyph(output_class, 0));
614 0 : ENDOP
615 :
616 : STARTOP(push_glyph_attr)
617 0 : declare_params(3);
618 0 : const unsigned int glyph_attr = uint8(param[0]) << 8
619 0 : | uint8(param[1]);
620 0 : const int slot_ref = int8(param[2]);
621 0 : slotref slot = slotat(slot_ref);
622 0 : if (slot)
623 0 : push(seg.glyphAttr(slot->gid(), glyph_attr));
624 0 : ENDOP
625 :
626 : STARTOP(push_att_to_glyph_attr)
627 0 : declare_params(3);
628 0 : const unsigned int glyph_attr = uint8(param[0]) << 8
629 0 : | uint8(param[1]);
630 0 : const int slot_ref = int8(param[2]);
631 0 : slotref slot = slotat(slot_ref);
632 0 : if (slot)
633 : {
634 0 : slotref att = slot->attachedTo();
635 0 : if (att) slot = att;
636 0 : push(seg.glyphAttr(slot->gid(), glyph_attr));
637 : }
638 0 : ENDOP
639 :
640 : STARTOP(temp_copy)
641 0 : slotref newSlot = seg.newSlot();
642 0 : int16 *tempUserAttrs = newSlot->userAttrs();
643 0 : memcpy(newSlot, is, sizeof(Slot));
644 0 : memcpy(tempUserAttrs, is->userAttrs(), seg.numAttrs() * sizeof(uint16));
645 0 : newSlot->userAttrs(tempUserAttrs);
646 0 : newSlot->markCopied(true);
647 0 : *map = newSlot;
648 0 : ENDOP
|