line
stmt
bran
cond
sub
pod
time
code
1
####################################################################
2
#
3
# This file was generated using Parse::Yapp version 1.05.
4
#
5
# Don't edit this file, use source file instead.
6
#
7
# ANY CHANGE MADE HERE WILL BE LOST !
8
#
9
####################################################################
10
package PerlPoint::Parser;
11
34
34
241814
use vars qw ( @ISA );
34
84
34
2503
12
34
34
262
use strict;
34
81
34
7231
13
14
@ISA= qw ( Parse::Yapp::Driver );
15
#Included Parse/Yapp/Driver.pm file----------------------------------------
16
{
17
#
18
# Module Parse::Yapp::Driver
19
#
20
# This module is part of the Parse::Yapp package available on your
21
# nearest CPAN
22
#
23
# Any use of this module in a standalone parser make the included
24
# text under the same copyright as the Parse::Yapp module itself.
25
#
26
# This notice should remain unchanged.
27
#
28
# (c) Copyright 1998-2001 Francois Desarmenien, all rights reserved.
29
# (see the pod text in Parse::Yapp module for use and distribution rights)
30
#
31
32
package Parse::Yapp::Driver;
33
34
require 5.004;
35
36
34
34
199
use strict;
34
71
34
1067
37
38
34
34
168
use vars qw ( $VERSION $COMPATIBLE $FILENAME );
34
76
34
2697
39
40
$VERSION = '1.05';
41
$COMPATIBLE = '0.07';
42
$FILENAME=__FILE__;
43
44
34
34
207
use Carp;
34
112
34
41557
45
46
#Known parameters, all starting with YY (leading YY will be discarded)
47
my(%params)=(YYLEX => 'CODE', 'YYERROR' => 'CODE', YYVERSION => '',
48
YYRULES => 'ARRAY', YYSTATES => 'ARRAY', YYDEBUG => '');
49
#Mandatory parameters
50
my(@params)=('LEX','RULES','STATES');
51
52
sub new {
53
35
35
151
my($class)=shift;
54
35
86
my($errst,$nberr,$token,$value,$check,$dotpos);
55
35
539
my($self)={ ERROR => \&_Error,
56
ERRST => \$errst,
57
NBERR => \$nberr,
58
TOKEN => \$token,
59
VALUE => \$value,
60
DOTPOS => \$dotpos,
61
STACK => [],
62
DEBUG => 0,
63
CHECK => \$check };
64
65
35
252
_CheckParams( [], \%params, \@_, $self );
66
67
35
50
33
557
exists($$self{VERSION})
68
and $$self{VERSION} < $COMPATIBLE
69
and croak "Yapp driver version $VERSION ".
70
"incompatible with version $$self{VERSION}:\n".
71
"Please recompile parser module.";
72
73
35
50
181
ref($class)
74
and $class=ref($class);
75
76
35
246
bless($self,$class);
77
}
78
79
sub YYParse {
80
37
37
258
my($self)=shift;
81
37
998
my($retval);
82
83
37
853
_CheckParams( \@params, \%params, \@_, $self );
84
85
37
50
240
if($$self{DEBUG}) {
86
0
0
_DBLoad();
87
0
0
$retval = eval '$self->_DBParse()';#Do not create stab entry on compile
88
0
0
0
$@ and die $@;
89
}
90
else {
91
37
933
$retval = $self->_Parse();
92
}
93
37
401
$retval
94
}
95
96
sub YYData {
97
0
0
0
my($self)=shift;
98
99
0
0
0
exists($$self{USER})
100
or $$self{USER}={};
101
102
0
0
$$self{USER};
103
104
}
105
106
sub YYErrok {
107
0
0
0
my($self)=shift;
108
109
0
0
${$$self{ERRST}}=0;
0
0
110
0
0
undef;
111
}
112
113
sub YYNberr {
114
0
0
0
my($self)=shift;
115
116
0
0
${$$self{NBERR}};
0
0
117
}
118
119
sub YYRecovering {
120
0
0
0
my($self)=shift;
121
122
0
0
${$$self{ERRST}} != 0;
0
0
123
}
124
125
sub YYAbort {
126
0
0
0
my($self)=shift;
127
128
0
0
${$$self{CHECK}}='ABORT';
0
0
129
0
0
undef;
130
}
131
132
sub YYAccept {
133
33
33
115
my($self)=shift;
134
135
33
207
${$$self{CHECK}}='ACCEPT';
33
701
136
33
94
undef;
137
}
138
139
sub YYError {
140
0
0
0
my($self)=shift;
141
142
0
0
${$$self{CHECK}}='ERROR';
0
0
143
0
0
undef;
144
}
145
146
sub YYSemval {
147
0
0
0
my($self)=shift;
148
0
0
my($index)= $_[0] - ${$$self{DOTPOS}} - 1;
0
0
149
150
0
0
$index < 0
151
0
0
0
0
and -$index <= @{$$self{STACK}}
152
and return $$self{STACK}[$index][1];
153
154
0
0
undef; #Invalid index
155
}
156
157
sub YYCurtok {
158
8
8
13
my($self)=shift;
159
160
@_
161
8
100
22
and ${$$self{TOKEN}}=$_[0];
4
9
162
8
9
${$$self{TOKEN}};
8
34
163
}
164
165
sub YYCurval {
166
28
28
49
my($self)=shift;
167
168
@_
169
28
100
70
and ${$$self{VALUE}}=$_[0];
4
10
170
28
36
${$$self{VALUE}};
28
244
171
}
172
173
sub YYExpect {
174
4
4
12
my($self)=shift;
175
176
4
8
keys %{$self->{STATES}[$self->{STACK}[-1][0]]{ACTIONS}}
4
247
177
}
178
179
sub YYLexer {
180
0
0
0
my($self)=shift;
181
182
0
0
$$self{LEX};
183
}
184
185
186
#################
187
# Private stuff #
188
#################
189
190
191
sub _CheckParams {
192
72
72
250
my($mandatory,$checklist,$inarray,$outhash)=@_;
193
72
168
my($prm,$value);
194
72
210
my($prmlst)={};
195
196
72
701
while(($prm,$value)=splice(@$inarray,0,2)) {
197
216
514
$prm=uc($prm);
198
216
50
937
exists($$checklist{$prm})
199
or croak("Unknow parameter '$prm'");
200
216
50
813
ref($value) eq $$checklist{$prm}
201
or croak("Invalid value for parameter '$prm'");
202
216
1014
$prm=unpack('@2A*',$prm);
203
216
1741
$$outhash{$prm}=$value;
204
}
205
72
412
for (@$mandatory) {
206
111
50
704
exists($$outhash{$_})
207
or croak("Missing mandatory parameter '".lc($_)."'");
208
}
209
}
210
211
sub _Error {
212
0
0
0
print "Parse error.\n";
213
}
214
215
sub _DBLoad {
216
{
217
34
34
252
no strict 'refs';
34
0
87
34
151352
0
0
218
219
0
0
0
exists(${__PACKAGE__.'::'}{_DBParse})#Already loaded ?
0
0
220
and return;
221
}
222
0
0
my($fname)=__FILE__;
223
0
0
my(@drv);
224
0
0
0
open(DRV,"<$fname") or die "Report this as a BUG: Cannot open $fname";
225
0
0
while() {
226
/^\s*sub\s+_Parse\s*{\s*$/ .. /^\s*}\s*#\s*_Parse\s*$/
227
0
0
0
and do {
228
0
0
s/^#DBG>//;
229
0
0
push(@drv,$_);
230
}
231
}
232
0
0
close(DRV);
233
234
0
0
$drv[0]=~s/_P/_DBP/;
235
0
0
eval join('',@drv);
236
}
237
238
#Note that for loading debugging version of the driver,
239
#this file will be parsed from 'sub _Parse' up to '}#_Parse' inclusive.
240
#So, DO NOT remove comment at end of sub !!!
241
sub _Parse {
242
37
37
6580
my($self)=shift;
243
244
37
498
my($rules,$states,$lex,$error)
245
= @$self{ 'RULES', 'STATES', 'LEX', 'ERROR' };
246
37
336
my($errstatus,$nberror,$token,$value,$stack,$check,$dotpos)
247
= @$self{ 'ERRST', 'NBERR', 'TOKEN', 'VALUE', 'STACK', 'CHECK', 'DOTPOS' };
248
249
#DBG> my($debug)=$$self{DEBUG};
250
#DBG> my($dbgerror)=0;
251
252
#DBG> my($ShowCurToken) = sub {
253
#DBG> my($tok)='>';
254
#DBG> for (split('',$$token)) {
255
#DBG> $tok.= (ord($_) < 32 or ord($_) > 126)
256
#DBG> ? sprintf('<%02X>',ord($_))
257
#DBG> : $_;
258
#DBG> }
259
#DBG> $tok.='<';
260
#DBG> };
261
262
37
115
$$errstatus=0;
263
37
93
$$nberror=0;
264
37
136
($$token,$$value)=(undef,undef);
265
37
381
@$stack=( [ 0, undef ] );
266
37
212
$$check='';
267
268
37
112
while(1) {
269
27940
48971
my($actions,$act,$stateno);
270
271
27940
47748
$stateno=$$stack[-1][0];
272
27940
42143
$actions=$$states[$stateno];
273
274
#DBG> print STDERR ('-' x 40),"\n";
275
#DBG> $debug & 0x2
276
#DBG> and print STDERR "In state $stateno:\n";
277
#DBG> $debug & 0x08
278
#DBG> and print STDERR "Stack:[".
279
#DBG> join(',',map { $$_[0] } @$stack).
280
#DBG> "]\n";
281
282
283
27940
100
66319
if (exists($$actions{ACTIONS})) {
284
285
defined($$token)
286
7108
100
24135
or do {
287
5882
30397
($$token,$$value)=&$lex($self);
288
#DBG> $debug & 0x01
289
#DBG> and print STDERR "Need token. Got ".&$ShowCurToken."\n";
290
};
291
292
7108
100
49069
$act= exists($$actions{ACTIONS}{$$token})
100
293
? $$actions{ACTIONS}{$$token}
294
: exists($$actions{DEFAULT})
295
? $$actions{DEFAULT}
296
: undef;
297
}
298
else {
299
20832
67655
$act=$$actions{DEFAULT};
300
#DBG> $debug & 0x01
301
#DBG> and print STDERR "Don't need token.\n";
302
}
303
304
defined($act)
305
27940
100
66730
and do {
306
307
$act > 0
308
27936
100
66487
and do { #shift
309
310
#DBG> $debug & 0x04
311
#DBG> and print STDERR "Shift and go to state $act.\n";
312
313
$$errstatus
314
5878
50
12826
and do {
315
0
0
--$$errstatus;
316
317
#DBG> $debug & 0x10
318
#DBG> and $dbgerror
319
#DBG> and $$errstatus == 0
320
#DBG> and do {
321
#DBG> print STDERR "**End of Error recovery.\n";
322
#DBG> $dbgerror=0;
323
#DBG> };
324
};
325
326
327
5878
14141
push(@$stack,[ $act, $$value ]);
328
329
5878
100
18071
$$token ne '' #Don't eat the eof
330
and $$token=$$value=undef;
331
5878
9334
next;
332
};
333
334
#reduce
335
22058
28720
my($lhs,$len,$code,@sempar,$semval);
336
22058
25786
($lhs,$len,$code)=@{$$rules[-$act]};
22058
68928
337
338
#DBG> $debug & 0x04
339
#DBG> and $act
340
#DBG> and print STDERR "Reduce using rule ".-$act." ($lhs,$len): ";
341
342
22058
100
64963
$act
343
or $self->YYAccept();
344
345
22058
28630
$$dotpos=$len;
346
347
unpack('A1',$lhs) eq '@' #In line rule
348
22058
100
95224
and do {
349
1884
50
10398
$lhs =~ /^\@[0-9]+\-([0-9]+)$/
350
or die "In line rule name '$lhs' ill formed: ".
351
"report it as a BUG.\n";
352
1884
4239
$$dotpos = $1;
353
};
354
355
30567
85523
@sempar = $$dotpos
356
22058
100
92002
? map { $$_[1] } @$stack[ -$$dotpos .. -1 ]
357
: ();
358
359
22058
100
81848
$semval = $code ? &$code( $self, @sempar )
100
360
: @sempar ? $sempar[0] : undef;
361
362
22058
56718
splice(@$stack,-$len,$len);
363
364
$$check eq 'ACCEPT'
365
22058
100
76558
and do {
366
367
#DBG> $debug & 0x04
368
#DBG> and print STDERR "Accept.\n";
369
370
33
309
return($semval);
371
};
372
373
$$check eq 'ABORT'
374
22025
50
81225
and do {
375
376
#DBG> $debug & 0x04
377
#DBG> and print STDERR "Abort.\n";
378
379
0
0
return(undef);
380
381
};
382
383
#DBG> $debug & 0x04
384
#DBG> and print STDERR "Back to state $$stack[-1][0], then ";
385
386
$$check eq 'ERROR'
387
22025
50
86602
or do {
388
#DBG> $debug & 0x04
389
#DBG> and print STDERR
390
#DBG> "go to state $$states[$$stack[-1][0]]{GOTOS}{$lhs}.\n";
391
392
#DBG> $debug & 0x10
393
#DBG> and $dbgerror
394
#DBG> and $$errstatus == 0
395
#DBG> and do {
396
#DBG> print STDERR "**End of Error recovery.\n";
397
#DBG> $dbgerror=0;
398
#DBG> };
399
400
22025
86899
push(@$stack,
401
[ $$states[$$stack[-1][0]]{GOTOS}{$lhs}, $semval ]);
402
22025
38287
$$check='';
403
22025
59965
next;
404
};
405
406
#DBG> $debug & 0x04
407
#DBG> and print STDERR "Forced Error recovery.\n";
408
409
0
0
$$check='';
410
411
};
412
413
#Error
414
$$errstatus
415
4
50
21
or do {
416
417
4
14
$$errstatus = 1;
418
4
25
&$error($self);
419
4
50
25
$$errstatus # if 0, then YYErrok has been called
420
or next; # so continue parsing
421
422
#DBG> $debug & 0x10
423
#DBG> and do {
424
#DBG> print STDERR "**Entering Error recovery.\n";
425
#DBG> ++$dbgerror;
426
#DBG> };
427
428
4
12
++$$nberror;
429
430
};
431
432
$$errstatus == 3 #The next token is not valid: discard it
433
4
50
18
and do {
434
$$token eq '' # End of input: no hope
435
0
0
0
and do {
436
#DBG> $debug & 0x10
437
#DBG> and print STDERR "**At eof: aborting.\n";
438
0
0
return(undef);
439
};
440
441
#DBG> $debug & 0x10
442
#DBG> and print STDERR "**Dicard invalid token ".&$ShowCurToken.".\n";
443
444
0
0
$$token=$$value=undef;
445
};
446
447
4
11
$$errstatus=3;
448
449
4
33
103
while( @$stack
66
450
and ( not exists($$states[$$stack[-1][0]]{ACTIONS})
451
or not exists($$states[$$stack[-1][0]]{ACTIONS}{error})
452
or $$states[$$stack[-1][0]]{ACTIONS}{error} <= 0)) {
453
454
#DBG> $debug & 0x10
455
#DBG> and print STDERR "**Pop state $$stack[-1][0].\n";
456
457
16
125
pop(@$stack);
458
}
459
460
@$stack
461
4
50
20
or do {
462
463
#DBG> $debug & 0x10
464
#DBG> and print STDERR "**No state left on stack: aborting.\n";
465
466
4
39
return(undef);
467
};
468
469
#shift the error token
470
471
#DBG> $debug & 0x10
472
#DBG> and print STDERR "**Shift \$error token and go to state ".
473
#DBG> $$states[$$stack[-1][0]]{ACTIONS}{error}.
474
#DBG> ".\n";
475
476
0
push(@$stack, [ $$states[$$stack[-1][0]]{ACTIONS}{error}, undef ]);
477
478
}
479
480
#never reached
481
0
croak("Error in driver logic. Please, report it as a BUG");
482
483
}#_Parse
484
#DO NOT remove comment
485
486
1;
487
488
}
489
#End of include--------------------------------------------------
490
491
492
#line 10 "ppParser.yp"
493
494
495
# = HISTORY SECTION =====================================================================
496
497
# ---------------------------------------------------------------------------------------
498
# version | date | author | changes
499
# ---------------------------------------------------------------------------------------
500
# 0.452 |10.10.2007| JSTENZEL | just for the release;
501
# 0.451 |06.10.2007| JSTENZEL | just for the release;
502
# 0.45 |03.12.2006| JSTENZEL | just for the release;
503
# 0.44 |15.06.2006| JSTENZEL | new type "parsedexample" for \INCLUDE;
504
# |06.08.2006| JSTENZEL | bugfix in parameter check of _evalTagCondition(): using
505
# | | | "if defined $par" instead of "if $par";
506
# |27.11.2006| JSTENZEL | better definition of flagSet() etc., old implementation
507
# | | | was buggy;
508
# 0.43 |09.04.2006| JSTENZEL | slight code optimizations in file embedding;
509
# | | JSTENZEL | INCLUDE now has an "import" option with module API;
510
# | | JSTENZEL | included file type and embedded language now have
511
# | | | default "pp";
512
# | | JSTENZEL | run(): new configuration parameter "importMapping";
513
# 0.42 |05.03.2006| JSTENZEL | non kernel tags now can be configured to be standalone,
514
# | | | in which case a wrapping paragraph is removed from the
515
# | | | stream (IMAGE and LOCALTOC configuration moved to tag
516
# | | | definition);
517
# | | | area, the wrapping paragraph is removed;
518
# |07.03.2006| JSTENZEL | dummy tokens inserted by the parser now are special
519
# | | | strings that can be filtered out by the backend module;
520
# |10.03.2006| JSTENZEL | bugfix: statistics for list shifters did not work;
521
# | | JSTENZEL | Macro default parameters were not documented! Added.
522
# 0.41 |15.12.2005| JSTENZEL | almost all routines are internal, to avoid Pod::Coverage
523
# | | | complaints they now begin with an underscore;
524
# 0.40 |12.06.2003| JSTENZEL | bugfix: delayed tokens were not reparsed when reinserted,
525
# | | | this could cause trouble when the paragraph (special
526
# | | | characters) context changed between the point the
527
# | | | token was detected first and delayed, and the point
528
# | | | the token is reinserted into the stream (especially
529
# | | | important after file inclusion, when the stacked token
530
# | | | is a newline, has to be evaluated in STATE_DEFAULT
531
# | | | but was stacked in a paragraph where newlines are not
532
# | | | ignored;
533
# | | JSTENZEL | additionally, "empty paragraphs" (*skipped* paragraphs)
534
# | | | now are not only *really* empty paragraphs but all
535
# | | | paragraphs containing of whitespaces only;
536
# |21.06.2003| JSTENZEL | headlines provide additional data: their numerical, full
537
# | | | and shortcut pathes;
538
# |22.06.2003| JSTENZEL | _normalizeTableRows() now supplies number of columns both
539
# | | | in title row and the maximum value;
540
# | | JSTENZEL | new warning if the maximum columns number is detected
541
# | | | in another line than the first table line (which is the
542
# | | | base of normalization);
543
# |10.08.2003| JSTENZEL | new helper function _semerr() to report semantic errors;
544
# | | JSTENZEL | new option -criticalSemanticErrors;
545
# |14.08.2003| JSTENZEL | input filters can access the source file by a variable
546
# | | | $main::_ifilterFile now;
547
# | | JSTENZEL | fixed an "undefined value" warning;
548
# |17.08.2003| JSTENZEL | bugfix: docstream "main" was ignored like any other docstream
549
# | | | if working in the "docstream ignore" mode;
550
# |10.09.2003| JSTENZEL | definition list explanations ("texts" now have an own
551
# | | | enveloping directive (DIRECTIVE_DPOINT_TEXT);
552
# |11.09.2003| JSTENZEL | LOCALTOC added to the list of standalone tags (which are
553
# | | | stripped of of an enveloping text paragraph if they are its
554
# | | | only contents);
555
# |05.05.2004| JSTENZEL | anchors now take the number of the page they are defined in;
556
# | | JSTENZEL | tag hooks now take an additional parameter: the number of
557
# | | | the page the tag is used on;
558
# | | JSTENZEL | bugfix: numerical pathes were built incorrectly: when entering
559
# | | | a new sublevel, the counter was not reset to 1;
560
# | | JSTENZEL | added anchors();
561
# |11.07.2004| JSTENZEL | headlines now provide a path of absolute page numbers as well
562
# | | | and a variable snapshot;
563
# | | JSTENZEL | a reset variable is removed now (as a side effect, it is no
564
# | | | longer possible to build variables containing spaces only);
565
# |24.07.2004| JSTENZEL | added -skipcomments;
566
# |10.09.2004| JSTENZEL | bugfix: words looking like symbolic variables (but not defined
567
# | | | as such) were restored without their braces ("{}");
568
# |27.12.2004| JSTENZEL | bugfix: skipped headline levels were filled with previous
569
# | | | headline strings of those levels;
570
# |28.12.2004| JSTENZEL | text paragraphs now have their own special character, but
571
# | | | optional: a dot;
572
# |24.02.2005| JSTENZEL | acceleration: the lexer built some data very often;
573
# |27.02.2005| JSTENZEL | bugfix: backslashes before variables were handled incorrectly,
574
# | | | now variables are no longer "boosted" but handled like macros
575
# | | | - which has a performance drawback, unfortunately ...;
576
# |16.05.2005| JSTENZEL | backslashes in tag options are no longer ignored but can be
577
# | | | used to guard characters;
578
# |23.08.2005| JSTENZEL | first chapter is checked for a headline now;
579
# 0.39 |01.02.2003| JSTENZEL | passing directive id chain of the current chapter
580
# | | | headline to tag hook functions now;
581
# |07.03.2003| JSTENZEL | several variable patterns were used explicitly instead
582
# | | | if the precompiled ones from %lexerPatterns;
583
# | | JSTENZEL | bugfix: guarded variables were expanded;
584
# | | JSTENZEL | now it is documented that list indentation is reset
585
# | | | automatically by a subsequent non list paragraph;
586
# |26.04.2003| JSTENZEL | added "no utf8" to avoid errors under perl 5.8;
587
# |01.05.2003| JSTENZEL | adding *all* composite anchors for headlines, not only
588
# | | | for the full path;
589
# 0.38 |07.06.2002| JSTENZEL | restoring doubled backslashes in filtered paragraphs,
590
# | | | restoring ">" characters as if they were guarded;
591
# |04.07.2002| JSTENZEL | simplified several array field access codes;
592
# | | JSTENZEL | bugfix: empty headlines caused an infinite loop
593
# | | | when trailing whitespaces should be removed;
594
# | | JSTENZEL | bugfix: empty headlines caused a failure when headline
595
# | | | anchors should be stored, skipping them now;
596
# |20.08.2002| JSTENZEL | improved tag streaming: stream now contains a body hint;
597
# | | JSTENZEL | bugfix: paragraph filters restored tag bodies even if
598
# | | | there was no body;
599
# | | JSTENZEL | old caches need to be updated - adapted compatibility hint;
600
# |27.08.2002| JSTENZEL | started to use precompiled lexer patterns;
601
# |31.08.2002| JSTENZEL | \INCLUDE, \EMBED and \TABLE now support the _cnd_ option,
602
# | | | like tags defined externally;
603
# |04.12.2002| JSTENZEL | bugfix in pfilter retranslation: backslash reinsertion was
604
# | | | not performed multiply;
605
# | | JSTENZEL | pfilter retranslation: backslash reinsertion now suppressed
606
# | | | in verbatim blocks;
607
# |01.01.2003| JSTENZEL | added input filter support to \EMBED, via option "ifilter";
608
# |02.01.2003| JSTENZEL | added input filter support to \INCLUDE, same interface;
609
# 0.37 |up to | JSTENZEL | flagSet() now takes a list of flag names;
610
# |14.04.2002| JSTENZEL | names of included files are resolved to avoid trouble
611
# | | | with links (and to avoid error messages);
612
# | | JSTENZEL | \INCLUDE searches pathes specified in environment
613
# | | | variable PERLPOINTLIB (like perl, shells, linkers etc.);
614
# | | JSTENZEL | if tags with finish hooks are used, a paragraph will
615
# | | | not be cached because it becomes potentially dynamic;
616
# | | JSTENZEL | anchors defined by a cached paragraph are cached now
617
# | | | as well - and restored after a cache hit (updated cache
618
# | | | format);
619
# | | JSTENZEL | \INCLUDE additionally searches pathes specified in an
620
# | | | array passed to method run() via new parameter "libpath";
621
# | | JSTENZEL | Filtered paragraphs that need a parser lookahead into
622
# | | | the next paragraph to be completely detected could cause
623
# | | | trouble because the reinserted result was grammatically
624
# | | | placed before the already parsed start token of the
625
# | | | subsequent paragraph. Fixed by introducing a virtual,
626
# | | | empty "Word" token supplied by the lexer in such cases
627
# | | | (look for $flags{virtualParagraphStart} and
628
# | | | $lexerFlags{cbell}). (By the way, this outdated an
629
# | | | earlier solution using a virtual text paragraph startup
630
# | | | and a delayed token - this former solution caused trouble
631
# | | | when the paragraph following the filtered one was not
632
# | | | a pure text (so even filtered texts did not work)).
633
# | | JSTENZEL | Filtered paragraphs are no longer cached - the filter
634
# | | | makes them dynamical. Note that for combined paragraphs
635
# | | | like compound blocks and lists this is true for the first
636
# | | | part only, because subsequent parts can be cached in
637
# | | | their original form (the filter will be applied when the
638
# | | | parts will have been combined).
639
# | | JSTENZEL | paragraph filters: added retranslation of headlines and
640
# | | | verbatim blocks;
641
# | | JSTENZEL | passing original paragraph type to filters by new variable
642
# | | | $main::_pfilterType;
643
# | | JSTENZEL | generalized paragraph type constant to string translation;
644
# | | JSTENZEL | lexer delays to flag the end of the document source
645
# | | | when a paragraph filter still needs to be applied
646
# | | | (otherwise, the parser would not request more tokens
647
# | | | because from his point of view the source was already
648
# | | | parsed completely, so the filtering result (and the
649
# | | | original block) would disappear from the result - it would
650
# | | | not be reparsed);
651
# | | JSTENZEL | empty text paragraphs are no longer made part of the stream;
652
# | | JSTENZEL | blocks were streamed with a final newline, improved;
653
# | | JSTENZEL | added headline shortcuts;
654
# | | JSTENZEL | added document stream entry points;
655
# |15.04.2002| JSTENZEL | added chapter docstream hints to headline stream data;
656
# 0.36 |10.08.2001| JSTENZEL | the stream became a more complex data structure to
657
# | | | allow converter authors to act according to a documents
658
# | | | structure (getting headlines without having to process
659
# | | | all tokens, moving between chapters) - basically, it
660
# | | | *remained* a stream (with additional structure info);
661
# |29.09.2001| JSTENZEL | adapted stream initialization to intermediately
662
# | | | modified design;
663
# | | JSTENZEL | bugfixes in _normalizeTableRows(): standalone single "0"
664
# | | | in table cells was removed;
665
# |07.10.2001| JSTENZEL | improved error messages provide an error pointer;
666
# |11.10.2001| JSTENZEL | removed unused "use fields" directive;
667
# | | JSTENZEL | storing headline anchors now, depending on new
668
# | | | flag headlineLinks;
669
# | | JSTENZEL | modified tag hook interface, tag body array is now
670
# | | | passed by *reference*;
671
# | | JSTENZEL | passing anchor object to tag hooks;
672
# |12.10.2001| JSTENZEL | added tag finish hook interface;
673
# |13.10.2001| JSTENZEL | list shifts are no longer flagged by DIRECTIVE_START
674
# | | | *and* DIRECTIVE_COMPLETED, no just by DIRECTIVE_START;
675
# | | JSTENZEL | headline start directives in the stream now provide
676
# | | | the full (plain) headline;
677
# | | JSTENZEL | added tag conditions;
678
# |14.10.2001| JSTENZEL | bugfix: passed tag options to parsing hooks instead
679
# | | | of tag body;
680
# | | JSTENZEL | using new stream directive index constants;
681
# | | JSTENZEL | stream directives now begin with a hash reference to
682
# | | | pass backend hints;
683
# |17.10.2001| JSTENZEL | new directive format results in modified cache format,
684
# | | | adapted automatic update;
685
# |27.10.2001| JSTENZEL | list directives now contain hints about predecessing
686
# | | | or following list shifts;
687
# |29.10.2001| JSTENZEL | added paragraph filters (in a first version for verb. blocks);
688
# |16.11.2001| JSTENZEL | improved _Error();
689
# | | JSTENZEL | improved lexer traces (did hide lines in verb. blocks and
690
# | | | comments;
691
# | | JSTENZEL | Heredoc close sequence detection is no longer restricted
692
# | | | to original source lines but also active for lines gotten
693
# | | | from stack - this became possible because verbatim block
694
# | | | lines are scanned in *completely* since version 0.34.
695
# | | | As a result, it is possible now to generate verbatim
696
# | | | blocks via active contents, but it is still impossible
697
# | | | to do this for blocks and text paragraphs beginning with
698
# | | | a tag or macro.
699
# |17.11.2001| JSTENZEL | implemented a more general paragraph filter approach
700
# | | | (still incomplete: needs to be extended for lists, needs
701
# | | | retranslation of paragraph stream into text);
702
# |18.11.2001| JSTENZEL | slightly improved _stackInput() (initially empty lines
703
# | | | buffers would have been stacked, and a final buffer value
704
# | | | of "0" would have been ignored);
705
# | | JSTENZEL | detection of block starts and text paragraphs beginning
706
# | | | with a line now take stacked lines into consideration
707
# | | | - this was suppressed because stacked input can begin
708
# | | | anywhere in a real line and not just at the beginning,
709
# | | | but now it is checked if there was a trailing \n in the
710
# | | | previous stack entry (we do not have to check previous
711
# | | | non stacked lines because there is no way to produce
712
# | | | a beginning paragraph on the stack without a leading
713
# | | | (and therefore stacked) empty line);
714
# | | JSTENZEL | text passed to paragraph filters is now retranslated from
715
# | | | the paragraphs streams (implementation still incomplete);
716
# |21.11.2001| JSTENZEL | macro definitions can now optionally take option defaults;
717
# |22.11.2001| JSTENZEL | bugfix in macro definition tag option handling: no boost!;
718
# |01.12.2001| JSTENZEL | tables can be filtered now;
719
# | | JSTENZEL | Compound paragraphs can be filtered now!
720
# | | JSTENZEL | lists can be filtered now, added retranslation parts;
721
# | | JSTENZEL | slightly restructered lexer parts: new _lineStartResearch();
722
# |02.12.2002| JSTENZEL | slightly restructered lexer parts: new _refLexed()
723
# | | | (to detect streamed parts placed in the input line, must
724
# | | | have beed happened before as well??);
725
# 0.35 |16.06.2001| JSTENZEL | text paragraphs containing an image only are now
726
# | | | transformed into just the image;
727
# |22.07.2001| JSTENZEL | in order to make it run under 5.005 again, a pseudo
728
# | | | hash was replaced by a pure and simple standard hash;
729
# |22.07.2001| JSTENZEL | improved the "specials" pattern in lexer() by guarding "-";
730
# |23.07.2001| JSTENZEL | opening input files in binmode() for Windows compatibility;
731
# 0.34 |14.03.2001| JSTENZEL | added parsing time report;
732
# | | JSTENZEL | slight code optimizations;
733
# |20.03.2001| JSTENZEL | introduced tag templates declared via PerlPoint::Tags:
734
# |22.03.2001| JSTENZEL | bugfix: macros could not contain "0":
735
# | | JSTENZEL | comments are now read at once, no longer lexed and parsed,
736
# | | | likewise, verbatim block lines are handled as one word;
737
# |25.03.2001| JSTENZEL | special character activation in tags is now nearer to the
738
# | | | related grammatical constructs, so "<" is no longer a
739
# | | | special after the tag body is opened;
740
# | | JSTENZEL | completed tag template interface by checks of mandatory
741
# | | | parts and hooks into the parser to check options and body;
742
# |01.04.2001| JSTENZEL | paragraphs using macros or variables are cached now -
743
# | | | they can be reused unless macro/variable settings change;
744
# | | JSTENZEL | cache structure now stores parser version for compatibility
745
# | | | checks;
746
# |08.04.2001| JSTENZEL | removed ACCEPT_ALL support;
747
# | | JSTENZEL | improved special character handling in tag recognition
748
# | | | furtherly: "=" is now very locally specialized;
749
# | | JSTENZEL | tag option and body hooks now take the tag occurence line
750
# | | | number as their first argument, not the tag name which is
751
# | | | of course already known to the hook function author;
752
# | | JSTENZEL | The new macro caching feature allowed to improve the cache
753
# | | | another way: constructions looking like a tag or macro but
754
# | | | being none of them were streamed and cached like strings
755
# | | | (because they *were* strings). If later on somebody declared
756
# | | | such a macro, the cache still found the paragraph unchanged
757
# | | | (same checksum) and reused the old stream instead of building
758
# | | | a new stream on base of the resolved macro. Now, if something
759
# | | | looks like a macro, the macro cache checksum feature is
760
# | | | activated, so every later macro definition will prevent the
761
# | | | cached string representation of being reused. Instead of
762
# | | | this, the new macro will be resolved, and the new resulting
763
# | | | paragraph stream will be cached. This is by far more
764
# | | | transparent and intuitive.
765
# |11.04.2001| JSTENZEL | added predeclared variables;
766
# |19.04.2001| JSTENZEL | embedded Perl code offering no code is ignored now;
767
# |21.04.2001| JSTENZEL | replaced call to Parse::Yapps parser object method YYData()
768
# | | | by direct access to its built in hash entry USER as suggested
769
# | | | by the Parse::Yapp manual for reasons of efficiency;
770
# | | JSTENZEL | bugfix: all parts restored from @inputStack were handled as
771
# | | | new lines which caused several unnecessay operations including
772
# | | | line number updates, cache paragraph checksumming and
773
# | | | removal of "leading" whitespaces (tokens recognized as Ils
774
# | | | while we were still in a formerly started line) - this fix
775
# | | | should accelerate processing of documents using numerous
776
# | | | macros (when cached) and of course avoid invalid token removals;
777
# | | JSTENZEL | tables are now "normalized": if a table row contains less
778
# | | | columns than the headline row, the missed columns are
779
# | | | automatically added (this helps converters to detect empty columns);
780
# | | JSTENZEL | bugfix: internal table flags were not all reset if a table
781
# | | | was completed, thus causing streams for subsequent tables
782
# | | | being built with additional, incorrect elements;
783
# | | JSTENZEL | adapted macro handling to the new tag handling: if now options or
784
# | | | or body was declared in the macro definition, options or body are
785
# | | | not evaluated
786
# |22.04.2001| JSTENZEL | the first bugfix yesterday was too common, improved;
787
# |24.04.2001| JSTENZEL | bugfix: conditions were handled in headline state, causing
788
# | | | backslashes to be removed; new state STATE_CONDITION added;
789
# | | JSTENZEL | added first function (flagSet()) of a simplified condition
790
# | | | interface (SCI) which is intended to allow non (Perl) programmers
791
# | | | to easily understand and perform common checks;
792
# |27.04.2001| JSTENZEL | $^W is a global variable - no need to switch to the Safe
793
# | | | compartment to modify it;
794
# | | JSTENZEL | added next function (varValue()) of a the SCI;
795
# |29.04.2001| JSTENZEL | now the parser predeclares variables as well: first one is
796
# | | | $_STARTDIR to flag where processing started;
797
# |21.05.2001| JSTENZEL | bugfix in table handling: one column tables were not handled
798
# | | | correctly, modified table handling partly by the way si that
799
# | | | in the future it might become possible to have nested tables;
800
# |22.05.2001| JSTENZEL | source nesting level is now reported by an internal variable _SOURCE_LEVEL;
801
# |23.05.2001| JSTENZEL | table fields are trimmed now: beginning and trailing whitespaces are removed;
802
# |24.05.2001| JSTENZEL | text paragraphs containing only a table become just a table now;
803
# |24.05.2001| JSTENZEL | text paragraphs now longer contain a final whitespace (made from the
804
# | | | final carriage return;
805
# |25.05.2001| JSTENZEL | completed support for the new \TABLE flag option "rowseparator" which
806
# | | | allows you to separate table columns by a string of your choice enabling
807
# | | | streamed tables like in
808
# | | | "Look: \TABLE{rowseparator="+++"} c1 | c2 +++ row 2, 1 | row 2, 2 \END_TABLE";
809
# | | JSTENZEL | slightly reorganized the way tag build table streams are completed,
810
# | | | enabling a more common detection of prebuild stream parts - in fact, if
811
# | | | this description makes no sense to you, this enables to place \END_TABLE
812
# | | | even *in* the final table line instead of in a new line (as usually done
813
# | | | and documented);
814
# |26.05.2001| JSTENZEL | added new parser option "nestedTables" which enables table nesting if set
815
# | | | to a true value. made nesting finally possible;
816
# | | JSTENZEL | to help converters handling nested tables, tables now provide their
817
# | | | nesting level by the new internal table option "__nestingLevel__";
818
# |27.05.2001| JSTENZEL | cache hits are no longer mentioned in the list of expected tokens displayed
819
# | | | by _Error(), because the message is intended to be read by humans who
820
# | | | cannot insert cache hits into a document;
821
# |28.05.2001| JSTENZEL | new predeclared variable _PARSER_VERSION;
822
# | | JSTENZEL | new \INCLUDE option "localize";
823
# |31.05.2001| JSTENZEL | new headline level offset keyword "base_level";
824
# |01.06.2001| JSTENZEL | performance boost by lexing words no longer as real words or even
825
# | | | characters but as the longest strings until the next special character;
826
# |02.06.2001| JSTENZEL | improved table field trimming in _normalizeTableRows();
827
# |05.06.2001| JSTENZEL | the last line in a source file is now lexed the optimized way as well;
828
# |06.06.2001| JSTENZEL | cache structure now stores constant declarations version for compatability
829
# | | | checks;
830
# |09.06.2001| JSTENZEL | bugfix: headlines could not begin with a character that can start a
831
# | | | paragraph - fixed by introducing new state STATE_HEADLINE_LEVEL;
832
# | | JSTENZEL | variable names can contain umlauts now;
833
# | | JSTENZEL | updated inlined module documentation (POD);
834
# | | JSTENZEL | used Storable version is now stored in cache, cache is rebuilt
835
# | | | automatically if a different Storable version is detected;
836
# |10.06.2001| JSTENZEL | added code execution by eval() (on users request);
837
# |12.06.2001| JSTENZEL | code executed by eval() or do() is no started with "no strict" settings
838
# | | | to enable unlimited access to functions, like under Safe control
839
# | | | (also this is by no means optimal so it might be improved later);
840
# | | JSTENZEL | tag hooks can reply various values now;
841
# |15.06.2001| JSTENZEL | tags take exactly *one* hook into consideration now: this simplifies
842
# | | | and accelerates the interface *and* allows hooks for tags neither
843
# | | | owning option nor nody;
844
# 0.33 |22.02.2001| JSTENZEL | slightly improved PerlPoint::Parser::DelayedToken;
845
# |25.02.2001| JSTENZEL | variable values can now begin with every character;
846
# |13.03.2001| JSTENZEL | bugfix in handling cache hits for continued ordered lists:
847
# | | | list numbering is updated now;
848
# |14.03.2001| JSTENZEL | added mailing list hint to POD;
849
# | | JSTENZEL | undefined return values of embedded Perl are no longer
850
# | | | tried to be parsed, this is for example useful to
851
# | | | predeclare functions;
852
# | | JSTENZEL | slight bugfix in internal ordered list counting which
853
# | | | takes effect if an ordered list is *started* by "##";
854
# 0.32 |07.02.2001| JSTENZEL | bugfix: bodyless macros can now be used without moving
855
# | | | subsequent tokens before the macro replacement;
856
# |10.02.2001| JSTENZEL | added new special type "example" to \INCLUDE to relieve
857
# | | | people who want to include files just as examples;
858
# 0.31 |30.01.2001| JSTENZEL | ordered lists now provide the entry level number
859
# | | | (additionally to the first list point which already
860
# | | | did this if the list was continued);
861
# |01.02.2001| JSTENZEL | made POD more readable to pod2man;
862
# | | JSTENZEL | bugfix: if a headline is restored from cache, internal
863
# | | | headline level flags need to be restored as well to
864
# | | | make \INCLUDE{headlinebase=CURRENT_LEVEL} work when
865
# | | | it is the first thing in a document except of headlines
866
# | | | which are all restored from cache;
867
# | | JSTENZEL | new "smart" option of \INCLUDE tag suppresses inclusion
868
# | | | if the file was already loaded, which is useful for alias
869
# | | | definitions used both in a nested and the base source;
870
# |02.02.2001| JSTENZEL | bugfix: circular source nesting was supressed too hard:
871
# | | | a source could never be loaded twice, but this may be
872
# | | | really useful to reuse files multiply - now only the
873
# | | | currently nested sources are taken into account;
874
# |03.02.2001| JSTENZEL | bugfix: continued lists did not work as expected yet,
875
# | | | now they do (bug was detected by Lorenz), improved by
876
# | | | the way: continued list points not really continuing
877
# | | | are streamed now as usual list points (no level hint);
878
# 0.30 |05.01.2001| JSTENZEL | slight lexer improvement (removed obsolete code);
879
# | | JSTENZEL | modified the grammar a way that shift/reduce conflicts
880
# | | | were reduced (slightly) and, more important, the grammar
881
# | | | now passes yacc/bison (just a preparation);
882
# |20.01.2001| JSTENZEL | variable settings are now propagated into the stream;
883
# | | JSTENZEL | improved syntactical error messages;
884
# |23.01.2001| JSTENZEL | bugfix: embedding into tags failed because not all
885
# | | | special settings were restored correctly, especially
886
# | | | for ">" which completes a tag body;
887
# |27.01.2001| JSTENZEL | fixed "unintialized value" warning (cache statistics);
888
# | | JSTENZEL | tag implementation is now more restrictive: according
889
# | | | to the language definition tag and macro names now *have*
890
# | | | to be built from capitals and underscores, thus reducing
891
# | | | potential tag recognition confusion with ACCEPT_ALL;
892
# | | JSTENZEL | lowercased alias names in alias definitions are now
893
# | | | automatically converted into capitals because of the
894
# | | | modfied tag/macro recognition just mentioned before;
895
# | | JSTENZEL | POD: added a warning to the POD section that the cache
896
# | | | should be cleansed after introducing new macros which
897
# | | | could possibly be used as simple text before;
898
# 0.29 |21.12.2000| JSTENZEL | direct setting of $VERSION variable to enable CPAN to
899
# | | | detect and display the parser module version;
900
# | | JSTENZEL | introduced base settings for active contents provided
901
# | | | in %$PerlPoint - a new common way to pass things like
902
# | | | the current target language;
903
# |27.12.2000| JSTENZEL | closing angle brackets are to be guarded only *once*
904
# | | | now - in former versions each macro level added the need
905
# | | | of yet another backslash;
906
# |28.12.2000| JSTENZEL | macro bodies are no longer reparsed which accelerates
907
# | | | procesing of nested macros drastically (and avoids the
908
# | | | overhead and dangers of rebuilding a source string and
909
# | | | parsing it again - this way, parsing becomes easier to
910
# | | | maintain in case of syntax extensions (nevertheless, the
911
# | | | old code worked well!);
912
# 0.28 |14.12.2000| JSTENZEL | made it finally backward compatible to perl 5.005 again;
913
# 0.27 |07.12.2000| JSTENZEL | moved package namespace from "PP" to "PerlPoint";
914
# 0.26 |30.11.2000| JSTENZEL | "Perl Point" => "PerlPoint";
915
# |02.12.2000| JSTENZEL | bugfix in _stackInput() which could remove input lines;
916
# | | JSTENZEL | new headline level offset keyword "current_level";
917
# |03.12.2000| JSTENZEL | the parser now changes into a sourcefiles directory thus
918
# | | | getting able to follow relative paths in nested sources;
919
# | | JSTENZEL | bugfix in input stack: must be multi levelled - we need
920
# | | | one input stack per processed source!;
921
# | | JSTENZEL | cache data now contains headline level informations;
922
# 0.25 |22.11.2000| JSTENZEL | added notes about Storable updates;
923
# |24.11.2000| JSTENZEL | bugfix in caching of embedded parts including empty lines;
924
# | | JSTENZEL | bugfix in modified ordered point intro handling;
925
# |27.11.2000| JSTENZEL | bugfix in progress visualization;
926
# | | JSTENZEL | improved progress visualization;
927
# | | JSTENZEL | new experimental tag setting "\ACCEPT_ALL";
928
# 0.24 |10.11.2000| JSTENZEL | added incremental parsing ("caching");
929
# |18.11.2000| JSTENZEL | slightly simplified the code;
930
# | | JSTENZEL | added ordered list continuations;
931
# 0.23 |28.10.2000| JSTENZEL | bugfix: indentation in embedded code was not accepted;
932
# | | JSTENZEL | using an input stack now for improved embedding;
933
# | | JSTENZEL | tracing active contents now;
934
# 0.22 |21.10.2000| JSTENZEL | new \INCLUDE headline offset parameter;
935
# |25.10.2000| JSTENZEL | bugfixes in trace code;
936
# | | JSTENZEL | modified implementation of included file handling:
937
# | | | reopening a handle did not work in all cases with perl5.6;
938
# 0.21 |11.10.2000| JSTENZEL | improved table paragraphs;
939
# |14.10.2000| JSTENZEL | added alias/macro feature;
940
# 0.20 |10.10.2000| JSTENZEL | added table paragraphs;
941
# 0.19 |08.10.2000| JSTENZEL | added condition paragraphs;
942
# |09.10.2000| JSTENZEL | bugfix in table handling: generated stream was wrong;
943
# 0.18 |05.10.2000| JSTENZEL | embedded Perl code is evaluated now, method run() takes
944
# | | | a Safe object;
945
# |07.10.2000| JSTENZEL | Perl code can now be included as well as embedded;
946
# | | JSTENZEL | variable values are now accessible by embedded and
947
# | | | included Perl code;
948
# | | JSTENZEL | PerlPoint can now be embedded as well as included;
949
# 0.17 |04.10.2000| JSTENZEL | bugfix in documentation: colons have not to be guarded
950
# | | | in definition texts;
951
# | | JSTENZEL | bugfixes in special token handling;
952
# 0.16 |30.09.2000| JSTENZEL | updated documentation;
953
# | | JSTENZEL | bugfix in special token handling;
954
# |03.10.2000| JSTENZEL | definition list items can contain tags now;
955
# |04.10.2000| JSTENZEL | added new target language filter feature;
956
# 0.15 |06.06.2000| JSTENZEL | there were still 5.6 specific operations, using
957
# | | | IO::File now as an emulation under perl 5.005;
958
# 0.14 |03.06.2000| JSTENZEL | improved handling of special tag characters to simplify
959
# | | | PP writing;
960
# | | JSTENZEL | bugfixes: stream contained trailing whitespaces for
961
# | | | list points and headlines;
962
# | | JSTENZEL | bugfix: empty lines in verbatim blocks were not
963
# | | | streamed;
964
# | | JSTENZEL | bugfix: stream contained leading newline for verbatim
965
# | | | blocks;
966
# |05.06.2000| JSTENZEL | switched back to 5.005 open() syntax to become compatible;
967
# 0.13 |01.06.2000| JSTENZEL | made it 5.003 compatible again;
968
# 0.12 |27.05.2000| JSTENZEL | leading spaces in list point lines are suppressed now;
969
# | | JSTENZEL | bugfix in run(): did not supply correct a return code;
970
# | | JSTENZEL | bugfix: last semantic action must be a true value to
971
# | | | flag success (to the parser);
972
# 0.11 |20.05.2000| JSTENZEL | completed embedding feature;
973
# |21.05.2000| JSTENZEL | bugfix in semantic error counting;
974
# | | JSTENZEL | added include feature;
975
# |27.05.2000| JSTENZEL | added table feature (first version);
976
# 0.10 |17.04.2000| JSTENZEL | still incomplete embedding code added;
977
# |03.05.2000| JSTENZEL | bugfix: verbatim block opener was added to stream
978
# | | | because of the modified syntax (not completely impl.);
979
# 0.09 |11.04.2000| JSTENZEL | reorganized verbatim block start: spaces between "&"
980
# | | | and "<
981
# | | | paragraphs with a startup "&" character are allowed now;
982
# | | JSTENZEL | added new paragraph type "definition list point";
983
# |14.04.2000| JSTENZEL | streamed lists are embedded into list directives now;
984
# |15.04.2000| JSTENZEL | modified syntax of verbatim blocks;
985
# | | JSTENZEL | added variables;
986
# | | JSTENZEL | modified tag syntax into "\TAG[{parlist}][]";
987
# 0.08 |04.04.2000| JSTENZEL | started to implement the new pp2xy concept;
988
# |07.04.2000| JSTENZEL | headlines are terminated by a REAL empty line now;
989
# | | JSTENZEL | old "points" became "unordered list points";
990
# | | JSTENZEL | added new paragraph type "ordered list point";
991
# |08.04.2000| JSTENZEL | built in list shifting;
992
# |09.04.2000| JSTENZEL | bugfix in text paragraph rule;
993
# |10.04.2000| JSTENZEL | blocks are combined now automatically unless there is an
994
# | | | intermediate control paragraph;
995
# 0.07 |25.03.2000| JSTENZEL | tag length is now 1 to 8 characters (instead of 1 to 3);
996
# | | JSTENZEL | POD fixes;
997
# | | JSTENZEL | using CPAN id's in HOC now;
998
# 0.06 |24.02.2000| JSTENZEL | trailing whitespaces in input lines are now removed
999
# | | | (except of newlines!);
1000
# 0.05 |11.10.1999| JSTENZEL | bugfix: paragraphs generated array references;
1001
# | | JSTENZEL | PP::Parser::Constants became PP::Constants;
1002
# | | JSTENZEL | adapted POD to pod2text (needs more blank lines);
1003
# 0.04 |09.10.1999| JSTENZEL | moved certain constants into PP::Parser::Constants;
1004
# | | JSTENZEL | completed POD;
1005
# 0.03 |08.10.1999| JSTENZEL | started to generate intermediate data;
1006
# | | JSTENZEL | simplified array access;
1007
# | | JSTENZEL | bugfixes;
1008
# |09.10.1999| JSTENZEL | added data generation;
1009
# | | JSTENZEL | all messages are written in English now;
1010
# | | JSTENZEL | tags are declared outside now;
1011
# | | JSTENZEL | exported the script part;
1012
# | | JSTENZEL | added statistics;
1013
# | | JSTENZEL | added trace and display control;
1014
# 0.02 |07.10.1999| JSTENZEL | added C tag;
1015
# | | JSTENZEL | added comment traces;
1016
# | | JSTENZEL | bugfixes;
1017
# | | JSTENZEL | made it pass -w;
1018
# | | JSTENZEL | new "verbatim" paragraph;
1019
# 0.01 |28.09.1999| JSTENZEL | new.
1020
# ---------------------------------------------------------------------------------------
1021
1022
# = POD SECTION =========================================================================
1023
1024
=head1 NAME
1025
1026
B - a PerlPoint Parser
1027
1028
=head1 VERSION
1029
1030
This manual describes version B<0.451>.
1031
1032
=head1 SYNOPSIS
1033
1034
# load the module:
1035
use PerlPoint::Parser;
1036
1037
# build the parser and run it
1038
# to get intermediate data in @stream
1039
my ($parser)=new PerlPoint::Parser;
1040
$parser->run(
1041
stream => \@stream,
1042
files => \@files,
1043
);
1044
1045
1046
=head1 DESCRIPTION
1047
1048
The PerlPoint format, initially designed by Tom Christiansen, is intended
1049
to provide a simple and portable way to generate slides without the need of
1050
a proprietary product. Slides can be prepared in a text editor of your choice,
1051
generated on any platform where you find perl, and presented by any browser
1052
which can render the chosen output format.
1053
1054
To sum it up,
1055
I
1056
This is, by tradition, usually HTML, but you may decide to use another format like
1057
XML, SGML, TeX or whatever you want.
1058
1059
Well, this sounds fine, but how to build a translator which transforms ASCII
1060
into the output format of your choice? Thats what B is made for.
1061
It performs the first translation step by parsing ASCII and transforming it
1062
into an intermediate stream format, which can be processed by a subsequently
1063
called translator backend. By separating parsing and output generation we
1064
get the flexibility to write as many backends as necessary by using the same
1065
parser frontend for all translators.
1066
1067
B supports the complete I with exception of I
1068
tags. Tags I supported the I: the parser recognizes I
1069
tag which is declared by the author of a translator. This way the
1070
parser can be used for various flavours of the PerlPoint language without
1071
having to be modified. So, if there is a need of a certain new flag, it can
1072
quickly be added without any change to B.
1073
1074
The following chapters describe the input format (I) and the
1075
generated stream format (I). Finally, the class methods are
1076
described to show you how to build a parser.
1077
1078
1079
=head1 GRAMMAR
1080
1081
This chapter describes how a PerlPoint ASCII slide description has to be
1082
formatted to pass B parsers.
1083
1084
I that the input format does I completely determine how
1085
the output will be designed. The final I depends on the backend
1086
which has to be called after the parser to transform its output into a
1087
certain document description language. The final I depends on
1088
the I behaviour.
1089
1090
Each PerlPoint document is made of I.
1091
1092
=head2 The paragraphs
1093
1094
All paragraphs start at the beginning of their first line. The first character
1095
or string in this line determines which paragraph is recognized.
1096
1097
A paragraph is completed by an empty line (which may contain whitespaces).
1098
Exceptions are described.
1099
1100
Carriage returns in paragraphs which are completed by an empty line
1101
are transformed into a whitespace.
1102
1103
=over 4
1104
1105
=item Comments
1106
1107
start with "//" and reach until the end of the line.
1108
1109
1110
=item Headlines
1111
1112
start with one or more "=" characters.
1113
The number of "=" characters represents the headline level.
1114
1115
=First level headline
1116
1117
==Second level headline
1118
1119
===Multi
1120
line
1121
headline
1122
example
1123
1124
It is possible to declare a "short version" of the headline
1125
title by appending a "~" and plain strings to the headline
1126
like in
1127
1128
=Very long headlines are expressive but may exceed the
1129
available space for example in HTML navigation bars or
1130
something like that ~ Long headlines
1131
1132
The "~" often stands for similarity, or represents the described
1133
object in encyclopedias or dictionaries. So one may think of this
1134
as "long title is (sometimes) similar to short title".
1135
1136
1137
1138
=item Lists
1139
1140
B or B start with a "*" character.
1141
1142
* This is a first point.
1143
1144
* And, I forgot,
1145
there is something more to point out.
1146
1147
There are B as well, and I start with a hash sign ("#"):
1148
1149
# First, check the number of this.
1150
1151
# Second, don't forget the first.
1152
1153
The hash signs are intended to be replaced by numbers by a backend.
1154
1155
Because PerlPoint works on base of paragraphs, any paragraph different to
1156
an ordered list point I. If you wish the list to
1157
be continued use a double hash sign in case of the single one in the point
1158
that reopens the list.
1159
1160
# Here the ordered list begins.
1161
1162
? $includeMore
1163
1164
## This is point 2 of the list that started before.
1165
1166
# In subsequent points, the usual single hash sign
1167
works as expected again.
1168
1169
List continuation works list level specific (see below for level details).
1170
A list cannot be continued in another chapter. Using "##" in the first
1171
point of a new list takes no special effect: the list will begin as usual
1172
(with number 1).
1173
1174
B are a third list variant. Each item starts with the
1175
described phrase enclosed by a pair of colons, followed by the definition
1176
text:
1177
1178
:first things: are usually described first,
1179
1180
:others: later then.
1181
1182
All lists can be I. A new level is introduced by
1183
a special paragraph called I<"list indention"> which starts with a ">". A list level
1184
can be terminated by a I<"list indention stop"> paragraph starting with a "<"
1185
character. (These startup characters symbolize "level shifts".)
1186
1187
* First level.
1188
1189
* Still there.
1190
1191
>
1192
1193
* A list point of the 2nd level.
1194
1195
<
1196
1197
* Back on first level.
1198
1199
It is possible to shift more than one level by adding a number. There should be no whitespace between the
1200
level shift character and the level number.
1201
1202
* First level.
1203
1204
>
1205
1206
* Second level.
1207
1208
>
1209
1210
* Third level.
1211
1212
<2
1213
1214
* Back on first level.
1215
1216
Level shifts are accepted between list items I.
1217
1218
I Any non list
1219
paragraph will I list indentation, as well as the end of the source.
1220
1221
1222
=item Texts
1223
1224
are paragraphs like points but begin I without a startup
1225
character:
1226
1227
This is a simple text.
1228
1229
In this new text paragraph,
1230
we demonstrate the multiline feature.
1231
1232
I, a text paragraph can be started with a special character
1233
as well, which is a dot:
1234
1235
.This is a simple text with dot.
1236
1237
.In this new text paragraph,
1238
we demonstrate the multiline feature.
1239
1240
This is intended to be used by generators which translate other formats
1241
into PerlPoint, to make sure the first character of a paragraph has no
1242
special meaning to the PerlPoint parser.
1243
1244
1245
=item Blocks
1246
1247
are intended to contain examples or code I tag recognition.
1248
This means that the parser will discover embedded tags. On the other hand,
1249
it means that one may have to escape ">" characters embedded into tags. Blocks
1250
begin with an I and are completed by the next empty line.
1251
1252
* Look at these examples:
1253
1254
A block.
1255
1256
\I block.
1257
Escape ">" in tags: \C<<\>>.
1258
1259
Examples completed.
1260
1261
Subsequent blocks are joined together automatically: the intermediate empty
1262
lines which would usually complete a block are translated into real empty
1263
lines I the block. This makes it easier to integrate real code
1264
sequences as one block, regardless of the empty lines included. However,
1265
one may explicitly I to separate subsequent blocks and can do so
1266
by delimiting them by a special control paragraph:
1267
1268
* Separated subsequent blocks:
1269
1270
The first block.
1271
1272
-
1273
1274
The second block.
1275
1276
Note that the control paragraph starts at the left margin.
1277
1278
1279
=item Verbatim blocks
1280
1281
are similar to blocks in indentation but I
1282
pattern recognition. That means the embedded text is I scanned for tags
1283
and empty lines and may therefore remain as it was in its original place,
1284
possibly a script.
1285
1286
These special blocks need a special syntax. They are implemented as here documents.
1287
Start with a here document clause flagging which string will close the "here document":
1288
1289
<
1290
1291
PerlPoint knows various
1292
tags like \B, \C and \I. # unrecognized tags
1293
1294
EOC
1295
1296
1297
=item Tables
1298
1299
are supported as well, they start with an @ sign which is
1300
followed by the column delimiter:
1301
1302
@|
1303
column 1 | column 2 | column 3
1304
aaa | bbb | ccc
1305
uuu | vvvv | www
1306
1307
The first line is automatically marked as a "table headline". Most converters
1308
emphasize such headlines by bold formatting, so there is no need to insert \B
1309
tags into the document.
1310
1311
If a table row contains less columns than the table headline, the "missed"
1312
columns are automatically added. This is,
1313
1314
@|
1315
A | B | C
1316
1
1317
1 |
1318
1 | 2
1319
1 | 2 |
1320
1 | 2 | 3
1321
1322
is streamed exactly like
1323
1324
@|
1325
A | B | C
1326
1 | |
1327
1 | |
1328
1 | 2 |
1329
1 | 2 |
1330
1 | 2 | 3
1331
1332
to make backend handling easier. (Empty HTML table cells, for example, are rendered
1333
slightly obscure by certain browsers unless they are filled with invisible characters,
1334
so a converter to HTML can detect such cells because of normalization and handle them
1335
appropriately.)
1336
1337
Please note that normalization refers to the headline row. If another line contains
1338
I columns than the headline, normalization does not care. If the maximum column
1339
number is detected in another row, a warning is issued. (As a help for converter authors,
1340
the title and maximum column number are made part of a table tag as internal options
1341
C<__titleColumns__> and C<__maxColumns__>.)
1342
1343
In all tables, leading and trailing whitespaces of a cell are
1344
automatically removed, so you can use as many of them as you want to
1345
improve the readability of your source. The following table is absolutely
1346
equivalent to the last example:
1347
1348
@|
1349
A | B | C
1350
1 | |
1351
1 | |
1352
1 | 2 |
1353
1 | 2 |
1354
1 | 2 | 3
1355
1356
There is also a more sophisticated way to describe tables, see the tag section below.
1357
1358
Note: Although table paragraphs cannot be nested, tables declared by tag possibly
1359
I (and might be embedded into table paragraphs as well). To help converter authors
1360
handling nested tables, the opening table tag provides an internal option "__nestingLevel__".
1361
1362
1363
=item Conditions
1364
1365
start with a "?" character. If active contents is enabled, the paragraph text
1366
is evaluated as Perl code. The (boolean) evaluation result then determines if
1367
subsequent PerlPoint is read and parsed. If the result is false, all subsequent
1368
paragraphs until the next condition are I.
1369
1370
Note that base data is made available by a global (package) hash reference
1371
B<$PerlPoint>. See I for details about how to set up these data.
1372
1373
Conditions can be used to maintain various language versions of a presentation
1374
in one source file:
1375
1376
? $PerlPoint->{targetLanguage} eq 'German'
1377
1378
Or you could enable parts of your document by date:
1379
1380
? time>$dateOfTalk
1381
1382
or by a special setting:
1383
1384
? flagSet('setting')
1385
1386
Please note that the condition code shares its variables with embedded and included
1387
code.
1388
1389
To make usage easier and to improve readability, condition code is evaluated with
1390
disabled warnings (the language variable in the example above may not even been set).
1391
1392
Converter authors might want to provide predefined variables such as "$language"
1393
in the example.
1394
1395
Note: If a document uses I, be careful in intermixing docstream
1396
entry points and conditions. A condition placed in a skipped document stream will
1397
not e evaluated. A document stream entry point placed in a source area hidden by
1398
a false condition will not be reconized.
1399
1400
1401
=item Variable assignment paragraphs
1402
1403
Variables can be used in the text and will be automatically replaced by their string
1404
values (if declared).
1405
1406
The next paragraph sets a variable.
1407
1408
$var=var
1409
1410
This variable is called $var.
1411
1412
All variables are made available to embedded and included Perl code as well as to
1413
conditions and can be accessed there as package variables of "main::" (or whatever
1414
package name the Safe object is set up to). Because a
1415
variable is already replaced by the parser if possible, you have to use the fully
1416
qualified name or to guard the variables "$" prefix character to do so:
1417
1418
\EMBED{lang=perl}join(' ', $main::var, \$var)\END_EMBED
1419
1420
Variable modifications by embedded or included Perl I affect the variables
1421
visible to the parser. (This is true for conditions as well.) This means that
1422
1423
$var=10
1424
\EMBED{lang=perl}$main::var*=2;\END_EMBED
1425
1426
causes I<$var> to be different on parser and code side - the parser will still use a
1427
value of 10, while embedded code works on with a value of 20.
1428
1429
=item Macro or alias definitions
1430
1431
Sometimes certain text parts are used more than once. It would be a relieve
1432
to have a shortcut instead of having to insert them again and again. The same
1433
is true for tag combinations a user may prefer to use. That's what I
1434
(or "macros") are designed for. They allow a presentation author to declare
1435
his own shortcuts and to use them like a tag. The parser will resolve such aliases,
1436
replace them by the defined replacement text and work on with this replacement.
1437
1438
An alias declaration starts with a "+" character followed I by the
1439
alias I (without backslash prefix), optionally followed I
1440
by an option default list in "{}", followed I by a colon.
1441
(No additional spaces here.)
1442
1443
I
1444
So, whereever you will use the new macro, the parser will replace it by this
1445
text and I the result. This means that your macro text can contain
1446
any valid constructions like tags or other macros.
1447
1448
The replacement text may contain strings embedded into doubled underscores like
1449
C<__this__>. This is a special syntax to mark that the macro takes parameters
1450
of these names (e.g. C). If a macro is used and these parameters are set,
1451
their values will replace the mentioned placeholders. The special placeholder
1452
"__body__" is used to mark where the macro I is to place.
1453
1454
If a macro is used and defined options are I, but there are defaults
1455
for them in the optional default list, these defaults will be used for the
1456
respective options.
1457
1458
Here are a few examples:
1459
1460
+RED:\FONT{color=red}<__body__>
1461
1462
+F:\FONT{color=__c__}<__body__>
1463
1464
+COLORED{c=blue}:\FONT{color=__c__}<__body__>
1465
1466
+IB:\B<\I<__body__>>
1467
1468
This \IB is \RED.
1469
1470
Defaults: first, text in \COLORED{c=red},
1471
now text in \COLORED.
1472
1473
+TEXT:Macros can be used to abbreviate longer
1474
texts as well as other tags
1475
or tag combinations.
1476
1477
+HTML:\EMBED{lang=html}
1478
1479
Tags can be \RED<\I> into macros.
1480
And \I<\F{c=blue}>.
1481
\IB<\RED> is formatted by nested macros.
1482
\HTML This is embedded HTML \END_EMBED.
1483
1484
Please note: \TEXT
1485
1486
I
1487
The same is true for the body part.
1488
I is used in the macro definition, macro bodies will not be recognized.>
1489
This means that with the definition
1490
1491
+OPTIONLESS:\B<__body__>
1492
1493
the construction
1494
1495
\OPTIONLESS{something=this}
1496
1497
is evaluated as a usage of C<\OPTIONLESS> without body, followed by the I
1498
C<{something=here}>. Likewise, the definition
1499
1500
+BODYLESS:found __something__
1501
1502
causes
1503
1504
\BODYLESS{something=this}
1505
1506
to be recognized as a usage of C<\BODYLESS> with option C, followed
1507
by the I C<>. So this will be resolved as C. Finally,
1508
1509
+JUSTTHENAME:Text phrase.
1510
1511
enforces these constructions
1512
1513
... \JUSTTHENAME, ...
1514
... \JUSTTHENAME{name=Name}, ...
1515
... \JUSTTHENAME, ...
1516
... \JUSTTHENAME{name=Name} ...
1517
1518
to be translated into
1519
1520
... Text phrase. ...
1521
... Text phrase.{name=Name} ...
1522
... Text phrase., ...
1523
... Text phrase.{name=Name} ...
1524
1525
The principle behind all this is to make macro usage I and intuative:
1526
why think of options or a body or of special characters possibly treated as
1527
option/body part openers unless the macro makes use of an option or body?
1528
1529
An I macro text I the macro (if it was already known).
1530
1531
// undeclare the IB alias
1532
+IB:
1533
1534
An alias can be used like a tag.
1535
1536
Aliases named like a tag I the tag (as long as they are defined).
1537
1538
1539
=item Document stream entry points
1540
1541
A document stream is a "document in document" and best explained by example.
1542
1543
Consider a document talking about
1544
two scripts and comparing them. A
1545
typical review of this type is
1546
structured this way: headline, notes
1547
about script 1, notes about script 2,
1548
new headline to discuss another aspect,
1549
notes about script 1, notes about
1550
script 2, and so on.
1551
1552
Everything said about item 1 is a document stream, everything about object 2
1553
as well. and a third stream is implicitly built by all parts outside these
1554
two. In slide construction, each stream can have its own area, for example
1555
1556
-------------------------------------
1557
| |
1558
| main stream |
1559
| |
1560
-------------------------------------
1561
| | |
1562
| item 1 stream | item 2 stream |
1563
| | |
1564
-------------------------------------
1565
1566
But to construct a layout like this, streams need to be distinguished, and
1567
that is what "stream entry points" are made for.
1568
1569
A stream entry point starts with a "~" character, followed by a string
1570
which is the name of the stream. This may be an internal name only, or
1571
converters may turn it into a document part as well. The C<__ALL__> string
1572
is reserved for internal purposes. It is recommended to treat C<__MAIN__>
1573
as reserved as well, although it has no special meaning yet.
1574
1575
Once an entry point was passed, all subsequent document parts belong to the
1576
declared stream, up to the next entry point or a headline which implicitly
1577
switches back to the "main stream".
1578
1579
The parser can be instructed to ignore certain streams, see I for
1580
details. If this feature is used, please be careful in intermixing stream
1581
entry points and conditions. A condition placed in a skipped document
1582
stream will not be evaluated.
1583
1584
I Certain converters
1585
may ignore them at all. As a convenient solution, the parser can be instructed
1586
to transform stream entry points into headlines (one level below the current
1587
real headline level). See I for details.
1588
1589
1590
1591
=back
1592
1593
=head2 Tags
1594
1595
Tags are directives embedded into the text stream, commanding how certain parts
1596
of the text should be interpreted. Tags are declared by using one or more modules
1597
build on base of B.
1598
1599
use PerlPoint::Tags::Basic;
1600
1601
B parsers can recognize all tags which are build of a backslash
1602
and a number of capitals and numbers.
1603
1604
\TAG
1605
1606
I are optional and follow the tag name immediately, enclosed
1607
by a pair of corresponding curly braces. Each option is a simple string
1608
assignment. The value has to be quoted if /^\w+$/ does not match it.
1609
1610
\TAG{par1=value1 par2="www.perl.com" par3="words and blanks"}
1611
1612
The I is anything you want to make the tag valid for. It is optional
1613
as well and immediately follows the optional parameters, enclosed by "<" and ">":
1614
1615
\TAG
1616
\TAG{par=value}
1617
1618
Tags can be I.
1619
1620
To provide a maximum of flexibility, tags are declared I the parser.
1621
This way a translator programmer is free to implement the tags he needs. It is
1622
recommended to always support the basic tags declared by B.
1623
On the other hand,a few tags of special meaning are reserved and cannot be declared
1624
by converter authors, because they are handled by the parser itself. These are:
1625
1626
=over 4
1627
1628
=item \INCLUDE
1629
1630
It is possible to include a file into the input stream. Have a look:
1631
1632
\INCLUDE{type=HTML file=filename}
1633
1634
This imports the file "filename". The file contents is made part of the
1635
generated stream, but not parsed. This is useful to include target language
1636
specific, preformatted parts.
1637
1638
If, however, the file type is specified as "PP", the file contents is
1639
made part of the input stream and parsed. In this case a special tag option
1640
"headlinebase" can be specified to define a headline base level used as
1641
an offset to all headlines in the included document. This makes it easier
1642
to share partial documents with others, or to build complex documents by
1643
including separately maintained parts, or to include one and the same
1644
part at different headline levels.
1645
1646
Example: If "\INCLUDE{type=PP file=file headlinebase=20}" is
1647
specified and "file" contains a one level headline
1648
like "=Main topic of special explanations"
1649
this headline is detected with a level of 21.
1650
1651
Pass the special keyword "CURRENT_LEVEL" to this tag option if you want to
1652
set just the I headline level as an offset. This results in
1653
"subchapters".
1654
1655
Example:
1656
1657
===Headline 3
1658
1659
// let included chapters start on level 4
1660
\INCLUDE{type=PP file=file headlinebase=CURRENT_LEVEL}
1661
1662
Similar to "CURRENT_LEVEL", "BASE_LEVEL" sets the current I
1663
headline level as an offset. The "base level" is the level above
1664
the current one. Using "BASE_LEVEL" results in parallel chapters.
1665
1666
Example:
1667
1668
===Headline 3
1669
1670
// let included chapters start on level 3
1671
\INCLUDE{type=PP file=file headlinebase=BASE_LEVEL}
1672
1673
A given offset is reset when the included document is parsed completely.
1674
1675
A second special option I commands the parser to include the file
1676
only unless this was already done before. This is intended for inclusion
1677
of pure alias/macro definition or variable assignment files.
1678
1679
\INCLUDE{type=PP file="common-macros.pp" smart=1}
1680
1681
Included sources may declare variables of their own, possibly overwriting
1682
already assigned values. Option "localize" works like Perls C:
1683
such changes will be reversed after the nested source will have been
1684
processed completely, so the original values will be restored. You can
1685
specify a comma separated list of variable names or the special string
1686
C<__ALL__> which flags that I current settings shall be restored.
1687
1688
\INCLUDE{type=PP file="nested.pp" localize=myVar}
1689
1690
\INCLUDE{type=PP file="nested.pp" localize="var1, var2, var3"}
1691
1692
\INCLUDE{type=PP file="nested.pp" localize=__ALL__}
1693
1694
1695
PerlPoint authors can declare an I to preprocess the
1696
included file. This is done via option I:
1697
1698
\INCLUDE{type=pp file="source.pod" ifilter="pod2pp()"}
1699
1700
An input filter is a snippet of user defined Perl code, taking the
1701
included file via C<@main::_ifilterText> and the target type via
1702
C<$main::_ifilterType>. The original filename can be accessed via
1703
C<$main::_ifilterType>. It should supply its result as an array
1704
of strings which will then be processed instead of the original file.
1705
1706
Input filters are Active Content. If Active Content is disabled,
1707
\INCLUDE tags using input filters will be ignored I.
1708
1709
1710
As a simplified option, C allows to use I
1711
import filters defined in C modules. To use
1712
such a filter do I set the C option, set C instead.
1713
C takes the name of the source format, like "POD", or a true
1714
number to indicate that the file extension should be used as the source
1715
format name. The uppercased name is used as the final part of the filter
1716
module - for "POD", the modules name would be "PerlPoint::Import::POD".
1717
If this module is installed and has a function C this
1718
function name is used like C.
1719
1720
Here are a few examples:
1721
1722
\INCLUDE{file="source.pod" import=1}
1723
1724
\INCLUDE{file="source.pod" import=pod}
1725
1726
\INCLUDE{file=source import=pod}
1727
1728
Please note that in the last example C will not work, as the
1729
source file has no extension that indicates its format is POD.
1730
1731
If C is used together with C, C is ignored.
1732
1733
1734
A PerlPoint file can be included wherever a tag is allowed, but sometimes
1735
it has to be arranged slightly: if you place the inclusion directive at
1736
the beginning of a new paragraph I your included PerlPoint starts by
1737
a paragraph of another type than text, you should begin the included file
1738
by an empty line to let the parser detect the correct paragraph type. Here
1739
is an example: if the inclusion directive is placed like
1740
1741
// include PerlPoint
1742
\INCLUDE{type=pp file="file.pp"}
1743
1744
and file.pp immediately starts with a verbatim block like
1745
1746
<
1747
verbatim
1748
VERBATIM
1749
1750
, I which is detected to
1751
be "text" (because there is no special startup character). Now in the included
1752
file, from the parsers point of view the included PerlPoint is simply a
1753
continuation of this text, because a paragraph ends with an empty line. This
1754
trouble can be avoided by beginning the included file by an empty line,
1755
so that its first paragraph can be detected correctly.
1756
1757
The second special case is a file type of "Perl". If active contents is enabled,
1758
included Perl code is read into memory and evaluated like I Perl. The
1759
results are made part of the input stream to be parsed.
1760
1761
// execute a perl script and include the results
1762
\INCLUDE{type=perl file="disk-usage.pl"}
1763
1764
As another option, files may be declared to be of type "example" or "parsedexample".
1765
This makes the file placed into the source as a verbatim block (with "example"), or
1766
a standard block (with "parsedexample"), respectively, without need to copy its contents
1767
into the source.
1768
1769
// include an external script as an example
1770
\INCLUDE{type=example file="script.csh"}
1771
1772
All lines of the example file are included as they are but can be indented on request.
1773
To do so, just set the special option "indent" to a positive numerical value equal to
1774
the number of spaces to be inserted before each line.
1775
1776
// external example source, indented by 3 spaces
1777
\INCLUDE{type=example file="script.csh" indent=3}
1778
1779
Including external scripts this way can accelerate PerlPoint authoring significantly,
1780
especially if the included files are still subject to changes.
1781
1782
It is possible to filter the file types you wish to include (with exception
1783
of "pp" and "example"), see below for details. I, the mentioned file
1784
has to exist.
1785
1786
1787
1788
=item \EMBED and \END_EMBED
1789
1790
Target format code does not necessarily need to be imported - it can be
1791
directly I as well. This means that one can write target language
1792
code within the input stream using I<\EMBED>:
1793
1794
\EMBED{lang=HTML}
1795
This is embedded HTML .
1796
The parser detects no PerlPoint
1797
tag here, except of END_EMBED .
1798
\END_EMBED
1799
1800
Because this is handled by I, not by paragraphs, it can be placed
1801
directly in a text like this:
1802
1803
These \EMBED{lang=HTML}italics \END_EMBED
1804
are formatted by HTML code.
1805
1806
Please note that the EMBED tag does not accept a tag body (to avoid
1807
ambiguities).
1808
1809
Both tag and embedded text are made part of the intermediate stream.
1810
It is the backends task to deal with it. The only exception of this rule
1811
is the embedding of I code, which is evaluated by the parser.
1812
The reply of this code is made part of the input stream and parsed as
1813
usual.
1814
1815
PerlPoint authors can declare an I to preprocess the
1816
embedded text. This is done via option I:
1817
1818
\EMBED{lang=pp ifilter="pod2pp()"}
1819
1820
=head1 POD formatted part
1821
1822
This part was written in POD.
1823
1824
\END_EMBED
1825
1826
An input filter is a snippet of user defined Perl code, taking the
1827
embedded text via C<@main::_ifilterText> and the target language via
1828
C<$main::_ifilterType>. The original filename can be accessed via
1829
C<$main::_ifilterType> (but please note that this is the source with
1830
the \EMBED tag). It should supply its result as an array of
1831
strings which will then be processed as usual.
1832
1833
Input filters are Active Contents. If Active Contents is disabled,
1834
embedded parts using input filters will be ignored I.
1835
1836
It is possible to filter the languages you wish to embed (with exception
1837
of "PP"), see below for details.
1838
1839
1840
=item \TABLE and \END_TABLE
1841
1842
It was mentioned above that tables can be built by table paragraphs.
1843
Well, there is a tag variant of this:
1844
1845
\TABLE{bg=blue separator="|" border=2}
1846
\B | \B | \B
1847
aaaa | bbbb | cccc
1848
uuuu | vvvv | wwww
1849
\END_TABLE
1850
1851
This is sligthly more powerfull than the paragraph syntax: you can set
1852
up several table features like the border width yourself, and you can
1853
format the headlines as you like.
1854
1855
As in all tables, leading and trailing whitespaces of a cell are
1856
automatically removed, so you can use as many of them as you want to
1857
improve the readability of your source.
1858
1859
The default row separator (as in the example above) is a carriage return,
1860
so that each table line can be written as a separate source line. However,
1861
PerlPoint allows you to specify another string to separate rows by option
1862
C. This allows to specify a table I into a paragraph.
1863
1864
\TABLE{bg=blue separator="|" border=2 rowseparator="+++"}
1865
\B | \B | \B +++ aaaa
1866
| bbbb | cccc +++ uuuu | vvvv| wwww \END_TABLE
1867
1868
This is exactly the same table as above.
1869
1870
If parser option I is set to a true value calling I,
1871
it is possible to I tables. To help converter authors handling this,
1872
the opening table tag provides an internal option "__nestingLevel__".
1873
1874
Tables built by tag are normalized the same way as table paragraphs are.
1875
1876
=back
1877
1878
1879
=head2 What about special formatting?
1880
1881
Earlier versions of B supported special format hints like the HTML
1882
expression ">" for the ">" character, or "ü" for "ü". B
1883
does I support this directly because such hints are specific to the
1884
I - if someone wants to translate into TeX, it might be curious
1885
for him to use HTML syntax in his ASCII text. Further more, such hints can be
1886
handled I by a backend which finds them unchanged in the produced
1887
output stream.
1888
1889
The same is true for special headers and trailers. It is a I task to
1890
add them if necessary. The parser does handle the I only.
1891
1892
1893
=head1 STREAM FORMAT
1894
1895
It is suggested to use B to evaluate the intermediate format.
1896
Nevertheless, here is the documentation of this format.
1897
1898
The generated stream is an array of tokens. Most of them are very simple,
1899
representing just their contents - words, spaces and so on. Example:
1900
1901
"These three words."
1902
1903
could be streamed into
1904
1905
"These three" + " "+ "words."
1906
1907
(This shows the principle. Actually this complete sentence would be replied as
1908
I token for reasons of effeciency.)
1909
1910
Note that the final dot I of the last token. From a document
1911
description view, this should make no difference, its just a string containing
1912
special characters or not.
1913
1914
Well, besides this "main stream", there are I. They
1915
flag the I or I of a certain logical entity - this
1916
means a whole document, a paragraph or a formatting like italicising. Almost
1917
every entity is embedded into a start I a completion directive - except
1918
of simple tokens.
1919
1920
In the current implementation, a directive is a reference to an array of mostly
1921
two fields: a directive constant showing which entity is related, and a start
1922
or completion hint which is a constant, too. The used constants are declared in
1923
B. Directives can pass additional informations by additional
1924
fields. By now, the headline directives use this feature to show the headline
1925
level, as well as the tag ones to provide tag type information and the document ones
1926
to keep the name of the original document. Further more, ordered list points I
1927
request a fix number this way.
1928
1929
# this example shows a tag directive
1930
... [DIRECTIVE_TAG, DIRECTIVE_START, "I"]
1931
+ "formatted" + " " + "strings"
1932
+ [DIRECTIVE_TAG, DIRECTIVE_COMPLETE, "I"] ...
1933
1934
To recognize whether a token is a basic or a directive, the ref() function can be
1935
used. However, this handling should be done by B transparently.
1936
The format may be subject to changes and is documented for information purposes only.
1937
1938
Original line numbers are no part of the stream but can be provided by embedded
1939
directives on request, see below for details.
1940
1941
This is the complete generator format. It is designed to be simple but powerful.
1942
1943
1944
=head1 METHODS
1945
1946
=head2 new()
1947
1948
The constructor builds and prepares a new parser object.
1949
1950
B
1951
1952
=over 4
1953
1954
=item The class name.
1955
1956
=back
1957
1958
B
1959
The new object in case of success.
1960
1961
B
1962
1963
my ($parser)=new PerlPoint::Parser;
1964
1965
=cut
1966
1967
# = CODE SECTION ========================================================================
1968
1969
# startup actions
1970
BEGIN
1971
{
1972
# declare startup helper function
1973
sub _startupGenerateConstants
1974
{
1975
# init counter
1976
my $c=0;
1977
1978
# and generate constants
1979
foreach my $constant (@_)
1980
{eval "use constant $constant => $c"; $c++;}
1981
}
1982
1983
# declare internal constants: action timeout types (used as array indices, sort alphabetically!)
1984
_startupGenerateConstants(
1985
'LEXER_TOKEN', # reply symbols token;
1986
'LEXER_FATAL', # bug: unexpected symbol;
1987
'LEXER_IGNORE', # ignore this symbol;
1988
'LEXER_EMPTYLINE', # reply the token "Empty_line";
1989
'LEXER_SPACE', # reply the token "Space" and a simple whitespace;
1990
);
1991
1992
# state constants
1993
_startupGenerateConstants(
1994
'STATE_DEFAULT', # default;
1995
'STATE_DEFAULT_TAGMODE', # default in tag mode;
1996
1997
'STATE_BLOCK', # block;
1998
'STATE_COMMENT', # comment;
1999
'STATE_CONTROL', # control paragraph (of a single character);
2000
'STATE_DPOINT', # definition list point;
2001
'STATE_DPOINT_ITEM', # definition list point item (defined stuff);
2002
'STATE_EMBEDDING', # embedded things (HTML, Perl, ...);
2003
'STATE_PFILTER', # paragraph filter installation;
2004
'STATE_PFILTERED', # "default" state after a pfilter installation;
2005
'STATE_CONDITION', # condition;
2006
'STATE_HEADLINE_LEVEL', # headline level setting;
2007
'STATE_HEADLINE', # headline;
2008
'STATE_OPOINT', # ordered list point;
2009
'STATE_TEXT', # text;
2010
'STATE_UPOINT', # unordered list point;
2011
'STATE_VERBATIM', # verbatim block;
2012
'STATE_TABLE', # table *paragraph*;
2013
'STATE_DEFINITION', # macro definition;
2014
);
2015
2016
# declare internal constants: list shifters
2017
_startupGenerateConstants(
2018
'LIST_SHIFT_RIGHT', # shift right;
2019
'LIST_SHIFT_LEFT', # shift left;
2020
);
2021
2022
# release memory
2023
undef &_startupGenerateConstants;
2024
}
2025
2026
# requires modern perl
2027
require 5.00503;
2028
2029
# declare module version
2030
$PerlPoint::Parser::VERSION=0.451;
2031
$PerlPoint::Parser::VERSION=$PerlPoint::Parser::VERSION; # to suppress a warning of exclusive usage only;
2032
2033
# pragmata
2034
use strict;
2035
2036
# load modules
2037
use Carp;
2038
# use Memoize;
2039
use IO::File;
2040
use File::Basename;
2041
use File::Spec::Functions;
2042
use File::Temp qw(tempfile);
2043
use PerlPoint::Anchors 0.03;
2044
use PerlPoint::Backend 0.10;
2045
use Cwd qw(:DEFAULT abs_path);
2046
use Digest::SHA1 qw(sha1_base64);
2047
use Storable qw(:DEFAULT dclone nfreeze);
2048
use PerlPoint::Constants 0.19 qw(:DEFAULT :parsing :stream :tags);
2049
2050
# memoizations
2051
2052
# startup declarations
2053
my (
2054
%data, # the collected declaration data;
2055
%lineNrs, # the lexers line number hash, input handle specific;
2056
%specials, # special character control (may be active or not);
2057
%lexerFlags, # lexer state flags;
2058
%lexerFlagsOfPreviousState, # buffered lexer state flags of previous state;
2059
%statistics, # statistics data;
2060
%variables, # user managed variables;
2061
%flags, # various flags;
2062
%macros, # macros / aliases;
2063
%openedSourcefiles, # a hash of all source files already opened (to enable smart inclusion);
2064
%paragraphTypeStrings, # paragraph type to string translation table;
2065
2066
@nestedSourcefiles, # a list of current source file nesting (to avoid circular inclusions);
2067
@specialStack, # special state stack for temporary activations (to restore original states);
2068
@stateStack, # state stack (mostly intended for non paragraph states like STATE_EMBEDDED);
2069
@tableSeparatorStack, # the first element is the column separator string within a table, empty otherwise;
2070
@inputStack, # a stack of additional input lines and dynamically inserted parts;
2071
@inHandles, # a stack of input handles (to manage nested sources);
2072
@olistLevels, # a hint storing the last recent ordered list level number of a paragraph (hyrarchically);
2073
@inLine, # current *real* input line (the unexpanded line read from a source file);
2074
@previousStackLines, # buffer of the last lines gotten from input stack;
2075
@libraryPath, # a collection of pathes to find files for \INCLUDE in;
2076
@headlineIds, # the hierarchical values of $directiveCounter pointing to the current chapter headline;
2077
2078
$anchors, # anchor collector object;
2079
$safeObject, # an object of class Safe to evaluate Perl code embedded into PerlPoint;
2080
$sourceFile, # the source file currently read;
2081
$tagsRef, # reference to a hash of valid tag openers (strings without the "<");
2082
$resultStreamRef, # reference to a data structure to put generated stream data in;
2083
$inHandle, # the data input stream (to parse);
2084
$parserState, # the current parser state;
2085
$readCompletely, # the input file is read completely;
2086
$_semerr, # semantic error counter;
2087
$tableColumns, # counter of completed table columns;
2088
$checksums, # paragraph checksums (and associated stream parts);
2089
$macroChecksum, # the current macro checksum;
2090
$varChecksum, # the current user variables checksum;
2091
$pendingTags, # list of tags to be finished after parsing (collected using a structure);
2092
$directiveCounter, # directive counter (just to mark stream directive pairs uniquely);
2093
$retranslator, # a backend object used to restore paragraph sources to be filtered;
2094
$retranslationBuffer, # buffer used in retranslation (needs to b global to avoid closure effects with lexicals in translator routines);
2095
);
2096
2097
# ----- Startup code begins here. -----
2098
2099
# prepare main input handle (obsolete when all people will use perl 5.6)
2100
$inHandle=new IO::File;
2101
2102
# set developer data
2103
my ($developerName, $developer)=('J. Stenzel', 'perl@jochen-stenzel.de');
2104
2105
# init flag
2106
$readCompletely=0;
2107
2108
# prepare a common pattern
2109
my $patternWUmlauts=qr/[\wäöüÄÖÜß]+/;
2110
2111
# prepare lexer patterns
2112
my $patternNlbBackslash=qr/(?
2113
my %lexerPatterns=(
2114
tag => qr/$patternNlbBackslash\\([A-Z_0-9]+)/,
2115
space => qr/(\s+)/,
2116
pfilterDelimiter => qr/$patternNlbBackslash((\|){1,2})/,
2117
table => qr/$patternNlbBackslash\\(TABLE)/,
2118
endTable => qr/$patternNlbBackslash\\(END_TABLE)/,
2119
embed => qr/$patternNlbBackslash\\(EMBED)/,
2120
endEmbed => qr/$patternNlbBackslash\\(END_EMBED)/,
2121
include => qr/$patternNlbBackslash\\(INCLUDE)/,
2122
nonWhitespace => qr/$patternNlbBackslash(\S)/,
2123
colon => qr/$patternNlbBackslash(:)/,
2124
namedVarKernel => qr/\$($patternWUmlauts)/,
2125
symVarKernel => qr/\$({($patternWUmlauts)})/,
2126
);
2127
@lexerPatterns{qw(
2128
namedVar
2129
symVar
2130
)
2131
}=(
2132
qr/$patternNlbBackslash$lexerPatterns{namedVarKernel}/,
2133
qr/$patternNlbBackslash$lexerPatterns{symVarKernel}/,
2134
);
2135
2136
# declare paragraphs which are embedded
2137
my %embeddedParagraphs;
2138
@embeddedParagraphs{
2139
DIRECTIVE_UPOINT,
2140
DIRECTIVE_OPOINT,
2141
}=();
2142
2143
# declare token descriptions (to be used in error messages)
2144
my %tokenDescriptions=(
2145
EOL => 'a carriage return',
2146
Embed => 'embedded code',
2147
Embedded => 'an \END_EMBED tag',
2148
Empty_line => 'an empty line',
2149
Heredoc_close => 'a string closing the "here document"',
2150
Heredoc_open => 'a "here document" opener',
2151
Ils => 'a indentation',
2152
Include => 'an included part',
2153
Named_variable => 'a named variable',
2154
Space => 'a whitespace',
2155
StreamedPart => undef,
2156
Symbolic_variable => 'a symbolic variable',
2157
Table => 'a table',
2158
Table_separator => 'a table column separator',
2159
Tabled => 'an \END_TABLE tag',
2160
Tag_name => 'a tag name',
2161
Word => 'a word',
2162
NoToken => 'an internal dummy token that is finally ignored',
2163
);
2164
2165
2166
2167
sub new {
2168
my($class)=shift;
2169
ref($class)
2170
and $class=ref($class);
2171
2172
my($self)=$class->SUPER::new( yyversion => '1.05',
2173
yystates =>
2174
[
2175
{#State 0
2176
ACTIONS => {
2177
'Paragraph_cache_hit' => 11,
2178
"||" => 4,
2179
'Empty_line' => 3,
2180
"+" => 5,
2181
"?" => 2
2182
},
2183
DEFAULT => -3,
2184
GOTOS => {
2185
'non_filterable_paragraph' => 1,
2186
'document' => 6,
2187
'restored_paragraph' => 7,
2188
'alias_definition' => 8,
2189
'built_paragraph' => 9,
2190
'optional_paragraph_filter' => 10,
2191
'condition' => 12,
2192
'paragraph' => 13
2193
}
2194
},
2195
{#State 1
2196
DEFAULT => -12
2197
},
2198
{#State 2
2199
DEFAULT => -33,
2200
GOTOS => {
2201
'@4-1' => 14
2202
}
2203
},
2204
{#State 3
2205
DEFAULT => -22
2206
},
2207
{#State 4
2208
DEFAULT => -4,
2209
GOTOS => {
2210
'@1-1' => 15
2211
}
2212
},
2213
{#State 5
2214
DEFAULT => -152,
2215
GOTOS => {
2216
'@31-1' => 16
2217
}
2218
},
2219
{#State 6
2220
ACTIONS => {
2221
'' => 17,
2222
'Paragraph_cache_hit' => 11,
2223
"||" => 4,
2224
'Empty_line' => 3,
2225
"+" => 5,
2226
"?" => 2
2227
},
2228
DEFAULT => -3,
2229
GOTOS => {
2230
'non_filterable_paragraph' => 1,
2231
'built_paragraph' => 9,
2232
'optional_paragraph_filter' => 10,
2233
'restored_paragraph' => 7,
2234
'paragraph' => 18,
2235
'condition' => 12,
2236
'alias_definition' => 8
2237
}
2238
},
2239
{#State 7
2240
DEFAULT => -9
2241
},
2242
{#State 8
2243
DEFAULT => -24
2244
},
2245
{#State 9
2246
DEFAULT => -8
2247
},
2248
{#State 10
2249
DEFAULT => -10,
2250
GOTOS => {
2251
'@2-1' => 19
2252
}
2253
},
2254
{#State 11
2255
DEFAULT => -25
2256
},
2257
{#State 12
2258
DEFAULT => -23
2259
},
2260
{#State 13
2261
DEFAULT => -1
2262
},
2263
{#State 14
2264
ACTIONS => {
2265
'Embed' => 30,
2266
'Named_variable' => 21,
2267
'Table_separator' => 32,
2268
'Tag_name' => 34,
2269
'Symbolic_variable' => 33,
2270
'Table' => 37,
2271
'Include' => 36,
2272
'Space' => 23,
2273
'Word' => 27,
2274
'StreamedPart' => 28
2275
},
2276
GOTOS => {
2277
'basic' => 20,
2278
'basics' => 29,
2279
'embedded' => 31,
2280
'table_separator' => 25,
2281
'included' => 24,
2282
'table' => 22,
2283
'tag' => 26,
2284
'element' => 35
2285
}
2286
},
2287
{#State 15
2288
ACTIONS => {
2289
'Word' => 38
2290
},
2291
GOTOS => {
2292
'paragraph_filters' => 39
2293
}
2294
},
2295
{#State 16
2296
ACTIONS => {
2297
'Word' => 40
2298
}
2299
},
2300
{#State 17
2301
DEFAULT => 0
2302
},
2303
{#State 18
2304
DEFAULT => -2
2305
},
2306
{#State 19
2307
ACTIONS => {
2308
'Colon' => 41,
2309
'Named_variable' => 61,
2310
"\@" => 42,
2311
'Upoint_cache_hit' => 62,
2312
"~" => 43,
2313
'Dpoint_cache_hit' => 44,
2314
'Space' => 23,
2315
"*" => 47,
2316
'Word' => 27,
2317
'EOL' => 67,
2318
'StreamedPart' => 28,
2319
'Opoint_cache_hit' => 70,
2320
'Embed' => 30,
2321
'Table_separator' => 32,
2322
'Ils' => 52,
2323
'Block_cache_hit' => 73,
2324
"/" => 71,
2325
'Symbolic_variable' => 33,
2326
'Tag_name' => 34,
2327
"=" => 74,
2328
'Headline_cache_hit' => 53,
2329
'Table' => 37,
2330
'Include' => 36,
2331
"#" => 78,
2332
'Heredoc_open' => 81,
2333
"." => 57
2334
},
2335
GOTOS => {
2336
'basic' => 58,
2337
'dlist' => 60,
2338
'verbatim' => 59,
2339
'table' => 22,
2340
'dlist_opener' => 63,
2341
'upoint' => 45,
2342
'literal' => 46,
2343
'olist' => 64,
2344
'ulist' => 65,
2345
'text' => 66,
2346
'opoint_opener' => 48,
2347
'included' => 24,
2348
'table_separator' => 25,
2349
'tag' => 26,
2350
'optionally_dotted_text' => 68,
2351
'headline_level' => 49,
2352
'list' => 50,
2353
'dstream_entrypoint' => 69,
2354
'compound_block' => 51,
2355
'embedded' => 31,
2356
'variable_assignment' => 72,
2357
'element' => 35,
2358
'dotted_text' => 54,
2359
'opoint' => 55,
2360
'table_paragraph' => 75,
2361
'comment' => 76,
2362
'dpoint' => 56,
2363
'original_paragraph' => 77,
2364
'list_part' => 79,
2365
'block' => 80,
2366
'headline' => 82
2367
}
2368
},
2369
{#State 20
2370
DEFAULT => -101
2371
},
2372
{#State 21
2373
DEFAULT => -110
2374
},
2375
{#State 22
2376
DEFAULT => -104
2377
},
2378
{#State 23
2379
DEFAULT => -109
2380
},
2381
{#State 24
2382
DEFAULT => -115
2383
},
2384
{#State 25
2385
DEFAULT => -105
2386
},
2387
{#State 26
2388
DEFAULT => -113
2389
},
2390
{#State 27
2391
DEFAULT => -108
2392
},
2393
{#State 28
2394
DEFAULT => -112
2395
},
2396
{#State 29
2397
ACTIONS => {
2398
'Embed' => 30,
2399
'Empty_line' => 84,
2400
'Named_variable' => 21,
2401
'Table_separator' => 32,
2402
'Symbolic_variable' => 33,
2403
'Tag_name' => 34,
2404
'Table' => 37,
2405
'Include' => 36,
2406
'Space' => 23,
2407
'Word' => 27,
2408
'StreamedPart' => 28
2409
},
2410
GOTOS => {
2411
'basic' => 83,
2412
'embedded' => 31,
2413
'included' => 24,
2414
'table_separator' => 25,
2415
'table' => 22,
2416
'tag' => 26,
2417
'element' => 35
2418
}
2419
},
2420
{#State 30
2421
DEFAULT => -147,
2422
GOTOS => {
2423
'@28-1' => 85
2424
}
2425
},
2426
{#State 31
2427
DEFAULT => -114
2428
},
2429
{#State 32
2430
DEFAULT => -143
2431
},
2432
{#State 33
2433
DEFAULT => -111
2434
},
2435
{#State 34
2436
DEFAULT => -124,
2437
GOTOS => {
2438
'@19-1' => 86
2439
}
2440
},
2441
{#State 35
2442
DEFAULT => -103
2443
},
2444
{#State 36
2445
DEFAULT => -150,
2446
GOTOS => {
2447
'@30-1' => 87
2448
}
2449
},
2450
{#State 37
2451
DEFAULT => -140,
2452
GOTOS => {
2453
'@24-1' => 88
2454
}
2455
},
2456
{#State 38
2457
DEFAULT => -6
2458
},
2459
{#State 39
2460
ACTIONS => {
2461
"|" => 90,
2462
"||" => 89
2463
}
2464
},
2465
{#State 40
2466
DEFAULT => -153,
2467
GOTOS => {
2468
'@32-3' => 91
2469
}
2470
},
2471
{#State 41
2472
DEFAULT => -58,
2473
GOTOS => {
2474
'@8-1' => 92
2475
}
2476
},
2477
{#State 42
2478
DEFAULT => -144,
2479
GOTOS => {
2480
'@26-1' => 93
2481
}
2482
},
2483
{#State 43
2484
DEFAULT => -80,
2485
GOTOS => {
2486
'@16-1' => 94
2487
}
2488
},
2489
{#State 44
2490
DEFAULT => -57
2491
},
2492
{#State 45
2493
DEFAULT => -43
2494
},
2495
{#State 46
2496
DEFAULT => -70,
2497
GOTOS => {
2498
'@11-1' => 95
2499
}
2500
},
2501
{#State 47
2502
DEFAULT => -52,
2503
GOTOS => {
2504
'@6-1' => 96
2505
}
2506
},
2507
{#State 48
2508
DEFAULT => -47,
2509
GOTOS => {
2510
'@5-1' => 97
2511
}
2512
},
2513
{#State 49
2514
ACTIONS => {
2515
"=" => 99
2516
},
2517
DEFAULT => -26,
2518
GOTOS => {
2519
'@3-1' => 98
2520
}
2521
},
2522
{#State 50
2523
ACTIONS => {
2524
'Colon' => 41,
2525
"<" => 100,
2526
'Dpoint_cache_hit' => 44,
2527
"*" => 47,
2528
">" => 102,
2529
'Upoint_cache_hit' => 62,
2530
'Opoint_cache_hit' => 70,
2531
"#" => 78
2532
},
2533
DEFAULT => -20,
2534
GOTOS => {
2535
'list_shifter' => 103,
2536
'dlist' => 60,
2537
'list_shift' => 101,
2538
'dlist_opener' => 63,
2539
'upoint' => 45,
2540
'opoint' => 55,
2541
'olist' => 64,
2542
'ulist' => 65,
2543
'dpoint' => 56,
2544
'opoint_opener' => 48,
2545
'list_part' => 104
2546
}
2547
},
2548
{#State 51
2549
ACTIONS => {
2550
"-" => 105,
2551
'Ils' => 52,
2552
'Block_cache_hit' => 73
2553
},
2554
DEFAULT => -19,
2555
GOTOS => {
2556
'block_flagnew' => 106,
2557
'block' => 107
2558
}
2559
},
2560
{#State 52
2561
DEFAULT => -65,
2562
GOTOS => {
2563
'@10-1' => 108
2564
}
2565
},
2566
{#State 53
2567
DEFAULT => -28
2568
},
2569
{#State 54
2570
DEFAULT => -69
2571
},
2572
{#State 55
2573
DEFAULT => -41
2574
},
2575
{#State 56
2576
DEFAULT => -45
2577
},
2578
{#State 57
2579
DEFAULT => -72,
2580
GOTOS => {
2581
'@12-1' => 109
2582
}
2583
},
2584
{#State 58
2585
DEFAULT => -97
2586
},
2587
{#State 59
2588
DEFAULT => -15
2589
},
2590
{#State 60
2591
ACTIONS => {
2592
'Colon' => 41,
2593
'Dpoint_cache_hit' => 44
2594
},
2595
DEFAULT => -40,
2596
GOTOS => {
2597
'dpoint' => 110,
2598
'dlist_opener' => 63
2599
}
2600
},
2601
{#State 61
2602
ACTIONS => {
2603
"=" => 111
2604
},
2605
DEFAULT => -110
2606
},
2607
{#State 62
2608
DEFAULT => -54
2609
},
2610
{#State 63
2611
DEFAULT => -55,
2612
GOTOS => {
2613
'@7-1' => 112
2614
}
2615
},
2616
{#State 64
2617
ACTIONS => {
2618
'Opoint_cache_hit' => 70,
2619
"#" => 78
2620
},
2621
DEFAULT => -38,
2622
GOTOS => {
2623
'opoint' => 113,
2624
'opoint_opener' => 48
2625
}
2626
},
2627
{#State 65
2628
ACTIONS => {
2629
"*" => 47,
2630
'Upoint_cache_hit' => 62
2631
},
2632
DEFAULT => -39,
2633
GOTOS => {
2634
'upoint' => 114
2635
}
2636
},
2637
{#State 66
2638
DEFAULT => -68
2639
},
2640
{#State 67
2641
DEFAULT => -98
2642
},
2643
{#State 68
2644
DEFAULT => -14
2645
},
2646
{#State 69
2647
DEFAULT => -17
2648
},
2649
{#State 70
2650
DEFAULT => -49
2651
},
2652
{#State 71
2653
ACTIONS => {
2654
"/" => 115
2655
}
2656
},
2657
{#State 72
2658
DEFAULT => -21
2659
},
2660
{#State 73
2661
DEFAULT => -67
2662
},
2663
{#State 74
2664
DEFAULT => -29
2665
},
2666
{#State 75
2667
DEFAULT => -18
2668
},
2669
{#State 76
2670
DEFAULT => -16
2671
},
2672
{#State 77
2673
DEFAULT => -11
2674
},
2675
{#State 78
2676
ACTIONS => {
2677
"#" => 116
2678
},
2679
DEFAULT => -50
2680
},
2681
{#State 79
2682
DEFAULT => -35
2683
},
2684
{#State 80
2685
DEFAULT => -60
2686
},
2687
{#State 81
2688
DEFAULT => -74,
2689
GOTOS => {
2690
'@13-1' => 117
2691
}
2692
},
2693
{#State 82
2694
DEFAULT => -13
2695
},
2696
{#State 83
2697
DEFAULT => -102
2698
},
2699
{#State 84
2700
DEFAULT => -34
2701
},
2702
{#State 85
2703
ACTIONS => {
2704
"{" => 119
2705
},
2706
GOTOS => {
2707
'used_tagpars' => 118
2708
}
2709
},
2710
{#State 86
2711
ACTIONS => {
2712
"{" => 119
2713
},
2714
DEFAULT => -127,
2715
GOTOS => {
2716
'used_tagpars' => 120,
2717
'optional_tagpars' => 121
2718
}
2719
},
2720
{#State 87
2721
ACTIONS => {
2722
"{" => 119
2723
},
2724
GOTOS => {
2725
'used_tagpars' => 122
2726
}
2727
},
2728
{#State 88
2729
ACTIONS => {
2730
"{" => 119
2731
},
2732
GOTOS => {
2733
'used_tagpars' => 123
2734
}
2735
},
2736
{#State 89
2737
DEFAULT => -5
2738
},
2739
{#State 90
2740
ACTIONS => {
2741
'Word' => 124
2742
}
2743
},
2744
{#State 91
2745
ACTIONS => {
2746
"{" => 119
2747
},
2748
DEFAULT => -127,
2749
GOTOS => {
2750
'used_tagpars' => 120,
2751
'optional_tagpars' => 125
2752
}
2753
},
2754
{#State 92
2755
ACTIONS => {
2756
'Embed' => 30,
2757
'Named_variable' => 21,
2758
'Symbolic_variable' => 33,
2759
'Tag_name' => 34,
2760
'Space' => 23,
2761
'Include' => 36,
2762
'Word' => 27,
2763
'StreamedPart' => 28
2764
},
2765
GOTOS => {
2766
'elements' => 126,
2767
'embedded' => 31,
2768
'included' => 24,
2769
'tag' => 26,
2770
'element' => 127
2771
}
2772
},
2773
{#State 93
2774
ACTIONS => {
2775
'Word' => 128
2776
},
2777
GOTOS => {
2778
'words' => 129
2779
}
2780
},
2781
{#State 94
2782
ACTIONS => {
2783
'Word' => 128
2784
},
2785
GOTOS => {
2786
'words' => 130
2787
}
2788
},
2789
{#State 95
2790
ACTIONS => {
2791
'Embed' => 30,
2792
'Named_variable' => 21,
2793
'Table_separator' => 32,
2794
'Symbolic_variable' => 33,
2795
'Tag_name' => 34,
2796
'Table' => 37,
2797
'Include' => 36,
2798
'Space' => 23,
2799
'Word' => 27,
2800
'EOL' => 67,
2801
'StreamedPart' => 28
2802
},
2803
DEFAULT => -87,
2804
GOTOS => {
2805
'basic' => 58,
2806
'embedded' => 31,
2807
'table' => 22,
2808
'literals' => 131,
2809
'element' => 35,
2810
'literal' => 132,
2811
'included' => 24,
2812
'table_separator' => 25,
2813
'tag' => 26,
2814
'optional_literals' => 133
2815
}
2816
},
2817
{#State 96
2818
ACTIONS => {
2819
'Embed' => 30,
2820
'Named_variable' => 21,
2821
'Table_separator' => 32,
2822
'Symbolic_variable' => 33,
2823
'Tag_name' => 34,
2824
'Table' => 37,
2825
'Include' => 36,
2826
'Space' => 23,
2827
'Word' => 27,
2828
'EOL' => 67,
2829
'StreamedPart' => 28
2830
},
2831
GOTOS => {
2832
'basic' => 58,
2833
'embedded' => 31,
2834
'table' => 22,
2835
'element' => 35,
2836
'literal' => 46,
2837
'text' => 134,
2838
'table_separator' => 25,
2839
'included' => 24,
2840
'tag' => 26
2841
}
2842
},
2843
{#State 97
2844
ACTIONS => {
2845
'Embed' => 30,
2846
'Named_variable' => 21,
2847
'Table_separator' => 32,
2848
'Symbolic_variable' => 33,
2849
'Tag_name' => 34,
2850
'Table' => 37,
2851
'Include' => 36,
2852
'Space' => 23,
2853
'Word' => 27,
2854
'EOL' => 67,
2855
'StreamedPart' => 28
2856
},
2857
GOTOS => {
2858
'basic' => 58,
2859
'embedded' => 31,
2860
'table' => 22,
2861
'element' => 35,
2862
'literal' => 46,
2863
'text' => 135,
2864
'table_separator' => 25,
2865
'included' => 24,
2866
'tag' => 26
2867
}
2868
},
2869
{#State 98
2870
ACTIONS => {
2871
'Embed' => 30,
2872
'Named_variable' => 21,
2873
'Table_separator' => 32,
2874
'Symbolic_variable' => 33,
2875
'Tag_name' => 34,
2876
'Table' => 37,
2877
'Include' => 36,
2878
'Space' => 23,
2879
'Word' => 27,
2880
'StreamedPart' => 28
2881
},
2882
GOTOS => {
2883
'basic' => 20,
2884
'basics' => 136,
2885
'embedded' => 31,
2886
'table' => 22,
2887
'element' => 35,
2888
'table_separator' => 25,
2889
'included' => 24,
2890
'tag' => 26
2891
}
2892
},
2893
{#State 99
2894
DEFAULT => -30
2895
},
2896
{#State 100
2897
DEFAULT => -86
2898
},
2899
{#State 101
2900
ACTIONS => {
2901
'Opoint_cache_hit' => 70,
2902
'Colon' => 41,
2903
"*" => 47,
2904
"#" => 78,
2905
'Upoint_cache_hit' => 62,
2906
'Dpoint_cache_hit' => 44
2907
},
2908
GOTOS => {
2909
'dlist' => 60,
2910
'dlist_opener' => 63,
2911
'upoint' => 45,
2912
'opoint' => 55,
2913
'olist' => 64,
2914
'dpoint' => 56,
2915
'ulist' => 65,
2916
'opoint_opener' => 48,
2917
'list_part' => 137
2918
}
2919
},
2920
{#State 102
2921
DEFAULT => -85
2922
},
2923
{#State 103
2924
DEFAULT => -82,
2925
GOTOS => {
2926
'@17-1' => 138
2927
}
2928
},
2929
{#State 104
2930
DEFAULT => -36
2931
},
2932
{#State 105
2933
DEFAULT => -63,
2934
GOTOS => {
2935
'@9-1' => 139
2936
}
2937
},
2938
{#State 106
2939
ACTIONS => {
2940
'Ils' => 52,
2941
'Block_cache_hit' => 73
2942
},
2943
GOTOS => {
2944
'compound_block' => 140,
2945
'block' => 80
2946
}
2947
},
2948
{#State 107
2949
DEFAULT => -61
2950
},
2951
{#State 108
2952
ACTIONS => {
2953
'Embed' => 30,
2954
'Named_variable' => 21,
2955
'Table_separator' => 32,
2956
'Symbolic_variable' => 33,
2957
'Tag_name' => 34,
2958
'Table' => 37,
2959
'Include' => 36,
2960
'Space' => 23,
2961
'Word' => 27,
2962
'EOL' => 67,
2963
'StreamedPart' => 28
2964
},
2965
GOTOS => {
2966
'basic' => 58,
2967
'embedded' => 31,
2968
'table' => 22,
2969
'element' => 35,
2970
'literal' => 46,
2971
'text' => 141,
2972
'table_separator' => 25,
2973
'included' => 24,
2974
'tag' => 26
2975
}
2976
},
2977
{#State 109
2978
ACTIONS => {
2979
'Embed' => 30,
2980
'Named_variable' => 21,
2981
'Table_separator' => 32,
2982
'Symbolic_variable' => 33,
2983
'Tag_name' => 34,
2984
'Table' => 37,
2985
'Include' => 36,
2986
'Space' => 23,
2987
'Word' => 27,
2988
'EOL' => 67,
2989
'StreamedPart' => 28
2990
},
2991
GOTOS => {
2992
'basic' => 58,
2993
'embedded' => 31,
2994
'table' => 22,
2995
'element' => 35,
2996
'literal' => 46,
2997
'text' => 142,
2998
'table_separator' => 25,
2999
'included' => 24,
3000
'tag' => 26
3001
}
3002
},
3003
{#State 110
3004
DEFAULT => -46
3005
},
3006
{#State 111
3007
DEFAULT => -76,
3008
GOTOS => {
3009
'@14-2' => 143
3010
}
3011
},
3012
{#State 112
3013
ACTIONS => {
3014
'Embed' => 30,
3015
'Named_variable' => 21,
3016
'Table_separator' => 32,
3017
'Symbolic_variable' => 33,
3018
'Tag_name' => 34,
3019
'Table' => 37,
3020
'Include' => 36,
3021
'Space' => 23,
3022
'Word' => 27,
3023
'EOL' => 67,
3024
'StreamedPart' => 28
3025
},
3026
GOTOS => {
3027
'basic' => 58,
3028
'embedded' => 31,
3029
'table' => 22,
3030
'element' => 35,
3031
'literal' => 46,
3032
'text' => 144,
3033
'table_separator' => 25,
3034
'included' => 24,
3035
'tag' => 26
3036
}
3037
},
3038
{#State 113
3039
DEFAULT => -42
3040
},
3041
{#State 114
3042
DEFAULT => -44
3043
},
3044
{#State 115
3045
DEFAULT => -78,
3046
GOTOS => {
3047
'@15-2' => 145
3048
}
3049
},
3050
{#State 116
3051
DEFAULT => -51
3052
},
3053
{#State 117
3054
ACTIONS => {
3055
'Embed' => 30,
3056
'Empty_line' => 148,
3057
'Named_variable' => 21,
3058
'Table_separator' => 32,
3059
'Symbolic_variable' => 33,
3060
'Tag_name' => 34,
3061
'Table' => 37,
3062
'Include' => 36,
3063
'Space' => 23,
3064
'Word' => 27,
3065
'EOL' => 67,
3066
'StreamedPart' => 28
3067
},
3068
GOTOS => {
3069
'basic' => 58,
3070
'embedded' => 31,
3071
'table' => 22,
3072
'literal_or_empty_line' => 147,
3073
'element' => 35,
3074
'literal' => 146,
3075
'literals_and_empty_lines' => 149,
3076
'included' => 24,
3077
'table_separator' => 25,
3078
'tag' => 26
3079
}
3080
},
3081
{#State 118
3082
DEFAULT => -148,
3083
GOTOS => {
3084
'@29-3' => 150
3085
}
3086
},
3087
{#State 119
3088
ACTIONS => {
3089
'Word' => 152
3090
},
3091
GOTOS => {
3092
'tagpars' => 151,
3093
'tagpar' => 153
3094
}
3095
},
3096
{#State 120
3097
DEFAULT => -128
3098
},
3099
{#State 121
3100
DEFAULT => -125,
3101
GOTOS => {
3102
'@20-3' => 154
3103
}
3104
},
3105
{#State 122
3106
DEFAULT => -151
3107
},
3108
{#State 123
3109
DEFAULT => -141,
3110
GOTOS => {
3111
'@25-3' => 155
3112
}
3113
},
3114
{#State 124
3115
DEFAULT => -7
3116
},
3117
{#State 125
3118
DEFAULT => -154,
3119
GOTOS => {
3120
'@33-5' => 156
3121
}
3122
},
3123
{#State 126
3124
ACTIONS => {
3125
'Colon' => 157,
3126
'Embed' => 30,
3127
'Named_variable' => 21,
3128
'Symbolic_variable' => 33,
3129
'Tag_name' => 34,
3130
'Include' => 36,
3131
'Space' => 23,
3132
'Word' => 27,
3133
'StreamedPart' => 28
3134
},
3135
GOTOS => {
3136
'embedded' => 31,
3137
'included' => 24,
3138
'tag' => 26,
3139
'element' => 158
3140
}
3141
},
3142
{#State 127
3143
DEFAULT => -106
3144
},
3145
{#State 128
3146
DEFAULT => -118
3147
},
3148
{#State 129
3149
ACTIONS => {
3150
'Word' => 159,
3151
'EOL' => 160
3152
}
3153
},
3154
{#State 130
3155
ACTIONS => {
3156
'Empty_line' => 161,
3157
'Word' => 159
3158
}
3159
},
3160
{#State 131
3161
ACTIONS => {
3162
'Embed' => 30,
3163
'Named_variable' => 21,
3164
'Table_separator' => 32,
3165
'Symbolic_variable' => 33,
3166
'Tag_name' => 34,
3167
'Table' => 37,
3168
'Include' => 36,
3169
'Space' => 23,
3170
'Word' => 27,
3171
'EOL' => 67,
3172
'StreamedPart' => 28
3173
},
3174
DEFAULT => -88,
3175
GOTOS => {
3176
'basic' => 58,
3177
'embedded' => 31,
3178
'table' => 22,
3179
'element' => 35,
3180
'literal' => 162,
3181
'table_separator' => 25,
3182
'included' => 24,
3183
'tag' => 26
3184
}
3185
},
3186
{#State 132
3187
DEFAULT => -89
3188
},
3189
{#State 133
3190
ACTIONS => {
3191
'Empty_line' => 163
3192
}
3193
},
3194
{#State 134
3195
DEFAULT => -53
3196
},
3197
{#State 135
3198
DEFAULT => -48
3199
},
3200
{#State 136
3201
ACTIONS => {
3202
'Embed' => 30,
3203
'Named_variable' => 21,
3204
'Table_separator' => 32,
3205
"~" => 164,
3206
'Symbolic_variable' => 33,
3207
'Tag_name' => 34,
3208
'Table' => 37,
3209
'Include' => 36,
3210
'Space' => 23,
3211
'Word' => 27,
3212
'StreamedPart' => 28
3213
},
3214
DEFAULT => -31,
3215
GOTOS => {
3216
'basic' => 83,
3217
'embedded' => 31,
3218
'table' => 22,
3219
'element' => 35,
3220
'table_separator' => 25,
3221
'included' => 24,
3222
'optional_headline_shortcut' => 165,
3223
'tag' => 26
3224
}
3225
},
3226
{#State 137
3227
DEFAULT => -37
3228
},
3229
{#State 138
3230
ACTIONS => {
3231
'Number' => 166
3232
},
3233
DEFAULT => -116,
3234
GOTOS => {
3235
'optional_number' => 167
3236
}
3237
},
3238
{#State 139
3239
ACTIONS => {
3240
'Empty_line' => 168
3241
}
3242
},
3243
{#State 140
3244
ACTIONS => {
3245
"-" => 105,
3246
'Ils' => 52,
3247
'Block_cache_hit' => 73
3248
},
3249
DEFAULT => -62,
3250
GOTOS => {
3251
'block_flagnew' => 106,
3252
'block' => 107
3253
}
3254
},
3255
{#State 141
3256
DEFAULT => -66
3257
},
3258
{#State 142
3259
DEFAULT => -73
3260
},
3261
{#State 143
3262
ACTIONS => {
3263
'Embed' => 30,
3264
'Named_variable' => 21,
3265
'Table_separator' => 32,
3266
'Symbolic_variable' => 33,
3267
'Tag_name' => 34,
3268
'Table' => 37,
3269
'Include' => 36,
3270
'Space' => 23,
3271
'Word' => 27,
3272
'EOL' => 67,
3273
'StreamedPart' => 28
3274
},
3275
GOTOS => {
3276
'basic' => 58,
3277
'embedded' => 31,
3278
'table' => 22,
3279
'element' => 35,
3280
'literal' => 46,
3281
'text' => 169,
3282
'table_separator' => 25,
3283
'included' => 24,
3284
'tag' => 26
3285
}
3286
},
3287
{#State 144
3288
DEFAULT => -56
3289
},
3290
{#State 145
3291
ACTIONS => {
3292
'Embed' => 30,
3293
'Named_variable' => 21,
3294
'Table_separator' => 32,
3295
'Symbolic_variable' => 33,
3296
'Tag_name' => 34,
3297
'Table' => 37,
3298
'Include' => 36,
3299
'Space' => 23,
3300
'Word' => 27,
3301
'StreamedPart' => 28
3302
},
3303
DEFAULT => -99,
3304
GOTOS => {
3305
'basic' => 20,
3306
'basics' => 170,
3307
'embedded' => 31,
3308
'table' => 22,
3309
'element' => 35,
3310
'table_separator' => 25,
3311
'included' => 24,
3312
'tag' => 26,
3313
'optional_basics' => 171
3314
}
3315
},
3316
{#State 146
3317
DEFAULT => -95
3318
},
3319
{#State 147
3320
DEFAULT => -93
3321
},
3322
{#State 148
3323
DEFAULT => -96
3324
},
3325
{#State 149
3326
ACTIONS => {
3327
'Embed' => 30,
3328
'Empty_line' => 148,
3329
'Named_variable' => 21,
3330
'Table_separator' => 32,
3331
'Symbolic_variable' => 33,
3332
'Tag_name' => 34,
3333
'Table' => 37,
3334
'Include' => 36,
3335
'Space' => 23,
3336
'Word' => 27,
3337
'Heredoc_close' => 173,
3338
'EOL' => 67,
3339
'StreamedPart' => 28
3340
},
3341
GOTOS => {
3342
'basic' => 58,
3343
'embedded' => 31,
3344
'table' => 22,
3345
'literal_or_empty_line' => 172,
3346
'element' => 35,
3347
'literal' => 146,
3348
'included' => 24,
3349
'table_separator' => 25,
3350
'tag' => 26
3351
}
3352
},
3353
{#State 150
3354
ACTIONS => {
3355
'Embed' => 30,
3356
'Empty_line' => 148,
3357
'Named_variable' => 21,
3358
'Table_separator' => 32,
3359
'Symbolic_variable' => 33,
3360
'Tag_name' => 34,
3361
'Table' => 37,
3362
'Include' => 36,
3363
'Space' => 23,
3364
'Word' => 27,
3365
'EOL' => 67,
3366
'StreamedPart' => 28
3367
},
3368
DEFAULT => -91,
3369
GOTOS => {
3370
'basic' => 58,
3371
'embedded' => 31,
3372
'optional_literals_and_empty_lines' => 175,
3373
'table' => 22,
3374
'literal_or_empty_line' => 147,
3375
'element' => 35,
3376
'literal' => 146,
3377
'literals_and_empty_lines' => 174,
3378
'included' => 24,
3379
'table_separator' => 25,
3380
'tag' => 26
3381
}
3382
},
3383
{#State 151
3384
ACTIONS => {
3385
'Space' => 177,
3386
"}" => 176
3387
}
3388
},
3389
{#State 152
3390
DEFAULT => -132,
3391
GOTOS => {
3392
'@21-1' => 178
3393
}
3394
},
3395
{#State 153
3396
DEFAULT => -130
3397
},
3398
{#State 154
3399
ACTIONS => {
3400
"<" => 179
3401
},
3402
DEFAULT => -137,
3403
GOTOS => {
3404
'optional_tagbody' => 180
3405
}
3406
},
3407
{#State 155
3408
ACTIONS => {
3409
'Embed' => 30,
3410
'Empty_line' => 148,
3411
'Named_variable' => 21,
3412
'Table_separator' => 32,
3413
'Symbolic_variable' => 33,
3414
'Tag_name' => 34,
3415
'Table' => 37,
3416
'Include' => 36,
3417
'Space' => 23,
3418
'Word' => 27,
3419
'EOL' => 67,
3420
'StreamedPart' => 28
3421
},
3422
DEFAULT => -91,
3423
GOTOS => {
3424
'basic' => 58,
3425
'embedded' => 31,
3426
'optional_literals_and_empty_lines' => 181,
3427
'table' => 22,
3428
'literal_or_empty_line' => 147,
3429
'element' => 35,
3430
'literal' => 146,
3431
'literals_and_empty_lines' => 174,
3432
'included' => 24,
3433
'table_separator' => 25,
3434
'tag' => 26
3435
}
3436
},
3437
{#State 156
3438
ACTIONS => {
3439
'Colon' => 182
3440
}
3441
},
3442
{#State 157
3443
DEFAULT => -59
3444
},
3445
{#State 158
3446
DEFAULT => -107
3447
},
3448
{#State 159
3449
DEFAULT => -119
3450
},
3451
{#State 160
3452
DEFAULT => -145,
3453
GOTOS => {
3454
'@27-4' => 183
3455
}
3456
},
3457
{#State 161
3458
DEFAULT => -81
3459
},
3460
{#State 162
3461
DEFAULT => -90
3462
},
3463
{#State 163
3464
DEFAULT => -71
3465
},
3466
{#State 164
3467
ACTIONS => {
3468
'Space' => 185,
3469
'Word' => 187
3470
},
3471
GOTOS => {
3472
'words_or_spaces' => 186,
3473
'word_or_space' => 184
3474
}
3475
},
3476
{#State 165
3477
ACTIONS => {
3478
'Empty_line' => 188
3479
}
3480
},
3481
{#State 166
3482
DEFAULT => -117
3483
},
3484
{#State 167
3485
DEFAULT => -83,
3486
GOTOS => {
3487
'@18-3' => 189
3488
}
3489
},
3490
{#State 168
3491
DEFAULT => -64
3492
},
3493
{#State 169
3494
DEFAULT => -77
3495
},
3496
{#State 170
3497
ACTIONS => {
3498
'Embed' => 30,
3499
'Named_variable' => 21,
3500
'Table_separator' => 32,
3501
'Symbolic_variable' => 33,
3502
'Tag_name' => 34,
3503
'Table' => 37,
3504
'Include' => 36,
3505
'Space' => 23,
3506
'Word' => 27,
3507
'StreamedPart' => 28
3508
},
3509
DEFAULT => -100,
3510
GOTOS => {
3511
'basic' => 83,
3512
'embedded' => 31,
3513
'included' => 24,
3514
'table_separator' => 25,
3515
'table' => 22,
3516
'tag' => 26,
3517
'element' => 35
3518
}
3519
},
3520
{#State 171
3521
ACTIONS => {
3522
'Empty_line' => 190
3523
}
3524
},
3525
{#State 172
3526
DEFAULT => -94
3527
},
3528
{#State 173
3529
DEFAULT => -75
3530
},
3531
{#State 174
3532
ACTIONS => {
3533
'Embed' => 30,
3534
'Empty_line' => 148,
3535
'Named_variable' => 21,
3536
'Table_separator' => 32,
3537
'Symbolic_variable' => 33,
3538
'Tag_name' => 34,
3539
'Table' => 37,
3540
'Include' => 36,
3541
'Space' => 23,
3542
'Word' => 27,
3543
'EOL' => 67,
3544
'StreamedPart' => 28
3545
},
3546
DEFAULT => -92,
3547
GOTOS => {
3548
'basic' => 58,
3549
'embedded' => 31,
3550
'table' => 22,
3551
'literal_or_empty_line' => 172,
3552
'element' => 35,
3553
'literal' => 146,
3554
'included' => 24,
3555
'table_separator' => 25,
3556
'tag' => 26
3557
}
3558
},
3559
{#State 175
3560
ACTIONS => {
3561
'Embedded' => 191
3562
}
3563
},
3564
{#State 176
3565
DEFAULT => -129
3566
},
3567
{#State 177
3568
ACTIONS => {
3569
'Word' => 152
3570
},
3571
GOTOS => {
3572
'tagpar' => 192
3573
}
3574
},
3575
{#State 178
3576
ACTIONS => {
3577
"=" => 193
3578
}
3579
},
3580
{#State 179
3581
DEFAULT => -138,
3582
GOTOS => {
3583
'@23-1' => 194
3584
}
3585
},
3586
{#State 180
3587
DEFAULT => -126
3588
},
3589
{#State 181
3590
ACTIONS => {
3591
'Tabled' => 195
3592
}
3593
},
3594
{#State 182
3595
DEFAULT => -155,
3596
GOTOS => {
3597
'@34-7' => 196
3598
}
3599
},
3600
{#State 183
3601
ACTIONS => {
3602
'Embed' => 30,
3603
'Named_variable' => 21,
3604
'Table_separator' => 32,
3605
'Symbolic_variable' => 33,
3606
'Tag_name' => 34,
3607
'Table' => 37,
3608
'Include' => 36,
3609
'Space' => 23,
3610
'Word' => 27,
3611
'EOL' => 67,
3612
'StreamedPart' => 28
3613
},
3614
DEFAULT => -87,
3615
GOTOS => {
3616
'basic' => 58,
3617
'embedded' => 31,
3618
'table' => 22,
3619
'literals' => 131,
3620
'element' => 35,
3621
'literal' => 132,
3622
'included' => 24,
3623
'table_separator' => 25,
3624
'tag' => 26,
3625
'optional_literals' => 197
3626
}
3627
},
3628
{#State 184
3629
DEFAULT => -120
3630
},
3631
{#State 185
3632
DEFAULT => -123
3633
},
3634
{#State 186
3635
ACTIONS => {
3636
'Space' => 185,
3637
'Word' => 187
3638
},
3639
DEFAULT => -32,
3640
GOTOS => {
3641
'word_or_space' => 198
3642
}
3643
},
3644
{#State 187
3645
DEFAULT => -122
3646
},
3647
{#State 188
3648
DEFAULT => -27
3649
},
3650
{#State 189
3651
ACTIONS => {
3652
'Empty_line' => 199
3653
}
3654
},
3655
{#State 190
3656
DEFAULT => -79
3657
},
3658
{#State 191
3659
DEFAULT => -149
3660
},
3661
{#State 192
3662
DEFAULT => -131
3663
},
3664
{#State 193
3665
DEFAULT => -133,
3666
GOTOS => {
3667
'@22-3' => 200
3668
}
3669
},
3670
{#State 194
3671
ACTIONS => {
3672
'Embed' => 30,
3673
'Named_variable' => 21,
3674
'Table_separator' => 32,
3675
'Symbolic_variable' => 33,
3676
'Tag_name' => 34,
3677
'Table' => 37,
3678
'Include' => 36,
3679
'Space' => 23,
3680
'Word' => 27,
3681
'EOL' => 67,
3682
'StreamedPart' => 28
3683
},
3684
GOTOS => {
3685
'basic' => 58,
3686
'embedded' => 31,
3687
'table' => 22,
3688
'literals' => 201,
3689
'element' => 35,
3690
'literal' => 132,
3691
'included' => 24,
3692
'table_separator' => 25,
3693
'tag' => 26
3694
}
3695
},
3696
{#State 195
3697
DEFAULT => -142
3698
},
3699
{#State 196
3700
ACTIONS => {
3701
'Embed' => 30,
3702
'Named_variable' => 21,
3703
'Table_separator' => 32,
3704
'Symbolic_variable' => 33,
3705
'Tag_name' => 34,
3706
'Table' => 37,
3707
'Include' => 36,
3708
'Space' => 23,
3709
'Word' => 27,
3710
'EOL' => 67,
3711
'StreamedPart' => 28
3712
},
3713
GOTOS => {
3714
'basic' => 58,
3715
'embedded' => 31,
3716
'table' => 22,
3717
'element' => 35,
3718
'literal' => 46,
3719
'text' => 202,
3720
'table_separator' => 25,
3721
'included' => 24,
3722
'tag' => 26
3723
}
3724
},
3725
{#State 197
3726
ACTIONS => {
3727
'Empty_line' => 203
3728
}
3729
},
3730
{#State 198
3731
DEFAULT => -121
3732
},
3733
{#State 199
3734
DEFAULT => -84
3735
},
3736
{#State 200
3737
ACTIONS => {
3738
"\"" => 206,
3739
'Word' => 204
3740
},
3741
GOTOS => {
3742
'tagvalue' => 205
3743
}
3744
},
3745
{#State 201
3746
ACTIONS => {
3747
'Embed' => 30,
3748
'Named_variable' => 21,
3749
'Table_separator' => 32,
3750
'Symbolic_variable' => 33,
3751
'Tag_name' => 34,
3752
'Table' => 37,
3753
'Include' => 36,
3754
'Space' => 23,
3755
'Word' => 27,
3756
'EOL' => 67,
3757
'StreamedPart' => 28,
3758
">" => 207
3759
},
3760
GOTOS => {
3761
'basic' => 58,
3762
'embedded' => 31,
3763
'table' => 22,
3764
'element' => 35,
3765
'literal' => 162,
3766
'table_separator' => 25,
3767
'included' => 24,
3768
'tag' => 26
3769
}
3770
},
3771
{#State 202
3772
DEFAULT => -156
3773
},
3774
{#State 203
3775
DEFAULT => -146
3776
},
3777
{#State 204
3778
DEFAULT => -135
3779
},
3780
{#State 205
3781
DEFAULT => -134
3782
},
3783
{#State 206
3784
ACTIONS => {
3785
'Embed' => 30,
3786
'Named_variable' => 21,
3787
'Table_separator' => 32,
3788
'Symbolic_variable' => 33,
3789
'Tag_name' => 34,
3790
'Table' => 37,
3791
'Include' => 36,
3792
'Space' => 23,
3793
'Word' => 27,
3794
'StreamedPart' => 28
3795
},
3796
GOTOS => {
3797
'basic' => 20,
3798
'basics' => 208,
3799
'embedded' => 31,
3800
'table' => 22,
3801
'element' => 35,
3802
'table_separator' => 25,
3803
'included' => 24,
3804
'tag' => 26
3805
}
3806
},
3807
{#State 207
3808
DEFAULT => -139
3809
},
3810
{#State 208
3811
ACTIONS => {
3812
'Embed' => 30,
3813
'Named_variable' => 21,
3814
'Table_separator' => 32,
3815
'Symbolic_variable' => 33,
3816
'Tag_name' => 34,
3817
'Table' => 37,
3818
'Include' => 36,
3819
'Space' => 23,
3820
"\"" => 209,
3821
'Word' => 27,
3822
'StreamedPart' => 28
3823
},
3824
GOTOS => {
3825
'basic' => 83,
3826
'embedded' => 31,
3827
'included' => 24,
3828
'table_separator' => 25,
3829
'table' => 22,
3830
'tag' => 26,
3831
'element' => 35
3832
}
3833
},
3834
{#State 209
3835
DEFAULT => -136
3836
}
3837
],
3838
yyrules =>
3839
[
3840
[#Rule 0
3841
'$start', 2, undef
3842
],
3843
[#Rule 1
3844
'document', 1,
3845
sub
3846
#line 1707 "ppParser.yp"
3847
{
3848
# skip empty "paragraphs"
3849
unless ($_[1][0]=~/^\s*$/ or not @{$_[1][0]})
3850
{
3851
# add data to the output stream
3852
push(@{$resultStreamRef->[STREAM_TOKENS]}, @{$_[1][0]});
3853
3854
# update tag finish memory
3855
_updateTagFinishMem(scalar(@{$resultStreamRef->[STREAM_TOKENS]}));
3856
3857
# update checksums (unless done before for parts)
3858
_updateChecksums($_[1][0], 'Paragraph_cache_hit') unless $_[1][0][0][STREAM_DIR_TYPE]==DIRECTIVE_BLOCK
3859
or $_[1][0][0][STREAM_DIR_TYPE]==DIRECTIVE_DLIST
3860
or $_[1][0][0][STREAM_DIR_TYPE]==DIRECTIVE_OLIST
3861
or $_[1][0][0][STREAM_DIR_TYPE]==DIRECTIVE_ULIST
3862
or $_[1][0][0][STREAM_DIR_TYPE]==DIRECTIVE_HEADLINE;
3863
3864
# update statistics, if necessary
3865
$statistics{$_[1][0][0][STREAM_DIR_TYPE]}++ unless not defined $_[1][0][0][STREAM_DIR_TYPE] or exists $embeddedParagraphs{$_[1][0][0][STREAM_DIR_TYPE]};
3866
3867
# perform special headline operations
3868
if ($_[1][0][0][STREAM_DIR_TYPE]==DIRECTIVE_HEADLINE)
3869
{
3870
# update headline stream by adding the token index of the headline
3871
push(@{$resultStreamRef->[STREAM_HEADLINES]}, @{$resultStreamRef->[STREAM_TOKENS]}-@{$_[1][0]});
3872
3873
# add a copy of the variables valid at the end of the page
3874
$_[1][0][0][STREAM_DIR_HINTS]{vars}=dclone(\%variables);
3875
3876
# let the user know that something is going on
3877
print STDERR "\r", ' ' x length('[Info] '), '... ', $statistics{&DIRECTIVE_HEADLINE}, " chapters read."
3878
if $flags{vis}
3879
and not $statistics{&DIRECTIVE_HEADLINE} % $flags{vis};
3880
}
3881
elsif ($_[1][0][0][STREAM_DIR_TYPE]!=DIRECTIVE_COMMENT)
3882
{
3883
# the document starts with streamed content before the first headline,
3884
# this is considered an error except when this happens due to an import
3885
_semerr($_[0], "$sourceFile, line $_[1][1]: the first chapter needs a headline, please add one.") unless exists $flags{complainedAbout1stHeadline};
3886
3887
# update complaint flag
3888
if (exists $flags{complainedAbout1stHeadline} and $flags{complainedAbout1stHeadline} eq 'IMPORT')
3889
{delete $flags{complainedAbout1stHeadline};}
3890
else
3891
{$flags{complainedAbout1stHeadline}=1;}
3892
}
3893
3894
# this is for the parser to flag success
3895
1;
3896
}
3897
}
3898
],
3899
[#Rule 2
3900
'document', 2,
3901
sub
3902
#line 1759 "ppParser.yp"
3903
{
3904
# skip empty "paragraphs"
3905
unless ($_[2][0]=~/^\s*$/ or not @{$_[2][0]})
3906
{
3907
# add data to the output stream, if necessary
3908
push(@{$resultStreamRef->[STREAM_TOKENS]}, @{$_[2][0]});
3909
3910
# update tag finish memory
3911
_updateTagFinishMem(scalar(@{$resultStreamRef->[STREAM_TOKENS]}));
3912
3913
# update checksums, if necessary
3914
_updateChecksums($_[2][0], 'Paragraph_cache_hit') unless $_[2][0][0][STREAM_DIR_TYPE]==DIRECTIVE_BLOCK
3915
or $_[2][0][0][STREAM_DIR_TYPE]==DIRECTIVE_DLIST
3916
or $_[2][0][0][STREAM_DIR_TYPE]==DIRECTIVE_OLIST
3917
or $_[2][0][0][STREAM_DIR_TYPE]==DIRECTIVE_ULIST
3918
or $_[2][0][0][STREAM_DIR_TYPE]==DIRECTIVE_HEADLINE;
3919
3920
# update ordered list flag as necessary
3921
$flags{olist}=0 unless $_[2][0][0][STREAM_DIR_TYPE]==DIRECTIVE_OLIST;
3922
3923
# update statistics, if necessary
3924
$statistics{$_[2][0][0][STREAM_DIR_TYPE]}++ unless exists $embeddedParagraphs{$_[2][0][0][STREAM_DIR_TYPE]};
3925
3926
# perform special headline operations
3927
if ($_[2][0][0][STREAM_DIR_TYPE]==DIRECTIVE_HEADLINE)
3928
{
3929
# update headline stream by adding the token index of the headline
3930
push(@{$resultStreamRef->[STREAM_HEADLINES]}, @{$resultStreamRef->[STREAM_TOKENS]}-@{$_[2][0]});
3931
3932
# add a copy of the variables valid at the end of the page
3933
$_[2][0][0][STREAM_DIR_HINTS]{vars}=dclone(\%variables);
3934
3935
# let the user know that something is going on, if necessary
3936
print STDERR "\r", ' ' x length('[Info] '), '... ', $statistics{&DIRECTIVE_HEADLINE}, " chapters read."
3937
if $flags{vis}
3938
and not $statistics{&DIRECTIVE_HEADLINE} % $flags{vis};
3939
}
3940
elsif (
3941
$_[2][0][0][STREAM_DIR_TYPE]!=DIRECTIVE_COMMENT
3942
and not @{$resultStreamRef->[STREAM_HEADLINES]}
3943
and (
3944
not exists $flags{complainedAbout1stHeadline}
3945
or $flags{complainedAbout1stHeadline} eq 'IMPORT'
3946
)
3947
)
3948
{
3949
# the document starts with streamed content before the first headline,
3950
# this is considered an error except when this happens due to an import
3951
_semerr($_[0], "$sourceFile, line $_[2][1]: the first chapter needs a headline, please add one.") unless exists $flags{complainedAbout1stHeadline};
3952
3953
# update complaint flag
3954
if (exists $flags{complainedAbout1stHeadline} and $flags{complainedAbout1stHeadline} eq 'IMPORT')
3955
{delete $flags{complainedAbout1stHeadline};}
3956
else
3957
{$flags{complainedAbout1stHeadline}=1;}
3958
}
3959
3960
# this is for the parser to flag success
3961
1;
3962
}
3963
}
3964
],
3965
[#Rule 3
3966
'optional_paragraph_filter', 0, undef
3967
],
3968
[#Rule 4
3969
'@1-1', 0,
3970
sub
3971
#line 1826 "ppParser.yp"
3972
{
3973
# switch to pfiltered mode
3974
_stateManager(STATE_PFILTER);
3975
}
3976
],
3977
[#Rule 5
3978
'optional_paragraph_filter', 4,
3979
sub
3980
#line 1831 "ppParser.yp"
3981
{
3982
# back to default mode
3983
_stateManager(STATE_PFILTERED);
3984
3985
# supply filter list
3986
$_[3];
3987
}
3988
],
3989
[#Rule 6
3990
'paragraph_filters', 1,
3991
sub
3992
#line 1843 "ppParser.yp"
3993
{
3994
# start a new filter list
3995
[[$_[1][0]], $_[1][1]];
3996
}
3997
],
3998
[#Rule 7
3999
'paragraph_filters', 3,
4000
sub
4001
#line 1848 "ppParser.yp"
4002
{
4003
# append to filter list and reply updated list
4004
push(@{$_[1][0]}, $_[3][0]);
4005
[$_[1][0], $_[3][1]];
4006
}
4007
],
4008
[#Rule 8
4009
'paragraph', 1, undef
4010
],
4011
[#Rule 9
4012
'paragraph', 1, undef
4013
],
4014
[#Rule 10
4015
'@2-1', 0,
4016
sub
4017
#line 1865 "ppParser.yp"
4018
{
4019
# filter set?
4020
if ($_[1])
4021
{
4022
# prepare an extra "token" to start the next paragraph
4023
$flags{virtualParagraphStart}=1;
4024
4025
# Disable storage of a checksum. (A filter can make the paragraph depending
4026
# on something outside the paragraph - the paragraph becomes dynamic.)
4027
$flags{checksummed}=0;
4028
}
4029
}
4030
],
4031
[#Rule 11
4032
'built_paragraph', 3,
4033
sub
4034
#line 1878 "ppParser.yp"
4035
{
4036
# reset the "extra token" flag (it already worked when the parser
4037
# reaches this point)
4038
$flags{virtualParagraphStart}=0;
4039
4040
# filters installed and active?
4041
if ($_[1])
4042
{
4043
# Does the caller want to evaluate code?
4044
if ($safeObject)
4045
{
4046
# update active contents base data, if necessary
4047
if ($flags{activeBaseData})
4048
{
4049
no strict 'refs';
4050
${join('::', ref($safeObject) ? $safeObject->root : 'main', 'PerlPoint')}=dclone($flags{activeBaseData});
4051
}
4052
4053
# peform filter call(s)
4054
my $result=_pfilterCall($_[0], $_[1][0], $_[3][0], $_[3][1]);
4055
4056
# reply unmodified paragraph in case of an error
4057
return $_[3] unless defined $result;
4058
4059
# make the result part of the input stream, if any
4060
_stackInput($_[0], @$result) if $result;
4061
4062
# reset the "end of input reached" flag if necessary
4063
$readCompletely=0 if $readCompletely;
4064
4065
# supply nothing here, the result must be reparsed first
4066
['', $_[3][2]];
4067
}
4068
else
4069
{
4070
# filters cannot be run, inform user
4071
warn "[Warn] $sourceFile, line $_[1][1]: Active Content is disabled, paragraph cannot be filtered.\n" unless $flags{display} & DISPLAY_NOWARN;
4072
4073
# supply the unmodified paragraph
4074
$_[3];
4075
}
4076
}
4077
else
4078
{
4079
# no filter: provide paragraph data
4080
$_[3];
4081
}
4082
}
4083
],
4084
[#Rule 12
4085
'built_paragraph', 1, undef
4086
],
4087
[#Rule 13
4088
'original_paragraph', 1, undef
4089
],
4090
[#Rule 14
4091
'original_paragraph', 1,
4092
sub
4093
#line 1932 "ppParser.yp"
4094
{
4095
# remove leading dummy tokens which might have been produced by "standalone macros"
4096
splice(@{$_[1][0]}, 1, 1) while @{$_[1][0]}>1 and !ref($_[1][0][1]) and $_[1][0][1] eq DUMMY_TOKEN;
4097
4098
# check if this paragraph consists of exactly one table only
4099
# or exactly one tag which is allowed to exists standalone,
4100
# or exactly one embedded region
4101
if (
4102
(
4103
# starting with a table tag or standalone tag?
4104
@{$_[1][0]}>1
4105
and ref($_[1][0][1]) eq 'ARRAY'
4106
and $_[1][0][1][STREAM_DIR_TYPE]==DIRECTIVE_TAG
4107
and (
4108
$_[1][0][1][STREAM_DIR_DATA]=~/^(TABLE)$/
4109
or (
4110
$_[1][0][1][STREAM_DIR_DATA]=~/^(\w+)$/
4111
and (
4112
(
4113
exists $tagsRef->{$1}
4114
and exists $tagsRef->{$1}{standalone}
4115
and $tagsRef->{$1}{standalone}
4116
)
4117
or $1 eq 'EMBED'
4118
)
4119
)
4120
)
4121
4122
# ending with the same tag?
4123
and ref($_[1][0][-2]) eq 'ARRAY'
4124
and $_[1][0][-2][STREAM_DIR_TYPE]==DIRECTIVE_TAG
4125
and $_[1][0][-2][STREAM_DIR_DATA] eq $1
4126
4127
# both building the same tag?
4128
and $_[1][0][-2][STREAM_DIR_DATA+1] eq $_[1][0][1][STREAM_DIR_DATA+1]
4129
)
4130
)
4131
{
4132
# remove the enclosing paragraph stuff - just return the contents (table / tag)
4133
shift(@{$_[1][0]}); # text paragraph opener
4134
pop(@{$_[1][0]}); # text paragraph trailer
4135
}
4136
4137
# pass (original or modified) data
4138
$_[1];
4139
}
4140
],
4141
[#Rule 15
4142
'original_paragraph', 1, undef
4143
],
4144
[#Rule 16
4145
'original_paragraph', 1, undef
4146
],
4147
[#Rule 17
4148
'original_paragraph', 1, undef
4149
],
4150
[#Rule 18
4151
'original_paragraph', 1, undef
4152
],
4153
[#Rule 19
4154
'original_paragraph', 1, undef
4155
],
4156
[#Rule 20
4157
'original_paragraph', 1, undef
4158
],
4159
[#Rule 21
4160
'original_paragraph', 1, undef
4161
],
4162
[#Rule 22
4163
'non_filterable_paragraph', 1, undef
4164
],
4165
[#Rule 23
4166
'non_filterable_paragraph', 1, undef
4167
],
4168
[#Rule 24
4169
'non_filterable_paragraph', 1, undef
4170
],
4171
[#Rule 25
4172
'restored_paragraph', 1, undef
4173
],
4174
[#Rule 26
4175
'@3-1', 0,
4176
sub
4177
#line 2003 "ppParser.yp"
4178
{
4179
# switch to headline mode
4180
_stateManager(STATE_HEADLINE);
4181
4182
# update headline level hints
4183
$flags{headlineLevel}=$_[1][0];
4184
4185
# trace, if necessary
4186
warn "[Trace] $sourceFile, line $_[1][1]: Headline (of level $_[1][0]) starts.\n" if $flags{trace} & TRACE_PARAGRAPHS;
4187
}
4188
],
4189
[#Rule 27
4190
'headline', 5,
4191
sub
4192
#line 2014 "ppParser.yp"
4193
{
4194
# back to default mode
4195
_stateManager(STATE_DEFAULT);
4196
4197
# trace, if necessary
4198
warn "[Trace] $sourceFile, line $_[5][1]: Headline completed.\n" if $flags{trace} & TRACE_PARAGRAPHS;
4199
4200
# remove trailing whitespaces (the final one represents the final newline)
4201
pop(@{$_[3][0]}) while @{$_[3][0]} and $_[3][0][-1]=~/^\s*$/;
4202
4203
# abbreviation declared?
4204
if ($_[4][0])
4205
{
4206
# remove trailing whitespaces which separated a shortcut directive from
4207
# the long headline title version, if a shortcut was specified
4208
$_[3][0][-1]=~s/\s+$//;
4209
# remove leading and trailing whitespaces from the shortcut
4210
$_[4][0]=~s/^\s+//;
4211
$_[4][0]=~s/\s+$//;
4212
}
4213
4214
# update related data
4215
@olistLevels=();
4216
4217
# update directive counter and the level hierarchy memory
4218
$#headlineIds=$flags{headlineLevel}-1;
4219
$headlineIds[$flags{headlineLevel}-1]=++$flags{headlinenr};
4220
4221
# prepare result (data part and shortcut string)
4222
my %hints=(
4223
nr => ++$directiveCounter,
4224
shortcut => $_[4][0],
4225
docstreams => {},
4226
);
4227
my $data=[
4228
# opener directive (including headline level)
4229
[\%hints, DIRECTIVE_HEADLINE, DIRECTIVE_START, $_[1][0]],
4230
# the list of enclosed literals
4231
@{$_[3][0]},
4232
# final directive (including headline level again)
4233
[\%hints, DIRECTIVE_HEADLINE, DIRECTIVE_COMPLETE, $_[1][0]]
4234
];
4235
4236
# update checksums (done here because hits need special handling)
4237
_updateChecksums($data, 'Headline_cache_hit');
4238
4239
# update pointer to the current docstream hash
4240
$flags{chapterDocstreams}=$hints{docstreams};
4241
4242
# reply data
4243
[$data, $_[5][1]];
4244
}
4245
],
4246
[#Rule 28
4247
'headline', 1,
4248
sub
4249
#line 2067 "ppParser.yp"
4250
{
4251
# update headline level hint
4252
$flags{headlineLevel}=$_[1][0][0][STREAM_DIR_DATA];
4253
4254
# reset chapter docstream hash and update the appropriate pointer
4255
$flags{chapterDocstreams}=$_[1][0][0][STREAM_DIR_HINTS]{docstreams}={};
4256
4257
# supply what you got unchanged
4258
$_[1];
4259
}
4260
],
4261
[#Rule 29
4262
'headline_level', 1,
4263
sub
4264
#line 2081 "ppParser.yp"
4265
{
4266
# switch to headline intro mode
4267
_stateManager(STATE_HEADLINE_LEVEL);
4268
4269
# start new counter and reply it
4270
[$flags{headlineLevelOffset}+1, $_[1][1]];
4271
}
4272
],
4273
[#Rule 30
4274
'headline_level', 2,
4275
sub
4276
#line 2089 "ppParser.yp"
4277
{
4278
# update counter and reply it
4279
[$_[1][0]+1, $_[1][1]];
4280
}
4281
],
4282
[#Rule 31
4283
'optional_headline_shortcut', 0,
4284
sub
4285
#line 2097 "ppParser.yp"
4286
{
4287
# nothing declared: supply an empty shortcut string
4288
['', $lineNrs{$inHandle}];
4289
}
4290
],
4291
[#Rule 32
4292
'optional_headline_shortcut', 2,
4293
sub
4294
#line 2102 "ppParser.yp"
4295
{
4296
# reply the shortcut string
4297
[join('', @{$_[2][0]}), $lineNrs{$inHandle}];
4298
}
4299
],
4300
[#Rule 33
4301
'@4-1', 0,
4302
sub
4303
#line 2110 "ppParser.yp"
4304
{
4305
# switch to condition mode
4306
_stateManager(STATE_CONDITION);
4307
4308
# trace, if necessary
4309
warn "[Trace] $sourceFile, line $_[1][1]: Condition paragraph starts.\n" if $flags{trace} & TRACE_PARAGRAPHS;
4310
}
4311
],
4312
[#Rule 34
4313
'condition', 4,
4314
sub
4315
#line 2118 "ppParser.yp"
4316
{
4317
# back to default mode
4318
_stateManager(STATE_DEFAULT);
4319
4320
# trace, if necessary
4321
warn "[Trace] $sourceFile, line $_[4][1]: condition completed.\n" if $flags{trace} & TRACE_PARAGRAPHS;
4322
4323
# The condition is written in Perl, anything passed really?
4324
# And does the caller want to evaluate the code?
4325
if (@{$_[3][0]} and $safeObject)
4326
{
4327
# trace, if necessary
4328
warn "[Trace] Evaluating condition ...\n" if $flags{trace} & TRACE_SEMANTIC;
4329
4330
# update active contents base data, if necessary
4331
if ($flags{activeBaseData})
4332
{
4333
no strict 'refs';
4334
${join('::', ref($safeObject) ? $safeObject->root : 'main', 'PerlPoint')}=dclone($flags{activeBaseData});
4335
}
4336
4337
# make the Perl code a string and evaluate it
4338
my $perl=join('', @{$_[3][0]});
4339
$^W=0;
4340
warn "[Trace] $sourceFile, line $_[3][1]: Evaluating condition code:\n\n$perl\n\n\n" if $flags{trace} & TRACE_ACTIVE;
4341
my $result=ref($safeObject) ? $safeObject->reval($perl) : eval(join(' ', '{package main; no strict;', $perl, '}'));
4342
$^W=1;
4343
4344
# check result
4345
if ($@)
4346
{_semerr($_[0], "$sourceFile, line $_[3][1]: condition code could not be evaluated: $@.");}
4347
else
4348
{
4349
# trace, if necessary
4350
warn "[Trace] Condition is ", (defined $result and $result) ? 'true, parsing continues' : 'false, parsing is temporarily suspended', ".\n" if $flags{trace} & TRACE_ACTIVE or $flags{trace} & TRACE_SEMANTIC;
4351
4352
# success - configure parser behaviour according to result
4353
$flags{skipInput}=1 unless (defined $result and $result);
4354
}
4355
}
4356
else
4357
{
4358
# trace, if necessary
4359
warn "[Trace] Condition is not evaluated because of disabled active contents.\n" if $flags{trace} & TRACE_SEMANTIC;
4360
}
4361
4362
# we have to supply something, but it should be nothing (note that this is a *paragraph*, so reply a *string*)
4363
['', $_[4][1]];
4364
}
4365
],
4366
[#Rule 35
4367
'list', 1, undef
4368
],
4369
[#Rule 36
4370
'list', 2,
4371
sub
4372
#line 2172 "ppParser.yp"
4373
{
4374
# update token list and reply it
4375
push(@{$_[1][0]}, @{$_[2][0]});
4376
[$_[1][0], $_[2][1]];
4377
}
4378
],
4379
[#Rule 37
4380
'list', 3,
4381
sub
4382
#line 2178 "ppParser.yp"
4383
{
4384
# update statistics, if necessary (shifters are not passed as standalone paragraphs, so ...)
4385
$statistics{$_[2][0][0][1]}++;
4386
4387
# add shift informations to related list parts: the predecessor
4388
# gets informations about a following shift, the successor about
4389
# a predecessing shift
4390
@{$_[1][0][-1]}[STREAM_DIR_DATA+3, STREAM_DIR_DATA+4]
4391
=@{$_[3][0][ 0]}[STREAM_DIR_DATA+1, STREAM_DIR_DATA+2]
4392
=@{$_[2][0][ 0]}[STREAM_DIR_TYPE, STREAM_DIR_DATA];
4393
4394
# update token list and reply it
4395
push(@{$_[1][0]}, @{$_[2][0]}, @{$_[3][0]});
4396
[$_[1][0], $_[3][1]];
4397
}
4398
],
4399
[#Rule 38
4400
'list_part', 1,
4401
sub
4402
#line 2197 "ppParser.yp"
4403
{
4404
# the first point may start by a certain number, check this
4405
my $start=(defined $_[1][0][0][STREAM_DIR_DATA] and $_[1][0][0][STREAM_DIR_DATA]>1) ? $_[1][0][0][STREAM_DIR_DATA] : 1;
4406
4407
# embed the points into list directives
4408
my %hints=(nr=>++$directiveCounter);
4409
[
4410
[
4411
# opener directive
4412
[\%hints, DIRECTIVE_OLIST, DIRECTIVE_START, $start, (0) x 4],
4413
# the list of enclosed literals
4414
@{$_[1][0]},
4415
# final directive
4416
[\%hints, DIRECTIVE_OLIST, DIRECTIVE_COMPLETE, $start, (0) x 4]
4417
],
4418
$_[1][1]
4419
];
4420
}
4421
],
4422
[#Rule 39
4423
'list_part', 1,
4424
sub
4425
#line 2216 "ppParser.yp"
4426
{
4427
# reset ordered list flag
4428
$flags{olist}=0;
4429
4430
# embed the points into list directives
4431
my %hints=(nr=>++$directiveCounter);
4432
[
4433
[
4434
# opener directive
4435
[\%hints, DIRECTIVE_ULIST, DIRECTIVE_START, 0, (0) x 4],
4436
# the list of enclosed literals
4437
@{$_[1][0]},
4438
# final directive
4439
[\%hints, DIRECTIVE_ULIST, DIRECTIVE_COMPLETE, 0, (0) x 4]
4440
],
4441
$_[1][1]
4442
];
4443
}
4444
],
4445
[#Rule 40
4446
'list_part', 1,
4447
sub
4448
#line 2235 "ppParser.yp"
4449
{
4450
# reset ordered list flag
4451
$flags{olist}=0;
4452
4453
# embed the points into list directives
4454
my %hints=(nr=>++$directiveCounter);
4455
[
4456
[
4457
# opener directive
4458
[\%hints, DIRECTIVE_DLIST, DIRECTIVE_START, 0, (0) x 4],
4459
# the list of enclosed literals
4460
@{$_[1][0]},
4461
# final directive
4462
[\%hints, DIRECTIVE_DLIST, DIRECTIVE_COMPLETE, 0, (0) x 4]
4463
],
4464
$_[1][1]
4465
];
4466
}
4467
],
4468
[#Rule 41
4469
'olist', 1, undef
4470
],
4471
[#Rule 42
4472
'olist', 2,
4473
sub
4474
#line 2258 "ppParser.yp"
4475
{
4476
# update token list and reply it
4477
push(@{$_[1][0]}, @{$_[2][0]});
4478
[$_[1][0], $_[2][1]];
4479
}
4480
],
4481
[#Rule 43
4482
'ulist', 1, undef
4483
],
4484
[#Rule 44
4485
'ulist', 2,
4486
sub
4487
#line 2268 "ppParser.yp"
4488
{
4489
# update token list and reply it
4490
push(@{$_[1][0]}, @{$_[2][0]});
4491
[$_[1][0], $_[2][1]];
4492
}
4493
],
4494
[#Rule 45
4495
'dlist', 1, undef
4496
],
4497
[#Rule 46
4498
'dlist', 2,
4499
sub
4500
#line 2278 "ppParser.yp"
4501
{
4502
# update token list and reply it
4503
push(@{$_[1][0]}, @{$_[2][0]});
4504
[$_[1][0], $_[2][1]];
4505
}
4506
],
4507
[#Rule 47
4508
'@5-1', 0,
4509
sub
4510
#line 2287 "ppParser.yp"
4511
{
4512
# switch to opoint mode
4513
_stateManager(STATE_OPOINT);
4514
4515
# trace, if necessary
4516
warn "[Trace] $sourceFile, line $_[1][1]: Ordered list point starts.\n" if $flags{trace} & TRACE_PARAGRAPHS;
4517
}
4518
],
4519
[#Rule 48
4520
'opoint', 3,
4521
sub
4522
#line 2295 "ppParser.yp"
4523
{
4524
# update statistics (list points are not passed as standalone paragraphs, so ...)
4525
$statistics{&DIRECTIVE_OPOINT}++;
4526
4527
# trace, if necessary
4528
warn "[Trace] $sourceFile, line $_[3][1]: Ordered list point completed.\n" if $flags{trace} & TRACE_PARAGRAPHS;
4529
4530
# remove leading whitespaces from point text (it separated number wildcard and literal text part)
4531
splice(@{$_[3][0]}, 1, 1) while not ref($_[3][0][1]) and $_[3][0][1]=~/^\s*$/;
4532
4533
# reply data (they are already well prepared except that they are marked as text)
4534
$_[3][0][0][STREAM_DIR_TYPE]=$_[3][0][-1][STREAM_DIR_TYPE]=&DIRECTIVE_OPOINT;
4535
4536
# update list level hints as necessary
4537
$olistLevels[0]=(($flags{olist} or $_[1][0]) and @olistLevels) ? $olistLevels[0]+1 : 1;
4538
4539
# add a level hint, if necessary
4540
if ($_[1][0] and not $flags{olist} and $olistLevels[0]>1)
4541
{
4542
push(@{$_[3][0][0]}, $olistLevels[0]);
4543
push(@{$_[3][0][-1]}, $olistLevels[0]);
4544
}
4545
4546
# update ordered list flag
4547
$flags{olist}=1;
4548
4549
# update checksums, if possible
4550
$flags{checksummed}=0 unless $flags{virtualParagraphStart};
4551
_updateChecksums($_[3][0], 'Opoint_cache_hit');
4552
4553
# supply result
4554
$_[3];
4555
}
4556
],
4557
[#Rule 49
4558
'opoint', 1,
4559
sub
4560
#line 2329 "ppParser.yp"
4561
{
4562
# update list level hints as necessary
4563
$olistLevels[0]=($flags{olist} and @olistLevels) ? $olistLevels[0]+1 : 1;
4564
4565
# update continued list points
4566
$_[1][0][0][STREAM_DIR_DATA]=$olistLevels[0] if @{$_[1][0][0]}>3;
4567
4568
# update ordered list flag
4569
$flags{olist}=1;
4570
4571
# supply updated stream snippet
4572
$_[1];
4573
}
4574
],
4575
[#Rule 50
4576
'opoint_opener', 1,
4577
sub
4578
#line 2347 "ppParser.yp"
4579
{[0, $_[1][1]];}
4580
],
4581
[#Rule 51
4582
'opoint_opener', 2,
4583
sub
4584
#line 2349 "ppParser.yp"
4585
{[1, $_[1][1]];}
4586
],
4587
[#Rule 52
4588
'@6-1', 0,
4589
sub
4590
#line 2354 "ppParser.yp"
4591
{
4592
# switch to upoint mode
4593
_stateManager(STATE_UPOINT);
4594
4595
# trace, if necessary
4596
warn "[Trace] $sourceFile, line $_[1][1]: Unordered list point starts.\n" if $flags{trace} & TRACE_PARAGRAPHS;
4597
}
4598
],
4599
[#Rule 53
4600
'upoint', 3,
4601
sub
4602
#line 2362 "ppParser.yp"
4603
{
4604
# update statistics (list points are not passed as standalone paragraphs, so ...)
4605
$statistics{&DIRECTIVE_UPOINT}++;
4606
4607
# trace, if necessary
4608
warn "[Trace] $sourceFile, line $_[3][1]: Unordered list point completed.\n" if $flags{trace} & TRACE_PARAGRAPHS;
4609
4610
# remove leading whitespaces from point text (it separated bullet and literal text part)
4611
splice(@{$_[3][0]}, 1, 1) while not ref($_[3][0][1]) and $_[3][0][1]=~/^\s*$/;
4612
4613
# remove trailing whitespaces from point text (it represents the final newline character)
4614
splice(@{$_[3][0]}, -2, 1) while not ref($_[3][0][-2]) and $_[3][0][-2]=~/^\s*$/;
4615
4616
# reply data (they are already well prepared except that they are marked as text)
4617
$_[3][0][0][STREAM_DIR_TYPE]=$_[3][0][-1][STREAM_DIR_TYPE]=&DIRECTIVE_UPOINT;
4618
4619
# update checksums, if possible
4620
$flags{checksummed}=0 unless $flags{virtualParagraphStart};
4621
_updateChecksums($_[3][0], 'Upoint_cache_hit');
4622
4623
# supply result
4624
$_[3];
4625
}
4626
],
4627
[#Rule 54
4628
'upoint', 1, undef
4629
],
4630
[#Rule 55
4631
'@7-1', 0,
4632
sub
4633
#line 2391 "ppParser.yp"
4634
{
4635
}
4636
],
4637
[#Rule 56
4638
'dpoint', 3,
4639
sub
4640
#line 2394 "ppParser.yp"
4641
{
4642
# update statistics (list points are not passed as standalone paragraphs, so ...)
4643
$statistics{&DIRECTIVE_DPOINT}++;
4644
4645
# trace, if necessary
4646
warn "[Trace] $sourceFile, line $_[3][1]: Definition list point completed.\n" if $flags{trace} & TRACE_PARAGRAPHS;
4647
4648
# remove leading whitespaces from point text (it separated point introduction and literal text part)
4649
splice(@{$_[3][0]}, 1, 1) while not ref($_[3][0][1]) and $_[3][0][1]=~/^\s*$/;
4650
4651
# reply data (they are already well prepared except that they are marked as text, and that the definition item stream needs to be added)
4652
my ($hints1, $hints2, $hints3)=({nr=>++$directiveCounter}, {nr=>++$directiveCounter}, {nr=>++$directiveCounter});
4653
$_[3][0][0]=[$hints1, DIRECTIVE_DPOINT, DIRECTIVE_START];
4654
$_[3][0][-1]=[$hints1, DIRECTIVE_DPOINT, DIRECTIVE_COMPLETE];
4655
4656
# insert the definition item stream and an envelope for the explanation part
4657
splice(@{$_[3][0]}, 1, 0,
4658
[$hints2, DIRECTIVE_DPOINT_ITEM, DIRECTIVE_START],
4659
@{$_[1][0]},
4660
[$hints2, DIRECTIVE_DPOINT_ITEM, DIRECTIVE_COMPLETE],
4661
[$hints3, DIRECTIVE_DPOINT_TEXT, DIRECTIVE_START],
4662
);
4663
splice(@{$_[3][0]}, -1, 0, [$hints3, DIRECTIVE_DPOINT_TEXT, DIRECTIVE_COMPLETE]);
4664
4665
# update checksums, if possible
4666
$flags{checksummed}=0 unless $flags{virtualParagraphStart};
4667
_updateChecksums($_[3][0], 'Dpoint_cache_hit');
4668
4669
# supply the result
4670
$_[3];
4671
}
4672
],
4673
[#Rule 57
4674
'dpoint', 1, undef
4675
],
4676
[#Rule 58
4677
'@8-1', 0,
4678
sub
4679
#line 2431 "ppParser.yp"
4680
{
4681
# switch to dlist item mode
4682
_stateManager(STATE_DPOINT_ITEM);
4683
4684
# trace, if necessary
4685
warn "[Trace] $sourceFile, line $_[1][1]: Definition list point starts.\n" if $flags{trace} & TRACE_PARAGRAPHS;
4686
}
4687
],
4688
[#Rule 59
4689
'dlist_opener', 4,
4690
sub
4691
#line 2439 "ppParser.yp"
4692
{
4693
# switch to dlist body mode
4694
_stateManager(STATE_DPOINT);
4695
4696
# simply pass the elements
4697
[$_[3][0], $_[4][1]];
4698
}
4699
],
4700
[#Rule 60
4701
'compound_block', 1, undef
4702
],
4703
[#Rule 61
4704
'compound_block', 2,
4705
sub
4706
#line 2452 "ppParser.yp"
4707
{
4708
# this is tricky - to combine both blocks, we have to remove the already
4709
# embedded stop/start directives and to supply the ...
4710
[
4711
[
4712
# ... original collection WITHOUT the final directive ...
4713
@{$_[1][0]}[0..$#{$_[1][0]}-1],
4714
# insert two additional newline characters (restoring the original empty line)
4715
"\n\n",
4716
# ... combined with the new block, except of its INTRO directive
4717
@{$_[2][0]}[1..$#{$_[2][0]}],
4718
],
4719
$_[2][1]
4720
];
4721
}
4722
],
4723
[#Rule 62
4724
'compound_block', 3,
4725
sub
4726
#line 2468 "ppParser.yp"
4727
{
4728
# update statistics (for the first part which is completed by the intermediate flag paragraph)
4729
$statistics{&DIRECTIVE_BLOCK}++;
4730
4731
# this is simply a list of both blocks
4732
[
4733
[
4734
# original collection
4735
@{$_[1][0]},
4736
# ... followed by the new block
4737
@{$_[3][0]},
4738
],
4739
$_[3][1]
4740
];
4741
}
4742
],
4743
[#Rule 63
4744
'@9-1', 0,
4745
sub
4746
#line 2487 "ppParser.yp"
4747
{
4748
# switch to control mode
4749
_stateManager(STATE_CONTROL);
4750
4751
# trace, if necessary
4752
warn "[Trace] $sourceFile, line $_[1][1]: New block flag starts.\n" if $flags{trace} & TRACE_PARAGRAPHS;
4753
}
4754
],
4755
[#Rule 64
4756
'block_flagnew', 3,
4757
sub
4758
#line 2495 "ppParser.yp"
4759
{
4760
# back to default mode
4761
_stateManager(STATE_DEFAULT);
4762
4763
# trace, if necessary
4764
warn "[Trace] $sourceFile, line $_[1][1]: New block flag completed.\n" if $flags{trace} & TRACE_PARAGRAPHS;
4765
4766
# reply data (these are dummies because block connectors are not made part of the output stream)
4767
$_[3];
4768
}
4769
],
4770
[#Rule 65
4771
'@10-1', 0,
4772
sub
4773
#line 2509 "ppParser.yp"
4774
{
4775
# switch to block mode
4776
_stateManager(STATE_BLOCK);
4777
4778
# trace, if necessary
4779
warn "[Trace] $sourceFile, line $_[1][1]: Block starts.\n" if $flags{trace} & TRACE_PARAGRAPHS;
4780
}
4781
],
4782
[#Rule 66
4783
'block', 3,
4784
sub
4785
#line 2517 "ppParser.yp"
4786
{
4787
# trace, if necessary
4788
warn "[Trace] $sourceFile, line $_[3][1]: Block completed.\n" if $flags{trace} & TRACE_PARAGRAPHS;
4789
4790
# reply data (they are almost perfect except that they are marked as text,
4791
# and that the initial spaces have to be inserted, and that a trailing newline
4792
# has to be removed)
4793
$_[3][0][0][STREAM_DIR_TYPE]=$_[3][0][-1][STREAM_DIR_TYPE]=DIRECTIVE_BLOCK;
4794
splice(@{$_[3][0]}, 1, 0, $_[1][0]);
4795
# remove the final newline made from the last carriage return, if any
4796
splice(@{$_[3][0]}, -2, 1) if @{$_[3][0]}>2 and defined $_[3][0][-2] and $_[3][0][-2] eq "\n";
4797
4798
# update checksums, if possible
4799
$flags{checksummed}=0 unless $flags{virtualParagraphStart};
4800
_updateChecksums($_[3][0], 'Block_cache_hit');
4801
4802
# supply result
4803
$_[3];
4804
}
4805
],
4806
[#Rule 67
4807
'block', 1, undef
4808
],
4809
[#Rule 68
4810
'optionally_dotted_text', 1, undef
4811
],
4812
[#Rule 69
4813
'optionally_dotted_text', 1, undef
4814
],
4815
[#Rule 70
4816
'@11-1', 0,
4817
sub
4818
#line 2546 "ppParser.yp"
4819
{
4820
# enter text mode - unless we are in a block (or point (which already set this mode itself))
4821
unless ( $parserState==STATE_BLOCK
4822
or $parserState==STATE_UPOINT
4823
or $parserState==STATE_OPOINT
4824
or $parserState==STATE_DPOINT
4825
or $parserState==STATE_DPOINT_ITEM
4826
or $parserState==STATE_DEFINITION
4827
or $parserState==STATE_TEXT
4828
)
4829
{
4830
# switch to new mode
4831
_stateManager(STATE_TEXT);
4832
4833
# trace, if necessary
4834
warn "[Trace] $sourceFile, line $_[1][1]: Text starts.\n" if $flags{trace} & TRACE_PARAGRAPHS;
4835
}
4836
}
4837
],
4838
[#Rule 71
4839
'text', 4,
4840
sub
4841
#line 2566 "ppParser.yp"
4842
{
4843
# trace, if necessary
4844
warn "[Trace] $sourceFile, line $_[4][1]: Text completed.\n" unless not $flags{trace} & TRACE_PARAGRAPHS
4845
or $parserState==STATE_BLOCK
4846
or $parserState==STATE_UPOINT
4847
or $parserState==STATE_OPOINT
4848
or $parserState==STATE_DPOINT
4849
or $parserState==STATE_DPOINT_ITEM;
4850
4851
# back to default mode
4852
_stateManager(STATE_DEFAULT);
4853
4854
# remove the final EOL literal, if any
4855
pop(@{$_[3][0]}) if defined $_[3][0][-1] and $_[3][0][-1] eq 'EOL';
4856
4857
# remove the final whitespace string made from the last carriage return, if any
4858
pop(@{$_[3][0]}) if defined $_[3][0][-1] and $_[3][0][-1] eq ' ';
4859
4860
# reply data, if any
4861
if ((@{$_[1][0]} and $_[1][0][0]) or @{$_[3][0]})
4862
{
4863
my %hints=(nr=>++$directiveCounter);
4864
[
4865
[
4866
# opener directive
4867
[\%hints, DIRECTIVE_TEXT, DIRECTIVE_START],
4868
# the list of enclosed literals
4869
@{$_[1][0]}, @{$_[3][0]},
4870
# final directive
4871
[\%hints, DIRECTIVE_TEXT, DIRECTIVE_COMPLETE],
4872
],
4873
$_[4][1],
4874
];
4875
}
4876
else
4877
{
4878
# reply nothing real
4879
[[()], $_[4][1]];
4880
}
4881
}
4882
],
4883
[#Rule 72
4884
'@12-1', 0,
4885
sub
4886
#line 2610 "ppParser.yp"
4887
{
4888
# switch to new mode (to stop special handling of dots)
4889
_stateManager(STATE_TEXT);
4890
}
4891
],
4892
[#Rule 73
4893
'dotted_text', 3,
4894
sub
4895
#line 2615 "ppParser.yp"
4896
{
4897
# supply the text
4898
$_[3];
4899
}
4900
],
4901
[#Rule 74
4902
'@13-1', 0,
4903
sub
4904
#line 2623 "ppParser.yp"
4905
{
4906
# switch to verbatim mode
4907
_stateManager(STATE_VERBATIM);
4908
4909
# trace, if necessary
4910
warn "[Trace] $sourceFile, line $_[1][1]: Verbatim block starts.\n" if $flags{trace} & TRACE_PARAGRAPHS;
4911
4912
# check close hint: should be different from "1"
4913
_semerr($_[0], "A heredoc close hint should be different from \"1\".") if $_[1][0] eq '1';
4914
4915
# store close hint
4916
$specials{heredoc}=$_[1][0];
4917
}
4918
],
4919
[#Rule 75
4920
'verbatim', 4,
4921
sub
4922
#line 2638 "ppParser.yp"
4923
{
4924
# trace, if necessary
4925
warn "[Trace] $sourceFile, line $_[4][1]: Verbatim block completed.\n" if $flags{trace} & TRACE_PARAGRAPHS;
4926
4927
# back to default mode
4928
_stateManager(STATE_DEFAULT);
4929
4930
# delete the initial newline (which follows the opener but is no part of the block)
4931
shift(@{$_[3][0]});
4932
4933
# reply data
4934
my %hints=(nr=>++$directiveCounter);
4935
[
4936
[
4937
# opener directive
4938
[\%hints, DIRECTIVE_VERBATIM, DIRECTIVE_START],
4939
# the list of enclosed literals
4940
@{$_[3][0]},
4941
# final directive
4942
[\%hints, DIRECTIVE_VERBATIM, DIRECTIVE_COMPLETE]
4943
],
4944
$_[4][1]
4945
];
4946
}
4947
],
4948
[#Rule 76
4949
'@14-2', 0,
4950
sub
4951
#line 2666 "ppParser.yp"
4952
{
4953
# switch to text mode to allow *all* characters starting a variable value!
4954
_stateManager(STATE_TEXT);
4955
4956
# trace, if necessary
4957
warn "[Trace] $sourceFile, line $_[1][1]: Variable assignment starts.\n" if $flags{trace} & TRACE_PARAGRAPHS;
4958
}
4959
],
4960
[#Rule 77
4961
'variable_assignment', 4,
4962
sub
4963
#line 2674 "ppParser.yp"
4964
{
4965
# remove text directives and the final space (made from the final EOL)
4966
shift(@{$_[4][0]});
4967
pop(@{$_[4][0]});
4968
4969
# make the text contents a string and store it
4970
$variables{$_[1][0]}=join('', @{$_[4][0]});
4971
4972
# the variable might have been reset
4973
delete($variables{$_[1][0]}) if $variables{$_[1][0]}=~/^\s*$/;
4974
4975
# update variable checksum
4976
$varChecksum=sha1_base64(nfreeze(\%variables));
4977
4978
# propagate the setting to the stream, if necessary
4979
if ($flags{var2stream})
4980
{
4981
push(@{$resultStreamRef->[STREAM_TOKENS]}, [{}, DIRECTIVE_VARSET, DIRECTIVE_START, {var=>$_[1][0], value=>$variables{$_[1][0]}}]);
4982
4983
# update tag finish memory by the way
4984
_updateTagFinishMem(scalar(@{$resultStreamRef->[STREAM_TOKENS]}));
4985
}
4986
4987
# make the new variable setting available to embedded Perl code, if necessary
4988
if ($safeObject)
4989
{
4990
no strict 'refs';
4991
${join('::', ref($safeObject) ? $safeObject->root : 'main', $_[1][0])}=$variables{$_[1][0]};
4992
}
4993
4994
# trace, if necessary
4995
warn "[Trace] $sourceFile, line $_[4][1]: Variable assignment: \$$_[1][0]=$variables{$_[1][0]}.\n" if $flags{trace} & TRACE_PARAGRAPHS;
4996
4997
# flag this paragraph as internal
4998
['', $_[4][1]];
4999
}
5000
],
5001
[#Rule 78
5002
'@15-2', 0,
5003
sub
5004
#line 2714 "ppParser.yp"
5005
{
5006
# switch to comment mode
5007
_stateManager(STATE_COMMENT);
5008
5009
# trace, if necessary
5010
warn "[Trace] $sourceFile, line $_[1][1]: Comment starts.\n" if $flags{trace} & TRACE_PARAGRAPHS;
5011
}
5012
],
5013
[#Rule 79
5014
'comment', 5,
5015
sub
5016
#line 2722 "ppParser.yp"
5017
{
5018
# back to default mode
5019
_stateManager(STATE_DEFAULT);
5020
5021
# trace, if necessary
5022
warn "[Trace] $sourceFile, line $_[5][1]: Comment completed.\n" if $flags{trace} & TRACE_PARAGRAPHS;
5023
5024
# reply data, if necessary
5025
my %hints=(nr=>++$directiveCounter);
5026
$flags{skipcomments} ? [[()], $_[5][1]]
5027
: [
5028
[
5029
# opener directive
5030
[\%hints, DIRECTIVE_COMMENT, DIRECTIVE_START],
5031
# the list of enclosed literals
5032
@{$_[4][0]},
5033
# final directive
5034
[\%hints, DIRECTIVE_COMMENT, DIRECTIVE_COMPLETE]
5035
],
5036
$_[5][1]
5037
];
5038
}
5039
],
5040
[#Rule 80
5041
'@16-1', 0,
5042
sub
5043
#line 2748 "ppParser.yp"
5044
{
5045
# no mode switch necessary
5046
5047
# trace, if necessary
5048
warn "[Trace] $sourceFile, line $_[1][1]: Stream entry point starts.\n" if $flags{trace} & TRACE_PARAGRAPHS;
5049
}
5050
],
5051
[#Rule 81
5052
'dstream_entrypoint', 4,
5053
sub
5054
#line 2755 "ppParser.yp"
5055
{
5056
# no mode switch necessary
5057
5058
# trace, if necessary
5059
warn "[Trace] $sourceFile, line $_[5][1]: Stream entry point completed.\n" if $flags{trace} & TRACE_PARAGRAPHS;
5060
5061
# deactivate caching
5062
$flags{checksummed}=0;
5063
5064
# reply data as wished
5065
my $streamTitle=join('', @{$_[3][0]});
5066
unless (
5067
$flags{docstreaming}==DSTREAM_IGNORE
5068
or (
5069
$flags{docstreams2skip}
5070
and exists $flags{docstreams2skip}{$streamTitle}
5071
)
5072
)
5073
{
5074
# store stream title (both globally and locally)
5075
$resultStreamRef->[STREAM_DOCSTREAMS]{$streamTitle}=$flags{chapterDocstreams}{$streamTitle}=undef;
5076
5077
# special handling requested?
5078
if ($flags{docstreaming}==DSTREAM_HEADLINES)
5079
{
5080
# make this docstream entry point a headline
5081
# one level below the last real headline level
5082
my %hints=(nr=>++$directiveCounter, shortcut=>'');
5083
[
5084
[
5085
# opener directive (including headline level)
5086
[\%hints, DIRECTIVE_HEADLINE, DIRECTIVE_START, $flags{headlineLevel}+1],
5087
# the stream title becomes the "headline"
5088
$streamTitle,
5089
# final directive (including headline level again)
5090
[\%hints, DIRECTIVE_HEADLINE, DIRECTIVE_COMPLETE, $flags{headlineLevel}+1]
5091
],
5092
$_[5][1]
5093
];
5094
}
5095
# default handling
5096
else
5097
{
5098
my %hints=(nr=>++$directiveCounter);
5099
[
5100
[
5101
# directives
5102
[\%hints, DIRECTIVE_DSTREAM_ENTRYPOINT, DIRECTIVE_START, $streamTitle],
5103
],
5104
$_[5][1]
5105
];
5106
}
5107
}
5108
else
5109
{
5110
# configure parser to ignore eveything till the next stream entry point or headline
5111
# ... unless this is the *main* stream
5112
$flags{skipInput}=2 unless $streamTitle eq 'main';
5113
5114
# we have to supply something, but it should be nothing (note that this is a *paragraph*, so reply a *string*)
5115
['', $_[5][1]];
5116
}
5117
}
5118
],
5119
[#Rule 82
5120
'@17-1', 0,
5121
sub
5122
#line 2822 "ppParser.yp"
5123
{
5124
# temporarily activate number detection
5125
push(@specialStack, $specials{number});
5126
$specials{number}=1;
5127
}
5128
],
5129
[#Rule 83
5130
'@18-3', 0,
5131
sub
5132
#line 2828 "ppParser.yp"
5133
{
5134
# restore previous number detection mode
5135
$specials{number}=pop(@specialStack);
5136
5137
# switch to control mode
5138
_stateManager(STATE_CONTROL);
5139
5140
# trace, if necessary
5141
warn "[Trace] $sourceFile, line $_[3][1]: List shift ", $_[1][0]==LIST_SHIFT_RIGHT ? 'right' : 'left', " starts.\n" if $flags{trace} & TRACE_PARAGRAPHS;
5142
}
5143
],
5144
[#Rule 84
5145
'list_shift', 5,
5146
sub
5147
#line 2839 "ppParser.yp"
5148
{
5149
# back to default mode
5150
_stateManager(STATE_DEFAULT);
5151
5152
# trace, if necessary
5153
warn "[Trace] $sourceFile, line $_[5][1]: List shift ", $_[1][0]==LIST_SHIFT_RIGHT ? 'right' : 'left', " completed.\n" if $flags{trace} & TRACE_PARAGRAPHS;
5154
5155
# update related data
5156
if ($_[1][0]==LIST_SHIFT_RIGHT)
5157
{unshift(@olistLevels, 0) for (1..(defined $_[3][0] ? $_[3][0] : 1));}
5158
else
5159
{shift(@olistLevels) for (1..(defined $_[3][0] ? $_[3][0] : 1));}
5160
5161
# reset ordered list flag
5162
$flags{olist}=0;
5163
5164
# reply data
5165
[
5166
[
5167
# opener directive (no explicit closing)
5168
[{}, $_[1][0]==LIST_SHIFT_RIGHT ? DIRECTIVE_LIST_RSHIFT : DIRECTIVE_LIST_LSHIFT, DIRECTIVE_START, defined $_[3][0] ? $_[3][0] : 1],
5169
],
5170
$_[5][1]
5171
];
5172
}
5173
],
5174
[#Rule 85
5175
'list_shifter', 1,
5176
sub
5177
#line 2868 "ppParser.yp"
5178
{
5179
# reply a flag
5180
[LIST_SHIFT_RIGHT, $_[1][1]];
5181
}
5182
],
5183
[#Rule 86
5184
'list_shifter', 1,
5185
sub
5186
#line 2873 "ppParser.yp"
5187
{
5188
# reply a flag
5189
[LIST_SHIFT_LEFT, $_[1][1]];
5190
}
5191
],
5192
[#Rule 87
5193
'optional_literals', 0,
5194
sub
5195
#line 2881 "ppParser.yp"
5196
{
5197
# start a new, empty list and reply it
5198
[[], $lineNrs{$inHandle}];
5199
}
5200
],
5201
[#Rule 88
5202
'optional_literals', 1, undef
5203
],
5204
[#Rule 89
5205
'literals', 1, undef
5206
],
5207
[#Rule 90
5208
'literals', 2,
5209
sub
5210
#line 2891 "ppParser.yp"
5211
{
5212
# update token list and reply it
5213
push(@{$_[1][0]}, @{$_[2][0]});
5214
[$_[1][0], $_[2][1]];
5215
}
5216
],
5217
[#Rule 91
5218
'optional_literals_and_empty_lines', 0,
5219
sub
5220
#line 2900 "ppParser.yp"
5221
{
5222
# start a new, empty list and reply it
5223
[[], $lineNrs{$inHandle}];
5224
}
5225
],
5226
[#Rule 92
5227
'optional_literals_and_empty_lines', 1, undef
5228
],
5229
[#Rule 93
5230
'literals_and_empty_lines', 1, undef
5231
],
5232
[#Rule 94
5233
'literals_and_empty_lines', 2,
5234
sub
5235
#line 2910 "ppParser.yp"
5236
{
5237
# update token list and reply it
5238
push(@{$_[1][0]}, @{$_[2][0]});
5239
[$_[1][0], $_[2][1]];
5240
}
5241
],
5242
[#Rule 95
5243
'literal_or_empty_line', 1, undef
5244
],
5245
[#Rule 96
5246
'literal_or_empty_line', 1,
5247
sub
5248
#line 2920 "ppParser.yp"
5249
{
5250
# start a new token list and reply it
5251
[[$_[1][0]], $_[1][1]];
5252
}
5253
],
5254
[#Rule 97
5255
'literal', 1, undef
5256
],
5257
[#Rule 98
5258
'literal', 1,
5259
sub
5260
#line 2929 "ppParser.yp"
5261
{
5262
# start a new token list and reply it
5263
[[$_[1][0]], $_[1][1]];
5264
}
5265
],
5266
[#Rule 99
5267
'optional_basics', 0,
5268
sub
5269
#line 2937 "ppParser.yp"
5270
{
5271
# start a new, empty list and reply it
5272
[[], $lineNrs{$inHandle}];
5273
}
5274
],
5275
[#Rule 100
5276
'optional_basics', 1, undef
5277
],
5278
[#Rule 101
5279
'basics', 1, undef
5280
],
5281
[#Rule 102
5282
'basics', 2,
5283
sub
5284
#line 2947 "ppParser.yp"
5285
{
5286
# update token list and reply it
5287
push(@{$_[1][0]}, @{$_[2][0]});
5288
[$_[1][0], $_[2][1]];
5289
}
5290
],
5291
[#Rule 103
5292
'basic', 1, undef
5293
],
5294
[#Rule 104
5295
'basic', 1, undef
5296
],
5297
[#Rule 105
5298
'basic', 1, undef
5299
],
5300
[#Rule 106
5301
'elements', 1, undef
5302
],
5303
[#Rule 107
5304
'elements', 2,
5305
sub
5306
#line 2965 "ppParser.yp"
5307
{
5308
# update token list and reply it
5309
push(@{$_[1][0]}, @{$_[2][0]});
5310
[$_[1][0], $_[2][1]];
5311
}
5312
],
5313
[#Rule 108
5314
'element', 1,
5315
sub
5316
#line 2975 "ppParser.yp"
5317
{
5318
# start a new token list and reply it
5319
[[$_[1][0]], $_[1][1]];
5320
}
5321
],
5322
[#Rule 109
5323
'element', 1,
5324
sub
5325
#line 2980 "ppParser.yp"
5326
{
5327
# start a new token list and reply it
5328
[[$_[1][0]], $_[1][1]];
5329
}
5330
],
5331
[#Rule 110
5332
'element', 1,
5333
sub
5334
#line 2985 "ppParser.yp"
5335
{
5336
# flag that this paragraph uses variables (a cache hit will only be useful if variable settings will be unchanged)
5337
$flags{checksummed}[4]=1 unless exists $flags{checksummed} and not $flags{checksummed};
5338
5339
# start a new token list and reply it
5340
[[exists $variables{$_[1][0]} ? $variables{$_[1][0]} : join('', '$', $_[1][0])], $_[1][1]];
5341
}
5342
],
5343
[#Rule 111
5344
'element', 1,
5345
sub
5346
#line 2993 "ppParser.yp"
5347
{
5348
# flag that this paragraph uses variables (a cache hit will only be useful if variable settings will be unchanged)
5349
$flags{checksummed}[4]=1 unless exists $flags{checksummed} and not $flags{checksummed};
5350
5351
# start a new token list and reply it
5352
[[exists $variables{$_[1][0]} ? $variables{$_[1][0]} : join('', '$', "{$_[1][0]}")], $_[1][1]];
5353
}
5354
],
5355
[#Rule 112
5356
'element', 1,
5357
sub
5358
#line 3001 "ppParser.yp"
5359
{
5360
# start a new token list and reply it
5361
# (the passed stream is already a reference)
5362
[$_[1][0], $_[1][1]];
5363
}
5364
],
5365
[#Rule 113
5366
'element', 1, undef
5367
],
5368
[#Rule 114
5369
'element', 1, undef
5370
],
5371
[#Rule 115
5372
'element', 1, undef
5373
],
5374
[#Rule 116
5375
'optional_number', 0,
5376
sub
5377
#line 3014 "ppParser.yp"
5378
{[undef, $lineNrs{$inHandle}];}
5379
],
5380
[#Rule 117
5381
'optional_number', 1, undef
5382
],
5383
[#Rule 118
5384
'words', 1,
5385
sub
5386
#line 3021 "ppParser.yp"
5387
{
5388
# start a new token list and reply it
5389
[[$_[1][0]], $_[1][1]];
5390
}
5391
],
5392
[#Rule 119
5393
'words', 2,
5394
sub
5395
#line 3026 "ppParser.yp"
5396
{
5397
# update token list and reply it
5398
push(@{$_[1][0]}, $_[2][0]);
5399
[$_[1][0], $_[2][1]];
5400
}
5401
],
5402
[#Rule 120
5403
'words_or_spaces', 1,
5404
sub
5405
#line 3035 "ppParser.yp"
5406
{
5407
# start a new token list and reply it
5408
[[$_[1][0]], $_[1][1]];
5409
}
5410
],
5411
[#Rule 121
5412
'words_or_spaces', 2,
5413
sub
5414
#line 3040 "ppParser.yp"
5415
{
5416
# update token list and reply it
5417
push(@{$_[1][0]}, $_[2][0]);
5418
[$_[1][0], $_[2][1]];
5419
}
5420
],
5421
[#Rule 122
5422
'word_or_space', 1, undef
5423
],
5424
[#Rule 123
5425
'word_or_space', 1, undef
5426
],
5427
[#Rule 124
5428
'@19-1', 0,
5429
sub
5430
#line 3055 "ppParser.yp"
5431
{
5432
# trace, if necessary
5433
warn "[Trace] $sourceFile, line $_[1][1]: Tag $_[1][0] starts.\n" if $flags{trace} & TRACE_PARAGRAPHS;
5434
5435
# temporarily activate special "<" *as necessary*
5436
my $possible= (exists $macros{$_[1][0]} and $macros{$_[1][0]}->[2]) # macro: evaluate body flag;
5437
|| $tagsRef->{$_[1][0]}{__flags__}{__body__}; # tag with body;
5438
push(@specialStack, $specials{'<'}), $specials{'<'}=1 if $possible; # enable tag body, if necessary
5439
push(@specialStack, $possible); # flags what is on stack;
5440
5441
# temporarily activate specials "{" and "}" *as necessary*
5442
push(@specialStack, @specials{('{', '}')}), @specials{('{', '}')}=(1) x 2
5443
if (exists $macros{$_[1][0]} and %{$macros{$_[1][0]}->[0]}) # macro: evaluate declared options;
5444
|| $tagsRef->{$_[1][0]}{__flags__}{__options__}; # tag with options;
5445
5446
# deactivate boost
5447
$flags{noboost}=1;
5448
}
5449
],
5450
[#Rule 125
5451
'@20-3', 0,
5452
sub
5453
#line 3074 "ppParser.yp"
5454
{
5455
# reactivate boost
5456
$flags{noboost}=0;
5457
5458
# restore special states of "{" and "}", if necessary
5459
@specials{('{', '}')}=splice(@specialStack, -2, 2)
5460
if (exists $macros{$_[1][0]} and %{$macros{$_[1][0]}->[0]}) # macro: evaluate declared options;
5461
|| $tagsRef->{$_[1][0]}{__flags__}{__options__}; # tag with options;
5462
5463
# check options in general if declared mandatory
5464
if (
5465
not @{$_[3][0]}
5466
and exists $tagsRef->{$_[1][0]}
5467
and exists $tagsRef->{$_[1][0]}{options}
5468
and $tagsRef->{$_[1][0]}{options}==&TAGS_MANDATORY
5469
)
5470
{
5471
# display error message
5472
warn "\n\n[Fatal] $sourceFile, line $_[3][1]: Missing mandatory options of tag $_[1][0]\n";
5473
5474
# this is an syntactical error, stop parsing
5475
$_[0]->YYAbort;
5476
}
5477
}
5478
],
5479
[#Rule 126
5480
'tag', 5,
5481
sub
5482
#line 3099 "ppParser.yp"
5483
{
5484
# scopy
5485
my $ignore;
5486
5487
# trace, if necessary
5488
warn "[Trace] $sourceFile, line $_[5][1]: Tag $_[1][0] completed.\n" if $flags{trace} & TRACE_PARAGRAPHS;
5489
5490
# build parameter hash, if necessary
5491
my %pars;
5492
if (@{$_[3][0]})
5493
{
5494
# the list already consists of key/value pairs
5495
%pars=@{$_[3][0]}
5496
}
5497
5498
# Tag condition set?
5499
if (exists $pars{_cnd_})
5500
{
5501
# ok, if the condition was true or could not be evaluated, return just the body
5502
# (so that the tag or macro is ignored)
5503
unless (_evalTagCondition($pars{_cnd_}, $sourceFile, $_[5][1]))
5504
{return([[@{$_[5][0]} ? @{$_[5][0]} : ()], $_[5][1]]);}
5505
else
5506
{
5507
# strip off this special option before the tag or macro is furtherly processed
5508
delete $pars{_cnd_};
5509
}
5510
}
5511
5512
# tags require special handling
5513
unless (exists $macros{$_[1][0]})
5514
{
5515
# check tag body in general if declared mandatory
5516
if (
5517
not @{$_[5][0]}
5518
and exists $tagsRef->{$_[1][0]}
5519
and exists $tagsRef->{$_[1][0]}{body}
5520
and $tagsRef->{$_[1][0]}{body}==&TAGS_MANDATORY
5521
)
5522
{
5523
# display error message
5524
warn "[Fatal] $sourceFile, line $_[5][1]: Missing mandatory body of tag $_[1][0]\n";
5525
5526
# this is an syntactical error, stop parsing
5527
$_[0]->YYAbort;
5528
}
5529
5530
# invoke hook function, if necessary
5531
if (exists $tagsRef->{$_[1][0]} and exists $tagsRef->{$_[1][0]}{hook})
5532
{
5533
# make an option hash
5534
my $options={@{$_[3][0]}};
5535
5536
# call hook function (use eval() to guard yourself)
5537
my $rc;
5538
eval {$rc=&{$tagsRef->{$_[1][0]}{hook}}($_[1][1], $options, dclone($_[5][0]), $anchors, join('-', @headlineIds), $flags{headlinenr})};
5539
5540
# check result
5541
unless ($@)
5542
{
5543
{
5544
# semantic error?
5545
++$_semerr, last if $rc==PARSING_ERROR;
5546
5547
# syntactical error?
5548
$_[0]->YYAbort, last if $rc==PARSING_FAILED;
5549
5550
# tag to ignore, or even everything covered?
5551
$ignore=$rc, last if $rc==PARSING_IGNORE or $rc==PARSING_ERASE;
5552
5553
# update options (might be modified, and checking for a difference
5554
# might take more time then just copying the replied values)
5555
@{$_[3][0]}=%$options;
5556
5557
# all right?
5558
if ($rc==PARSING_OK)
5559
{
5560
# is this a tag that will invoke a finish hook?
5561
if (exists $tagsRef->{$_[1][0]}{finish})
5562
{
5563
# update number of tags to finish in the currently built stream section, if necessary
5564
$pendingTags->[1]++;
5565
5566
# Disable storage of a checksum. (A finish hook makes the paragraph depending
5567
# on something potentially outside the paragraph - the paragraph becomes dynamic.)
5568
$flags{checksummed}=0;
5569
}
5570
5571
# well done
5572
last;
5573
}
5574
5575
# or even superb?
5576
$_[0]->YYAccept, last if $rc==PARSING_COMPLETED;
5577
5578
# something is wrong here
5579
warn "[Warn] Tags $_[1][0] tag hook replied unexpected result $rc, ignored.\n";
5580
}
5581
}
5582
else
5583
{warn "[Warn] Error in tags $_[1][0] tag hook: $@\n"}
5584
5585
# rebuild parameter hash, if necessary
5586
if (@{$_[3][0]})
5587
{
5588
# the list already consists of key/value pairs
5589
%pars=@{$_[3][0]}
5590
}
5591
}
5592
}
5593
5594
# this might be a macro as well as a tag - so what?
5595
unless (exists $macros{$_[1][0]})
5596
{
5597
# update statistics
5598
$statistics{&DIRECTIVE_TAG}++;
5599
5600
# reply tag data as necessary
5601
unless (defined $ignore)
5602
{
5603
# supply a complete tag
5604
my %hints=(nr=>++$directiveCounter);
5605
[
5606
[
5607
# opener directive
5608
[\%hints, DIRECTIVE_TAG, DIRECTIVE_START, $_[1][0], \%pars, scalar(@{$_[5][0]})],
5609
# the list of enclosed literals, if any
5610
@{$_[5][0]} ? @{$_[5][0]} : (),
5611
# final directive
5612
[\%hints, DIRECTIVE_TAG, DIRECTIVE_COMPLETE, $_[1][0], \%pars, scalar(@{$_[5][0]})]
5613
],
5614
$_[5][1]
5615
];
5616
}
5617
elsif ($ignore==PARSING_IGNORE)
5618
{
5619
# supply the body, ignore the tag "envelope" ("hide" the tag)
5620
[
5621
[
5622
# the list of enclosed literals, if any
5623
@{$_[5][0]} ? @{$_[5][0]} : (),
5624
],
5625
$_[5][1]
5626
];
5627
}
5628
elsif ($ignore==PARSING_ERASE)
5629
{
5630
# reply nothing real
5631
[[()], $_[5][1]];
5632
}
5633
else
5634
{die "[BUG] Unhandled flag $ignore.";}
5635
}
5636
else
5637
{
5638
# flag that this paragraph uses macros (a cache hit will only be useful if macro definitions will have been unchanged)
5639
$flags{checksummed}[3]=1 unless exists $flags{checksummed} and not $flags{checksummed};
5640
5641
# this is a macro - resolve it!
5642
my $macro=$macros{$_[1][0]}->[1];
5643
5644
# fill in parameters
5645
foreach my $par (keys %{$macros{$_[1][0]}->[0]})
5646
{
5647
my $value= exists $pars{$par} ? $pars{$par}
5648
: defined $macros{$_[1][0]}->[0]{$par} ? $macros{$_[1][0]}->[0]{$par}
5649
: '';
5650
$macro=~s/__${par}__/$value/g;
5651
}
5652
5653
# Bodyless macros need special care - the parser already got the subsequent token to
5654
# recognize that the macro was complete. Now, the macro replacement is reinserted into
5655
# the stream where it will be read by the next lexer operation which is enforced when
5656
# the parser needs a token again - and this will happen after processing the already
5657
# received token which stood behind the bodyless macro. Letting the parser process the
5658
# read token this way, this token would be streamed (in most cases) *before* the macro
5659
# replacement, while it was intented to come after it. So, if we detect this case, we
5660
# move this token *behind* the macro replacement. As for the parser, we replace
5661
# this token by something streamed to "nothing", currently a special string declared
5662
# as "Word" token.
5663
my $delayedToken;
5664
unless (@{$_[5][0]})
5665
{
5666
# insert the current token behind the imaginary body
5667
$delayedToken=new PerlPoint::Parser::DelayedToken($_[0]->YYCurtok, $_[0]->YYCurval);
5668
5669
# set new dummy values to let the parser work on
5670
# (something without effect and valid everywhere a tag is)
5671
$_[0]->YYCurtok('Word');
5672
$_[0]->YYCurval([DUMMY_TOKEN, $_[0]->YYCurval->[1]]);
5673
}
5674
5675
# finally, pass the constructed text back to the input stream (by stack)
5676
_stackInput($_[0], (map {$_ eq '__body__' ? dclone($_[5][0]) : split(/(\n)/, $_)} split(/(__body__)/, $macro)), $delayedToken ? $delayedToken : ());
5677
5678
# reset the "end of input reached" flag if necessary
5679
$readCompletely=0 if $readCompletely;
5680
5681
# reply nothing real
5682
[[()], $_[5][1]];
5683
}
5684
}
5685
],
5686
[#Rule 127
5687
'optional_tagpars', 0,
5688
sub
5689
#line 3305 "ppParser.yp"
5690
{[[], $lineNrs{$inHandle}];}
5691
],
5692
[#Rule 128
5693
'optional_tagpars', 1, undef
5694
],
5695
[#Rule 129
5696
'used_tagpars', 3,
5697
sub
5698
#line 3311 "ppParser.yp"
5699
{
5700
# supply the parameters
5701
[$_[2][0], $_[3][1]];
5702
}
5703
],
5704
[#Rule 130
5705
'tagpars', 1, undef
5706
],
5707
[#Rule 131
5708
'tagpars', 3,
5709
sub
5710
#line 3320 "ppParser.yp"
5711
{
5712
# update parameter list
5713
push(@{$_[1][0]}, @{$_[3][0]});
5714
5715
# supply updated parameter list
5716
[$_[1][0], $_[3][1]];
5717
}
5718
],
5719
[#Rule 132
5720
'@21-1', 0,
5721
sub
5722
#line 3331 "ppParser.yp"
5723
{
5724
# backslashes should pass in tag options
5725
push(@specialStack, $lexerFlags{backsl});
5726
$lexerFlags{backsl}=LEXER_TOKEN;
5727
5728
# temporarily make "=" and quotes the only specials,
5729
# but take care to reset the remaining settings defined
5730
push(@specialStack, [(%specials)], $specials{'='});
5731
@specials{keys %specials}=(0) x scalar(keys %specials);
5732
@specials{('=', '"')}=(1, 1);
5733
}
5734
],
5735
[#Rule 133
5736
'@22-3', 0,
5737
sub
5738
#line 3343 "ppParser.yp"
5739
{
5740
# restore special "=" setting
5741
$specials{'='}=pop(@specialStack);
5742
}
5743
],
5744
[#Rule 134
5745
'tagpar', 5,
5746
sub
5747
#line 3348 "ppParser.yp"
5748
{
5749
# restore special settings
5750
%specials=@{pop(@specialStack)};
5751
5752
# restore backslash flag
5753
$lexerFlags{backsl}=pop(@specialStack);
5754
5755
# supply flag and value
5756
[[$_[1][0], $_[5][0]], $_[5][1]];
5757
}
5758
],
5759
[#Rule 135
5760
'tagvalue', 1, undef
5761
],
5762
[#Rule 136
5763
'tagvalue', 3,
5764
sub
5765
#line 3362 "ppParser.yp"
5766
{
5767
# build a string and supply it
5768
[join('', @{$_[2][0]}), $_[3][1]];
5769
}
5770
],
5771
[#Rule 137
5772
'optional_tagbody', 0,
5773
sub
5774
#line 3370 "ppParser.yp"
5775
{
5776
# if we are here, "<" *possibly* was marked to be a special - now it becomes what is was before
5777
# (take care the stack is filled correctly!)
5778
my $possible=pop(@specialStack); # was the body enabled?
5779
$specials{'<'}=pop(@specialStack) if $possible; # if so, restore the stack
5780
5781
# supply an empty result
5782
[[], $lineNrs{$inHandle}];
5783
}
5784
],
5785
[#Rule 138
5786
'@23-1', 0,
5787
sub
5788
#line 3380 "ppParser.yp"
5789
{
5790
# if we are here, "<" was marked to be a special - now it becomes what is was before
5791
# (take care the stack is filled correctly!)
5792
my $possible=pop(@specialStack); # can be ignored - surely the body was enabled!
5793
$specials{'<'}=pop(@specialStack); # restore the stack
5794
5795
# temporarily activate special ">"
5796
push(@specialStack, @specials{('>')});
5797
@specials{('>')}=1;
5798
}
5799
],
5800
[#Rule 139
5801
'optional_tagbody', 4,
5802
sub
5803
#line 3391 "ppParser.yp"
5804
{
5805
# reset ">" setting
5806
@specials{('>')}=pop(@specialStack);
5807
5808
# reply the literals
5809
[$_[3][0], $_[4][1]];
5810
}
5811
],
5812
[#Rule 140
5813
'@24-1', 0,
5814
sub
5815
#line 3402 "ppParser.yp"
5816
{
5817
# trace, if necessary
5818
warn "[Trace] $sourceFile, line $_[1][1]: Table starts.\n" if $flags{trace} & TRACE_PARAGRAPHS;
5819
5820
# check nesting
5821
_semerr($_[0], "$sourceFile, line $_[3][1]: Nested tables are not supported by this parser version.")
5822
if @tableSeparatorStack and not $flags{nestedTables};
5823
5824
# temporarily activate specials "{" and "}"
5825
push(@specialStack, @specials{('{', '}')});
5826
@specials{('{', '}')}=(1, 1);
5827
5828
# empty lines have to be ignored in tables
5829
push(@specialStack, $lexerFlags{el});
5830
$lexerFlags{el}=LEXER_IGNORE;
5831
5832
# deactivate boost
5833
$flags{noboost}=1;
5834
}
5835
],
5836
[#Rule 141
5837
'@25-3', 0,
5838
sub
5839
#line 3422 "ppParser.yp"
5840
{
5841
# reactivate boost
5842
$flags{noboost}=0;
5843
5844
# restore previous handling of empty lines
5845
$lexerFlags{el}=pop(@specialStack);
5846
5847
# restore special state of "{" and "}"
5848
@specials{('{', '}')}=splice(@specialStack, -2, 2);
5849
5850
# read parameters and adapt them, if necessary
5851
my %tagpars=@{$_[3][0]};
5852
5853
if (exists $tagpars{rowseparator})
5854
{
5855
$tagpars{rowseparator}=quotemeta($tagpars{rowseparator});
5856
$tagpars{rowseparator}="\n" if $tagpars{rowseparator} eq '\\\\n';
5857
}
5858
5859
# mark table start
5860
$tableColumns=0-(
5861
exists $tagpars{gracecr} ? $tagpars{gracecr}
5862
: (not exists $tagpars{rowseparator} or $tagpars{rowseparator} eq "\n") ? 1
5863
: 0
5864
);
5865
5866
# store specified column separator (or default)
5867
unshift(@tableSeparatorStack, [
5868
exists $tagpars{separator} ? quotemeta($tagpars{separator}) : '\|',
5869
exists $tagpars{rowseparator} ? $tagpars{rowseparator} : "\n",
5870
]);
5871
}
5872
],
5873
[#Rule 142
5874
'table', 6,
5875
sub
5876
#line 3455 "ppParser.yp"
5877
{
5878
# build parameter hash, if necessary
5879
my %pars;
5880
if (@{$_[3][0]})
5881
{
5882
# the list already consists of key/value pairs
5883
%pars=@{$_[3][0]}
5884
}
5885
5886
# Tag condition set?
5887
if (exists $pars{_cnd_})
5888
{
5889
# ok, if the condition was true or could not be evaluated,
5890
# stop processing of this tag (there is no body, so return an empty stream)
5891
unless (_evalTagCondition($pars{_cnd_}, $sourceFile, $_[6][1]))
5892
{return([[()], $_[6][1]]);}
5893
else
5894
{
5895
# strip off this special option before the tag or macro is furtherly processed
5896
delete $pars{_cnd_};
5897
}
5898
}
5899
5900
# add row separator information unless it was defined by the user itself
5901
$pars{rowseparator}='\n' unless exists $pars{rowseparator};
5902
$pars{rowseparator}='\\\\n' if $pars{rowseparator} eq '\\n';
5903
5904
# store nesting level information
5905
$pars{__nestingLevel__}=@tableSeparatorStack;
5906
5907
# If we are here and found anything in the table, it is
5908
# possible that a final row was closed and a new one opened
5909
# (e.g. at the end of the last table line, if rows are separated
5910
# by "\n"). Because the table is completed now, these tags can
5911
# be removed to get the common case of an opened but not yet
5912
# completed table cell.
5913
splice(@{$_[5][0]}, -4, 4) if @{$_[5][0]}
5914
and ref($_[5][0][-1]) eq 'ARRAY'
5915
and @{$_[5][0][-1]}==4
5916
and $_[5][0][-1][STREAM_DIR_TYPE] eq DIRECTIVE_TAG
5917
and $_[5][0][-1][STREAM_DIR_STATE] eq DIRECTIVE_START
5918
and $_[5][0][-1][STREAM_DIR_DATA] eq 'TABLE_COL';
5919
5920
# normalize table rows (no need of auto format)
5921
($pars{__titleColumns__}, $pars{__maxColumns__})=_normalizeTableRows($_[5][0], 0);
5922
5923
# warn user in case of potential row width conflicts
5924
warn qq([Warn] $sourceFile, line $_[1][1]: The maximum cell number per row ($pars{__maxColumns__}) was not detected in the first row (which has $pars{__titleColumns__} columns).\n) if $pars{__titleColumns__}<$pars{__maxColumns__} and not ($flags{display} & DISPLAY_NOWARN);
5925
5926
# reset column separator memory, mark table completed
5927
shift(@tableSeparatorStack);
5928
$tableColumns=0;
5929
5930
# reply data in a "tag envelope" (for backends)
5931
my ($hints1, $hints2, $hints3)=({nr=>++$directiveCounter}, {nr=>++$directiveCounter}, {nr=>++$directiveCounter});
5932
[
5933
[
5934
# opener directives
5935
[$hints1, DIRECTIVE_TAG, DIRECTIVE_START, 'TABLE', \%pars],
5936
[$hints2, DIRECTIVE_TAG, DIRECTIVE_START, 'TABLE_ROW'],
5937
[$hints3, DIRECTIVE_TAG, DIRECTIVE_START, 'TABLE_COL'],
5938
# the list of enclosed literals reduced by the final two, if any
5939
@{$_[5][0]} ? @{$_[5][0]} : (),
5940
# final directive
5941
[$hints3, DIRECTIVE_TAG, DIRECTIVE_COMPLETE, 'TABLE_COL'],
5942
[$hints2, DIRECTIVE_TAG, DIRECTIVE_COMPLETE, 'TABLE_ROW'],
5943
[$hints1, DIRECTIVE_TAG, DIRECTIVE_COMPLETE, 'TABLE', \%pars]
5944
],
5945
$_[6][1]
5946
];
5947
}
5948
],
5949
[#Rule 143
5950
'table_separator', 1,
5951
sub
5952
#line 3530 "ppParser.yp"
5953
{
5954
# update counter of completed table columns
5955
$tableColumns++;
5956
5957
# supply a simple seperator tag
5958
my %hints=(nr=>++$directiveCounter);
5959
[
5960
[
5961
[\%hints, DIRECTIVE_TAG, DIRECTIVE_COMPLETE, 'TABLE_COL'],
5962
$_[1][0] eq 'c' ? ()
5963
: (
5964
[{}, DIRECTIVE_TAG, DIRECTIVE_COMPLETE, 'TABLE_ROW'],
5965
[{}, DIRECTIVE_TAG, DIRECTIVE_START, 'TABLE_ROW'],
5966
),
5967
[\%hints, DIRECTIVE_TAG, DIRECTIVE_START, 'TABLE_COL'],
5968
],
5969
$_[1][1]
5970
];
5971
}
5972
],
5973
[#Rule 144
5974
'@26-1', 0,
5975
sub
5976
#line 3553 "ppParser.yp"
5977
{
5978
# switch to condition mode
5979
_stateManager(STATE_TABLE);
5980
5981
# trace, if necessary
5982
warn "[Trace] $sourceFile, line $_[1][1]: Table paragraph starts.\n" if $flags{trace} & TRACE_PARAGRAPHS;
5983
}
5984
],
5985
[#Rule 145
5986
'@27-4', 0,
5987
sub
5988
#line 3561 "ppParser.yp"
5989
{
5990
# store specified column separator
5991
unshift(@tableSeparatorStack, [quotemeta(join('', @{$_[3][0]})), "\n"]);
5992
}
5993
],
5994
[#Rule 146
5995
'table_paragraph', 7,
5996
sub
5997
#line 3566 "ppParser.yp"
5998
{
5999
# back to default mode
6000
_stateManager(STATE_DEFAULT);
6001
6002
# trace, if necessary
6003
warn "[Trace] $sourceFile, line $_[7][1]: Table paragraph completed.\n" if $flags{trace} & TRACE_PARAGRAPHS;
6004
6005
# reset column separator memory, mark table completed
6006
shift(@tableSeparatorStack);
6007
$tableColumns=0;
6008
6009
# build parameter hash (contains level information, which is always 1,
6010
# and various retranslation hints)
6011
my %pars=(
6012
__nestingLevel__ => 1,
6013
__paragraph__ => 1,
6014
separator => join('', @{$_[3][0]}),
6015
);
6016
6017
# If we are here and found anything in the table, a final row was
6018
# closed and a new one opened at the end of the last table line.
6019
# Because the table is completed now, the final opener tags can
6020
# be removed. This is done *here* and by pop() for acceleration.
6021
if (@{$_[6][0]}>4)
6022
{
6023
# delete final opener directives made by the final carriage return
6024
splice(@{$_[6][0]}, -2, 2);
6025
6026
# normalize table rows and autoformat headline fields
6027
($pars{__titleColumns__}, $pars{__maxColumns__})=_normalizeTableRows($_[6][0], 1);
6028
6029
# warn user in case of potential row width conflicts
6030
warn qq([Warn] $sourceFile, line $_[1][1]: The maximum cell number per row ($pars{__maxColumns__}) was not detected in the first row (which has $pars{__titleColumns__} columns).\n) if $pars{__titleColumns__}<$pars{__maxColumns__} and not ($flags{display} & DISPLAY_NOWARN);
6031
6032
# reply data in a "tag envelope" (for backends)
6033
my %hints=(nr=>++$directiveCounter);
6034
[
6035
[
6036
# opener directives (note that first row and column are already opened by the initial carriage return stream)
6037
[\%hints, DIRECTIVE_TAG, DIRECTIVE_START, 'TABLE', \%pars],
6038
[{}, DIRECTIVE_TAG, DIRECTIVE_START, 'TABLE_ROW'],
6039
[{}, DIRECTIVE_TAG, DIRECTIVE_START, 'TABLE_HL'],
6040
# the list of enclosed literals reduced by the final two, if any
6041
@{$_[6][0]} ? @{$_[6][0]} : (),
6042
# final directive
6043
[\%hints, DIRECTIVE_TAG, DIRECTIVE_COMPLETE, 'TABLE', \%pars]
6044
],
6045
$_[7][1]
6046
];
6047
}
6048
else
6049
{
6050
# empty table - reply nothing real
6051
[[()], $_[7][1]];
6052
}
6053
}
6054
],
6055
[#Rule 147
6056
'@28-1', 0,
6057
sub
6058
#line 3626 "ppParser.yp"
6059
{
6060
# switch to embedding mode saving the former state (including *all* special settings)
6061
push(@stateStack, $parserState);
6062
push(@specialStack, [%specials]);
6063
_stateManager(STATE_EMBEDDING);
6064
6065
# trace, if necessary
6066
warn "[Trace] $sourceFile, line $_[1][1]: Embedding starts.\n" if $flags{trace} & TRACE_PARAGRAPHS;
6067
6068
# Disable storage of a checksum. (Dynamic parts may change or have changed.
6069
# Static parts are static of course, but the filter settings may vary.)
6070
$flags{checksummed}=0;
6071
6072
# temporarily activate specials "{" and "}"
6073
push(@specialStack, @specials{('{', '}')});
6074
@specials{('{', '}')}=(1, 1);
6075
6076
# deactivate boost
6077
$flags{noboost}=1;
6078
}
6079
],
6080
[#Rule 148
6081
'@29-3', 0,
6082
sub
6083
#line 3647 "ppParser.yp"
6084
{
6085
# reactivate boost
6086
$flags{noboost}=0;
6087
6088
# restore special state of "{" and "}"
6089
@specials{('{', '}')}=splice(@specialStack, -2, 2);
6090
}
6091
],
6092
[#Rule 149
6093
'embedded', 6,
6094
sub
6095
#line 3655 "ppParser.yp"
6096
{
6097
# restore former parser state (including *all* special settings)
6098
_stateManager(pop(@stateStack));
6099
%specials=@{pop(@specialStack)};
6100
6101
# build parameter hash, if necessary
6102
my %pars;
6103
if (@{$_[3][0]})
6104
{
6105
# the list already consists of key/value pairs
6106
%pars=@{$_[3][0]}
6107
}
6108
6109
# set default language, if necessary
6110
$pars{lang}='pp' unless exists $pars{lang};
6111
6112
# Tag condition set?
6113
if (exists $pars{_cnd_})
6114
{
6115
# ok, if the condition was true or could not be evaluated,
6116
# stop processing of this tag (there is no body, so return an empty stream)
6117
unless (_evalTagCondition($pars{_cnd_}, $sourceFile, $_[6][1]))
6118
{return([[()], $_[6][1]]);}
6119
else
6120
{
6121
# strip off this special option before the tag or macro is furtherly processed
6122
delete $pars{_cnd_};
6123
}
6124
}
6125
6126
# did the user exclude files of the language the embedded source is written in?
6127
my $langExcluded=not (
6128
not $flags{filter} # no general language filter is defined, so all languages are allowed, or
6129
or lc($pars{lang}) eq 'pp' # this is a PerlPoint file, or
6130
or (
6131
exists $pars{lang} # there is a general language filter,
6132
and $pars{lang}=~/^$flags{filter}$/i # and it allows to include files of this language
6133
)
6134
);
6135
6136
# set import filter as necessary
6137
my $filterSet=_setImportFilter($_[0], \%pars);
6138
6139
# Input filter to call?
6140
if (
6141
not $langExcluded # files in the language of the embedded one are not excluded in general
6142
and exists $pars{ifilter} # and there is an import filter
6143
)
6144
{
6145
# Can we invoke the filter code?
6146
unless ($safeObject)
6147
{
6148
# What a pity - but probably the unfiltered source is not what the backend
6149
# expects, so we need to ignore the embedded code completely for now. As
6150
# usually, this is done without warning.
6151
return([[()], $_[6][1]]);
6152
}
6153
else
6154
{
6155
# OK, we can try to invoke the filter.
6156
6157
# inform user
6158
warn qq([Warn] $sourceFile, line $_[1][1]: Running input filter.\n) if $flags{trace} & TRACE_ACTIVE;
6159
6160
# update active contents base data, if necessary
6161
if ($flags{activeBaseData})
6162
{
6163
no strict 'refs';
6164
${join('::', ref($safeObject) ? $safeObject->root : 'main', 'PerlPoint')}=dclone($flags{activeBaseData});
6165
}
6166
6167
# We provide the text in a special variable @main::_ifilterText,
6168
# and the target type in a special variable $main::_ifilterType,
6169
# as well as the filename in a special var. $main::_ifilterFile.
6170
{
6171
no strict 'refs';
6172
@{join('::', ref($safeObject) ? $safeObject->root : 'main', '_ifilterText')}=@{$_[5][0]};
6173
${join('::', ref($safeObject) ? $safeObject->root : 'main', '_ifilterType')}=$pars{lang};
6174
${join('::', ref($safeObject) ? $safeObject->root : 'main', '_ifilterFile')}=$sourceFile;
6175
}
6176
6177
# run the filter and catch what it supplies
6178
$_[5][0]=[ref($safeObject) ? $safeObject->reval($pars{ifilter}) : eval(join(' ', '{package main; no strict;', $pars{ifilter}, '}'))];
6179
6180
# check result
6181
if ($@)
6182
{
6183
# inform user, if necessary
6184
_semerr($_[0], qq($sourceFile, line $_[1][1]: input filter failed: $@.));
6185
6186
# ignore this part
6187
return([[()], $_[6][1]]);
6188
}
6189
}
6190
}
6191
6192
# check if we have to stream this code
6193
if (not defined($filterSet) or $langExcluded)
6194
{
6195
# filter error occured, or the caller wants to skip the embedded code:
6196
# we have to supply something, but it should be nothing
6197
[[()], $_[6][1]];
6198
}
6199
elsif (lc($pars{lang}) eq 'pp')
6200
{
6201
# embedded PerlPoint - pass it back to the parser (by stack)
6202
_stackInput($_[0], split(/(\n)/, join('', @{$_[5][0]})));
6203
6204
# reset the "end of input reached" flag if necessary
6205
$readCompletely=0 if $readCompletely;
6206
6207
# we have to supply something, but it should be nothing
6208
[[()], $_[6][1]];
6209
}
6210
elsif (lc($pars{lang}) eq 'perl')
6211
{
6212
# This is embedded Perl code, anything passed really?
6213
# And does the caller want to evaluate the code?
6214
if (@{$_[5][0]} and $safeObject)
6215
{
6216
# update active contents base data, if necessary
6217
if ($flags{activeBaseData})
6218
{
6219
no strict 'refs';
6220
${join('::', ref($safeObject) ? $safeObject->root : 'main', 'PerlPoint')}=dclone($flags{activeBaseData});
6221
}
6222
6223
# make the code a string and evaluate it
6224
my $perl=join('', @{$_[5][0]});
6225
warn "[Trace] $sourceFile, line $_[6][1]: Evaluating this code:\n\n$perl\n\n\n" if $flags{trace} & TRACE_ACTIVE;
6226
6227
# ignore empty code
6228
if ($perl=~/\S/)
6229
{
6230
# well, there is something, evaluate it
6231
my $result=ref($safeObject) ? $safeObject->reval($perl) : eval(join(' ', '{package main; no strict;', $perl, '}'));
6232
6233
# check result
6234
if ($@)
6235
{_semerr($_[0], "$sourceFile, line $_[6][1]: embedded Perl code could not be evaluated: $@.");}
6236
else
6237
{
6238
# success - make the result part of the input stream, if any
6239
_stackInput($_[0], split(/(\n)/, $result)) if defined $result;
6240
}
6241
6242
# reset the "end of input reached" flag if necessary
6243
$readCompletely=0 if $readCompletely;
6244
}
6245
}
6246
6247
# we have to supply something, but it should be nothing
6248
[[()], $_[6][1]];
6249
}
6250
else
6251
{
6252
# reply data in a "tag envelope" (for backends)
6253
my %hints=(nr=>++$directiveCounter);
6254
[
6255
[
6256
# opener directive
6257
[\%hints, DIRECTIVE_TAG, DIRECTIVE_START, 'EMBED', \%pars],
6258
# the list of enclosed literals, if any
6259
@{$_[5][0]} ? @{$_[5][0]} : (),
6260
# final directive
6261
[\%hints, DIRECTIVE_TAG, DIRECTIVE_COMPLETE, 'EMBED', \%pars]
6262
],
6263
$_[6][1]
6264
];
6265
}
6266
}
6267
],
6268
[#Rule 150
6269
'@30-1', 0,
6270
sub
6271
#line 3830 "ppParser.yp"
6272
{
6273
# trace, if necessary
6274
warn "[Trace] $sourceFile, line $_[1][1]: Inclusion starts.\n" if $flags{trace} & TRACE_PARAGRAPHS;
6275
6276
# Disable storage of a checksum. (Files may change or have changed. Later on,
6277
# we could try to keep a files modification date unless it is a nested PerlPoint
6278
# source or a dynamic Perl part. For now, it seems to be sufficient that each file
6279
# is cached itself.)
6280
$flags{checksummed}=0;
6281
6282
# temporarily activate specials "{" and "}"
6283
push(@specialStack, @specials{('{', '}')});
6284
@specials{('{', '}')}=(1, 1);
6285
6286
# deactivate boost
6287
$flags{noboost}=1;
6288
}
6289
],
6290
[#Rule 151
6291
'included', 3,
6292
sub
6293
#line 3848 "ppParser.yp"
6294
{
6295
# scopies
6296
my ($errors, $originalPath);
6297
6298
# reactivate boost
6299
$flags{noboost}=0;
6300
6301
# restore special state of "{" and "}"
6302
@specials{('{', '}')}=splice(@specialStack, -2, 2);
6303
6304
# check parameters: type and filename should be set at least
6305
my %tagpars=@{$_[3][0]};
6306
$errors++, _semerr($_[0], "$sourceFile, line $_[3][1]: You forgot to specify the name of your included file.") unless exists $tagpars{file};
6307
6308
# set default type, if necessary
6309
$tagpars{type}='pp' unless exists $tagpars{type};
6310
6311
# Tag condition set?
6312
if (exists $tagpars{_cnd_})
6313
{
6314
# ok, if the condition was true or could not be evaluated,
6315
# stop processing of this tag (there is no body, so return an empty stream)
6316
unless (_evalTagCondition($tagpars{_cnd_}, $sourceFile, $_[3][1]))
6317
{return([[()], $_[3][1]]);}
6318
else
6319
{
6320
# strip off this special option before the tag or macro is furtherly processed
6321
delete $tagpars{_cnd_};
6322
}
6323
}
6324
6325
# search specified directories for the file if necessary
6326
unless (-e $tagpars{file})
6327
{
6328
# pathes are stored in an already prepared array @libraryPath
6329
foreach my $path (@libraryPath)
6330
{
6331
my $newname="$path/$tagpars{file}";
6332
warn "[Trace] $sourceFile, line $_[3][1]: Trying include file name $newname for $tagpars{file}.\n" if $flags{trace} & TRACE_SEMANTIC;
6333
$tagpars{file}=$newname, last if -e $newname;
6334
}
6335
}
6336
6337
# expand filename to avoid trouble by various names for the same file
6338
$tagpars{file}=catfile(abs_path(dirname($originalPath=$tagpars{file})), basename($tagpars{file}))
6339
or $errors++, semmerr("$sourceFile, line $_[3][1]: File name $tagpars{file} cannot be resolved.\n");
6340
6341
# smart inclusion?
6342
my $smart=1 if $tagpars{type}=~/^pp$/
6343
and exists $tagpars{smart} and $tagpars{smart}
6344
and exists $openedSourcefiles{$tagpars{file}};
6345
6346
# avoid circular source inclusion
6347
$errors++, _semerr($_[0], "$sourceFile, line $_[3][1]: Source file $originalPath was already opened before (full path: $tagpars{file}).") if $tagpars{type}=~/^pp$/
6348
and not $smart
6349
and grep($_ eq $tagpars{file}, @nestedSourcefiles);
6350
6351
6352
# PerlPoint headline offsets have to be positive numbers or certain strings
6353
$errors++, _semerr($_[0], "$sourceFile, line $_[3][1]: Invalid headline level offset $tagpars{headlinebase}, positive number or keywords BASE_LEVEL/CURRENT_LEVEL expected.") if $tagpars{type}=~/^pp$/i and exists $tagpars{headlinebase} and $tagpars{headlinebase}!~/^\d+$/ and $tagpars{headlinebase}!~/^(base|current)_level$/i;
6354
$tagpars{headlinebase}=$flags{headlineLevel} if exists $tagpars{headlinebase} and $tagpars{headlinebase}=~/^current_level$/i;
6355
$tagpars{headlinebase}=$flags{headlineLevel}-1 if exists $tagpars{headlinebase} and $tagpars{headlinebase}=~/^base_level$/i;
6356
6357
# all right?
6358
unless (defined $smart or defined $errors)
6359
{
6360
# check the filename
6361
if (-r $tagpars{file})
6362
{
6363
# store the files name and directory for later reference
6364
# (we could refer do that later, but using intermediate buffers
6365
# allows to keep the original values when switching the file in
6366
# background which happens with input filters)
6367
my $orgname=$tagpars{file};
6368
6369
# did the user exclude files of the language the embedded source is written in?
6370
my $typeExcluded=not (
6371
not $flags{filter} # no general language filter is defined, so all languages are allowed, or
6372
or lc($tagpars{type}) eq 'pp' # this is a PerlPoint file, or
6373
or (
6374
exists $tagpars{type} # there is a general language filter,
6375
and $tagpars{type}=~/^$flags{filter}$/i # and it allows to include files of this language
6376
)
6377
);
6378
6379
# try to set a set default import filter, if necessary
6380
if (exists $tagpars{import} and $tagpars{import} and $tagpars{import}!~/\D/)
6381
{
6382
# import format not set explicitly, scan file name for extension
6383
$tagpars{file}=~/\.(\w+)$/;
6384
$tagpars{import}=$1;
6385
6386
# success?
6387
delete $tagpars{import}, _semerr($_[0], qq($sourceFile, line $_[3][1]: could not determine import filter via file extension.)) unless $1;
6388
}
6389
6390
# arrange import as necessary
6391
my $filterSet=_setImportFilter($_[0], \%tagpars);
6392
6393
# Import filter to call?
6394
if (not $typeExcluded and exists $tagpars{ifilter})
6395
{
6396
# Can we invoke the filter code?
6397
unless ($safeObject)
6398
{
6399
# What a pity - but probably the unfiltered source is not what the backend
6400
# expects, so we need to ignore the embedded code completely for now. As
6401
# usually, this is done without warning.
6402
return([[()], $_[3][1]]);
6403
}
6404
else
6405
{
6406
# OK, we can try to invoke the filter.
6407
6408
# inform user
6409
warn qq([Warn] $sourceFile, line $_[1][1]: Running input filter.\n) if $flags{trace} & TRACE_ACTIVE;
6410
6411
# update active contents base data, if necessary
6412
if ($flags{activeBaseData})
6413
{
6414
no strict 'refs';
6415
${join('::', ref($safeObject) ? $safeObject->root : 'main', 'PerlPoint')}=dclone($flags{activeBaseData});
6416
}
6417
6418
# open original file
6419
open(my $orgHandle, $tagpars{file});
6420
binmode($orgHandle);
6421
6422
# We provide the text in a special variable @main::_ifilterText,
6423
# and the target type in a special variable $main::_ifilterType,
6424
# as well as the filename in a special var. $main::_ifilterFile.
6425
{
6426
no strict 'refs';
6427
@{join('::', ref($safeObject) ? $safeObject->root : 'main', '_ifilterText')}=<$orgHandle>;
6428
${join('::', ref($safeObject) ? $safeObject->root : 'main', '_ifilterType')}=$tagpars{type};
6429
${join('::', ref($safeObject) ? $safeObject->root : 'main', '_ifilterFile')}=$tagpars{file};
6430
}
6431
6432
# close original file
6433
close($orgHandle);
6434
6435
# run the filter in the files directory and catch what it supplies
6436
my $startDir=cwd();
6437
chdir(dirname($orgname));
6438
6439
my @ifiltered=ref($safeObject) ? $safeObject->reval($tagpars{ifilter}) : eval(join(' ', '{package main; no strict;', $tagpars{ifilter}, '}'));
6440
chdir($startDir);
6441
6442
# check result
6443
if ($@)
6444
{
6445
# inform user, if necessary
6446
_semerr($_[0], qq($sourceFile, line $_[1][1]: input filter failed: $@.));
6447
6448
# ignore this part
6449
return([[()], $_[3][1]]);
6450
}
6451
6452
# ok, now "replace" the original file by a temporary one
6453
my ($tmpHandle, $tmpFilename)=tempfile(UNLINK => ($flags{trace} & TRACE_TMPFILES ? 0 : 1));
6454
$tagpars{file}=$tmpFilename;
6455
6456
print $tmpHandle @ifiltered;
6457
close($tmpHandle);
6458
}
6459
}
6460
6461
# check for errors
6462
if (not defined $filterSet)
6463
{
6464
# we have to supply something - but it should be nothing
6465
[[()], $_[3][1]];
6466
}
6467
# check specified file type
6468
elsif ($tagpars{type}=~/^pp$/i)
6469
{
6470
# update nesting stack
6471
push(@nestedSourcefiles, $orgname);
6472
6473
# update source file nesting level hint
6474
_predeclareVariables({_SOURCE_LEVEL=>scalar(@nestedSourcefiles)});
6475
6476
# build a hash of variables to "localize"
6477
my ($localizedVars, $localizeAll)=({}, 0);
6478
if (exists $tagpars{localize})
6479
{
6480
# special setting?
6481
if ($tagpars{localize}=~/^\s*__ALL__\s*$/)
6482
{
6483
# store a copy of all existing variables
6484
$localizedVars=dclone(\%variables);
6485
$localizeAll=1;
6486
}
6487
else
6488
{
6489
# store values of all variables to localize (passed by a comma separated list)
6490
$localizedVars={map {$_=>$variables{$_}} split(/\s*,\s*/, $tagpars{localize})};
6491
}
6492
6493
# the source level variable needs to be corrected
6494
$localizedVars->{_SOURCE_LEVEL}-- if exists $localizedVars->{_SOURCE_LEVEL};
6495
}
6496
6497
# we include a PerlPoint document, switch input handle
6498
# (we intermediately have to close the original handle because of perl5.6.0 bugs)
6499
unshift(
6500
@inHandles, [
6501
tell($inHandle),
6502
$_[0]->{USER}->{INPUT},
6503
basename($sourceFile),
6504
$lineNrs{$inHandle},
6505
@flags{qw(headlineLevelOffset headlineLevel)},
6506
cwd(),
6507
$localizedVars, $localizeAll,
6508
]
6509
);
6510
close($inHandle);
6511
open($inHandle, $tagpars{file});
6512
binmode($inHandle);
6513
$_[0]->{USER}->{INPUT}='';
6514
$sourceFile=$tagpars{file};
6515
$lineNrs{$inHandle}=0;
6516
6517
# change directory with file
6518
chdir(dirname($orgname));
6519
6520
# open a new input stack
6521
unshift(@inputStack, []);
6522
6523
# headline level offset declared?
6524
$flags{headlineLevelOffset}=exists $tagpars{headlinebase} ? $tagpars{headlinebase} : 0;
6525
6526
# store the filename in the list of opened sources, to avoid circular reopening
6527
# (it would be more perfect to store the complete path, is there a module for this?)
6528
$openedSourcefiles{$tagpars{file}}=1;
6529
6530
# we have to supply something, but it should be nothing
6531
[[()], $_[3][1]];
6532
}
6533
elsif ($flags{filter} and $tagpars{type}!~/^(($flags{filter})|(?:parsed)?example)$/i)
6534
{
6535
# this file does not need to be included, nevertheless
6536
# we have to supply something - but it should be nothing
6537
[[()], $_[3][1]];
6538
}
6539
elsif ($tagpars{type}=~/^perl$/i)
6540
{
6541
# Does the caller want to evaluate code?
6542
if ($safeObject)
6543
{
6544
# update active contents base data, if necessary
6545
if ($flags{activeBaseData})
6546
{
6547
no strict 'refs';
6548
${join('::', ref($safeObject) ? $safeObject->root : 'main', 'PerlPoint')}=dclone($flags{activeBaseData});
6549
}
6550
6551
# evaluate the source code (for an unknown reason, we have to precede the constant by "&" here to work)
6552
warn "[Info] Evaluating included Perl code.\n" unless $flags{display} & &DISPLAY_NOINFO;
6553
my $result=ref($safeObject) ? $safeObject->rdo($tagpars{file})
6554
: eval
6555
{
6556
# enter user code namespace
6557
package main;
6558
# disable "strict" checks
6559
no strict;
6560
# excute user code
6561
my $result=do $tagpars{file};
6562
# check result ($! does not need to be checked, we checked file readability ourselves before)
6563
die $@ if $@;
6564
# reply provided result
6565
$result;
6566
};
6567
6568
# check result
6569
if ($@)
6570
{_semerr($_[0], "$sourceFile, line $_[3][1]: included Perl code could not be evaluated: $@.");}
6571
else
6572
{
6573
# success - make the result part of the input stream (by stack)
6574
_stackInput($_[0], split(/(\n)/, $result)) if defined $result;
6575
6576
# reset the "end of input reached" flag if necessary
6577
$readCompletely=0 if $readCompletely;
6578
}
6579
}
6580
6581
# we have to supply something, but it should be nothing
6582
[[()], $_[3][1]];
6583
}
6584
else
6585
{
6586
# we include anything else: provide the contents as it is,
6587
# declared as an "embedded" part
6588
# open(my $included, $tagpars{file});
6589
my $included=new IO::File;
6590
open($included, $tagpars{file});
6591
my @included=<$included>;
6592
close($included);
6593
6594
# in case the file was declared a (parsed) example, embed its contents as a (verbatim) block,
6595
# otherwise, include it as really embedded part (to be processed by a backend)
6596
if ($tagpars{type}=~/^(parsed)?example$/i)
6597
{
6598
# set paragraph type
6599
my $ptypeDirective=defined($1) ? DIRECTIVE_BLOCK : DIRECTIVE_VERBATIM;
6600
6601
# indent lines, if requested
6602
if (exists $tagpars{indent})
6603
{
6604
# check parameter
6605
unless ($tagpars{indent}=~/^\d+$/)
6606
{$errors++, _semerr($_[0], "$sourceFile, line $_[3][1]: Invalid indentation value of \"$tagpars{indent}\", please set up a number.");}
6607
else
6608
{
6609
# all right, indent
6610
my $indentation=' ' x $tagpars{indent};
6611
@included=map {"$indentation$_"} @included;
6612
}
6613
}
6614
6615
my %hints=(nr=>++$directiveCounter);
6616
[
6617
[
6618
# opener directive
6619
[\%hints, $ptypeDirective, DIRECTIVE_START],
6620
# the list of enclosed literals
6621
@included,
6622
# final directive
6623
[\%hints, $ptypeDirective, DIRECTIVE_COMPLETE]
6624
],
6625
$_[3][1]
6626
];
6627
}
6628
else
6629
{
6630
my %hints=(nr=>++$directiveCounter);
6631
[
6632
[
6633
# opener directive
6634
[\%hints, DIRECTIVE_TAG, DIRECTIVE_START, 'EMBED', {lang=>$tagpars{type}}],
6635
# the list of enclosed "literals", if any
6636
@included,
6637
# final directive
6638
[\%hints, DIRECTIVE_TAG, DIRECTIVE_COMPLETE, 'EMBED', {lang=>$tagpars{type}}]
6639
],
6640
$_[3][1]
6641
];
6642
}
6643
}
6644
}
6645
else
6646
{
6647
# file missing, simply inform user
6648
$errors++, _semerr($_[0], "$sourceFile, line $_[3][1]: File $tagpars{file} does not exist or cannot be read (current directory: ", cwd(), ").");
6649
6650
# we have to supply something, but it should be nothing
6651
[[()], $_[3][1]];
6652
}
6653
}
6654
else
6655
{
6656
# we have to supply something, but it should be nothing
6657
[[()], $_[3][1]];
6658
}
6659
}
6660
],
6661
[#Rule 152
6662
'@31-1', 0,
6663
sub
6664
#line 4219 "ppParser.yp"
6665
{
6666
# switch to definition mode
6667
_stateManager(STATE_DEFINITION);
6668
6669
# trace, if necessary
6670
warn "[Trace] $sourceFile, line $_[1][1]: Macro definition starts.\n" if $flags{trace} & TRACE_PARAGRAPHS;
6671
}
6672
],
6673
[#Rule 153
6674
'@32-3', 0,
6675
sub
6676
#line 4227 "ppParser.yp"
6677
{
6678
# deactivate boost
6679
$flags{noboost}=1;
6680
}
6681
],
6682
[#Rule 154
6683
'@33-5', 0,
6684
sub
6685
#line 4232 "ppParser.yp"
6686
{
6687
# reactivate boost
6688
$flags{noboost}=0;
6689
}
6690
],
6691
[#Rule 155
6692
'@34-7', 0,
6693
sub
6694
#line 4237 "ppParser.yp"
6695
{
6696
# disable all specials to get the body as a plain text
6697
@specials{keys %specials}=(0) x scalar(keys %specials);
6698
}
6699
],
6700
[#Rule 156
6701
'alias_definition', 9,
6702
sub
6703
#line 4242 "ppParser.yp"
6704
{
6705
# "text" already switched back to default mode (and disabled specials [{}:])
6706
6707
# trace, if necessary
6708
warn "[Trace] $sourceFile, line $_[7][1]: Macro definition completed.\n" if $flags{trace} & TRACE_PARAGRAPHS;
6709
6710
# check spelling (only accept capitals and underscores in alias names, just like in tags)
6711
if ($_[3][0]=~/[a-z]/)
6712
{
6713
warn "[Warn] $sourceFile, line $_[3][1]: Macro \"\\$_[3][0]\" is stored as ", uc("\\$_[3][0]"), ".\n" unless $flags{display} & DISPLAY_NOWARN;
6714
$_[3][0]=uc($_[3][0]);
6715
}
6716
6717
# build macro text
6718
shift(@{$_[9][0]}); pop(@{$_[9][0]});
6719
my $macro=join('', @{$_[9][0]});
6720
6721
# anything specified?
6722
if ($macro=~/^\s*$/)
6723
{
6724
# nothing defined, should this line cancel a previous definition?
6725
if (exists $macros{$_[3][0]})
6726
{
6727
# cancel macro
6728
delete $macros{$_[3][0]};
6729
6730
# trace, if necessary
6731
warn "[Trace] $sourceFile, line $_[7][1]: Macro \"$_[3][0]\" is cancelled.\n" if $flags{trace} & TRACE_SEMANTIC;
6732
6733
# update macro checksum
6734
$macroChecksum=sha1_base64(nfreeze(\%macros));
6735
}
6736
else
6737
{
6738
# trace, if necessary
6739
warn "[Trace] $sourceFile, line $_[7][1]: Empty macro \"$_[3][0]\" is ignored.\n" if $flags{trace} & TRACE_SEMANTIC;
6740
}
6741
}
6742
else
6743
{
6744
# ok, this is a new definition - get all used parameters
6745
my %pars;
6746
@pars{($macro=~/__([^_\\]+)__/g)}=();
6747
6748
# store default values of options, if necessary
6749
if (@{$_[5][0]})
6750
{
6751
# the list already consists of key/value pairs
6752
my %defaults=@{$_[5][0]};
6753
exists $pars{$_} and $pars{$_}=$defaults{$_} for keys %defaults;
6754
}
6755
6756
# tag body wildcard is no parameter
6757
my $bodyFlag=exists $pars{body} ? 1 : 0;
6758
delete $pars{body};
6759
6760
# make guarded underscores just underscores
6761
$macro=~s/\\_//g;
6762
6763
# store name, parameters (and their defaults, if any),
6764
# macro text and body flag
6765
$macros{$_[3][0]}=[\%pars, $macro, $bodyFlag];
6766
6767
# update macro checksum
6768
$macroChecksum=sha1_base64(nfreeze(\%macros));
6769
}
6770
6771
# we have to supply something, but it should be nothing
6772
# (this is a paragraph, so reply a plain string)
6773
['', $_[11][1]];
6774
}
6775
]
6776
],
6777
@_);
6778
bless($self,$class);
6779
}
6780
6781
#line 4317 "ppParser.yp"
6782
6783
6784
6785
# ------------------------------------------
6786
# Internal function: input stack management.
6787
# ------------------------------------------
6788
sub _stackInput
6789
{
6790
# get parameters
6791
my ($parser, @lines)=@_;
6792
6793
# declare variable
6794
my (@waiting);
6795
6796
# the current input line becomes the last line to read in this set
6797
# (this way, we arrange it that additional text is exactly placed where its generator tag or macro stood,
6798
# without Ils confusion)
6799
push(@lines, (defined $parser->{USER}->{INPUT} and $parser->{USER}->{INPUT}) ? $parser->{USER}->{INPUT} : ());
6800
6801
# combine line parts to lines completed by a trailing newline
6802
# (additionally, take into account that there might be mixed references which have to be stored unchanged)
6803
{
6804
my $lineBuffer='';
6805
foreach my $line (@lines)
6806
{
6807
if (ref($line))
6808
{
6809
# push collected string and current reference
6810
push(@waiting, length($lineBuffer) ? $lineBuffer : (), $line);
6811
6812
# reset line buffer
6813
$lineBuffer='';
6814
6815
# next turn
6816
next;
6817
}
6818
6819
# compose a string ...
6820
$lineBuffer.=$line;
6821
6822
# ... until a newline was found
6823
push(@waiting, $lineBuffer), $lineBuffer='' if $line eq "\n";
6824
}
6825
push(@waiting, $lineBuffer) if length($lineBuffer);
6826
}
6827
6828
# get next line to read
6829
my $newInputLine=shift(@waiting);
6830
6831
# update (innermost) input stack
6832
unshift(@{$inputStack[0]}, @waiting);
6833
6834
# update line memory (flag that this was an expanded line by adding a third parameter)
6835
unshift(@inLine, [length($newInputLine)+length('exp.: '), "exp.: $newInputLine", 1]);
6836
6837
# make the new top line the current input
6838
$parser->{USER}->{INPUT}=$newInputLine;
6839
}
6840
6841
6842
6843
# a pattern lookup table for certain specials, used by the lexer (should be scoped to it
6844
# but indentation of a long function takes time ...)
6845
my %specials2patterns;
6846
@specials2patterns{'colon', 'number', '-'}=(':', '0-9', '\-');
6847
6848
6849
# -----------------------------
6850
# Internal function: the lexer.
6851
# -----------------------------
6852
sub _lexer
6853
{
6854
# get parameters
6855
my ($parser)=@_;
6856
6857
# scan for unlexed EOL´s which should be ignored
6858
while (
6859
$parser->{USER}->{INPUT}
6860
and $parser->{USER}->{INPUT}=~/^\n/
6861
and (
6862
$lexerFlags{eol}==LEXER_IGNORE
6863
or (
6864
@tableSeparatorStack
6865
and $tableSeparatorStack[0][1] eq "\n"
6866
and $tableColumns<0
6867
)
6868
)
6869
)
6870
{
6871
# trace, if necessary
6872
warn "[Trace] Lexer: Ignored EOL in line $lineNrs{$inHandle}.\n" if $flags{trace} & TRACE_LEXER;
6873
6874
# remove the ignored newline
6875
$parser->{USER}->{INPUT}=~s/^\n//;
6876
6877
# update column counter, if necessary
6878
$tableColumns++ if @tableSeparatorStack and $tableSeparatorStack[0][1] eq "\n" and $tableColumns<0;
6879
}
6880
6881
# get next symbol
6882
unless ($parser->{USER}->{INPUT})
6883
{
6884
# update line memory (removed handled lines, both original and expanded ones)
6885
# (use a do block to perform the operation once in any case, see perlsyn)
6886
do {shift(@inLine)} until not @inLine or @{$inLine[0]}==2;
6887
6888
{
6889
# will the next line be get from the input stack instead of from a real file?
6890
my $lineFromStack=scalar(@{$inputStack[0]});
6891
6892
# reset stack line buffer, if necessary
6893
undef @previousStackLines unless $lineFromStack;
6894
6895
# get next input line
6896
unless (
6897
(@{$inputStack[0]} and ($parser->{USER}->{INPUT}=shift(@{$inputStack[0]}) or 1))
6898
or (defined($inHandle) and $parser->{USER}->{INPUT}=<$inHandle>)
6899
)
6900
{
6901
# was this a nested source?
6902
unless (@inHandles)
6903
{
6904
# This was the base document: should we insert a final additional token?
6905
# (In case we recognize the end of a document source when there is still a
6906
# paragraph filter pending, supply as many "empty lines" as necessary to let
6907
# the parser recognize the filtered paragraph is completed. Possibly a loop
6908
# detection should be added to avoid endless ping-pong.)
6909
$readCompletely=1,
6910
(($flags{trace} & TRACE_LEXER) and warn("[Trace] Lexer: Final Empty_line in line $lineNrs{$inHandle}.\n")),
6911
return('Empty_line', ['', $lineNrs{$inHandle}]) unless $readCompletely and not $flags{virtualParagraphStart};
6912
6913
# well done
6914
return('', [undef, -1]);
6915
}
6916
else
6917
{
6918
# we finished a nested source: close it and restore
6919
# things to continue reading of enclosing file
6920
my ($helper1, $helper2, $helper3, $localizedVars, $localizedAll);
6921
(
6922
$helper1,
6923
$parser->{USER}->{INPUT},
6924
$sourceFile,
6925
$helper2,
6926
@flags{qw(headlineLevelOffset headlineLevel)},
6927
$helper3,
6928
$localizedVars, $localizedAll,
6929
)=@{shift(@inHandles)};
6930
$lineNrs{$inHandle}=$helper2-1; # -1 to compensate the subsequent increment
6931
6932
# back to envelopes directory
6933
chdir($helper3);
6934
6935
# reopen envelope file
6936
close($inHandle);
6937
$inHandle=new IO::File;
6938
open($inHandle, $sourceFile);
6939
binmode($inHandle);
6940
seek($inHandle, $helper1, 0);
6941
6942
# switch back to envelopes input stack
6943
shift(@inputStack);
6944
6945
# update nesting stack
6946
pop(@nestedSourcefiles);
6947
6948
# update source file nesting level hint
6949
_predeclareVariables({_SOURCE_LEVEL=>scalar(@nestedSourcefiles)});
6950
6951
# restore variables as necessary
6952
if ($localizedAll)
6953
{
6954
# Do we have to take care of the stream?
6955
if ($flags{var2stream})
6956
{
6957
# stream variable reset
6958
push(@{$resultStreamRef->[STREAM_TOKENS]}, [{}, DIRECTIVE_VARRESET, DIRECTIVE_START]);
6959
6960
# update tag finish memory
6961
_updateTagFinishMem(scalar(@{$resultStreamRef->[STREAM_TOKENS]}));
6962
6963
# restore former variables completely, overwriting current settings
6964
# (and propagating them into the stream again)
6965
undef %variables;
6966
_predeclareVariables({$_=>$localizedVars->{$_}}, 1) foreach sort keys %$localizedVars;
6967
}
6968
else
6969
{
6970
# ok, the stream does not take notice of this operation, so it can be performed quicker
6971
%variables=%$localizedVars;
6972
}
6973
}
6974
elsif (!$localizedAll and %$localizedVars)
6975
{
6976
# handle each localized variable
6977
foreach my $var (keys %$localizedVars)
6978
{
6979
# restore old value in parser and stream context, if necessary
6980
_predeclareVariables({$var=>$localizedVars->{$var}}, 1)
6981
if $localizedVars->{$var} ne $variables{$var};
6982
}
6983
}
6984
}
6985
}
6986
6987
# update stack line buffers, if necessary
6988
if ($lineFromStack)
6989
{
6990
# "rotate" buffers (necessary because there are various return points following,
6991
# so there will be not exactly one final point where we could save the current
6992
# line value in a scalar buffer)
6993
$previousStackLines[0]=$previousStackLines[1];
6994
$previousStackLines[1]=$parser->{USER}->{INPUT};
6995
}
6996
6997
# reference found on stack?
6998
if ($lineFromStack and ref($parser->{USER}->{INPUT}))
6999
{
7000
# get the reference
7001
my @refLexed=_refLexed($parser);
7002
7003
# unless the item was a newline, we can use it directly
7004
# (but the context for newline evaluation might have changed between the
7005
# point of delaying and now)
7006
return @refLexed unless $refLexed[0] eq 'Empty_line';
7007
7008
# ok, this has to be parsed *again* (because the paragraph/special characters
7009
# context *now* might be different from that that was present when we stacked
7010
# the item)
7011
($parser->{USER}->{INPUT}, $lineNrs{$inHandle})=@{$refLexed[1]};
7012
}
7013
7014
# update line counter, if necessary
7015
$lineNrs{$inHandle}++ unless $lineFromStack;
7016
7017
# ignore this line if wished (take conditions and docstreams into account)
7018
$parser->{USER}->{INPUT}='', redo if $flags{skipInput}==1 and $parser->{USER}->{INPUT}!~/^\?/;
7019
$parser->{USER}->{INPUT}='', redo if $flags{skipInput}==2 and $parser->{USER}->{INPUT}!~/^[~=]/;
7020
7021
# if we are here, we can leave the skip mode (both condition and docstream one)
7022
$flags{skipInput}=0;
7023
7024
# we read a new line (or something from stack)
7025
unshift(@inLine, [length($parser->{USER}->{INPUT})+length('org.: '), "org.: $parser->{USER}->{INPUT}"]);
7026
7027
unless ($lineFromStack)
7028
{
7029
# add a line update hint
7030
if ($flags{linehints})
7031
{
7032
push(@{$resultStreamRef->[STREAM_TOKENS]}, [{}, DIRECTIVE_NEW_LINE, DIRECTIVE_START, {file=>$sourceFile, line=>$lineNrs{$inHandle}}]);
7033
7034
# update tag finish memory by the way
7035
_updateTagFinishMem(scalar(@{$resultStreamRef->[STREAM_TOKENS]}));
7036
}
7037
7038
# remove TRAILING whitespaces, but keep newlines (if any)
7039
{
7040
my $newline=($parser->{USER}->{INPUT}=~/\n$/m);
7041
$parser->{USER}->{INPUT}=~s/\s*$//;
7042
$parser->{USER}->{INPUT}=join('', $parser->{USER}->{INPUT}, "\n") if $newline;
7043
}
7044
}
7045
7046
# scan for empty lines as necessary
7047
if ($parser->{USER}->{INPUT}=~/^$/)
7048
{
7049
# update the checksum flags
7050
$flags{checksum}=1 if $flags{cache} & CACHE_ON;
7051
7052
# trace, if necessary
7053
warn "[Trace] Lexer: Empty_line in line $lineNrs{$inHandle}", $lexerFlags{el}==LEXER_IGNORE ? ' is ignored' : '', ".\n" if $flags{trace} & TRACE_LEXER;
7054
7055
# update input line
7056
$parser->{USER}->{INPUT}='';
7057
7058
# sometimes empty lines have no special meaning
7059
shift(@inLine), redo if $lexerFlags{el}==LEXER_IGNORE;
7060
7061
# but sometimes they are very special
7062
return('Empty_line', ["\n", $lineNrs{$inHandle}]);
7063
}
7064
else
7065
{
7066
# disable caching for embedded code containing empty lines
7067
$flags{checksummed}=0 if $specials{embedded};
7068
7069
# this may be the first line of a new paragraph to be checksummed
7070
if (
7071
($flags{cache} & CACHE_ON)
7072
and $flags{checksum}
7073
and not $lineFromStack
7074
and (not $specials{heredoc} or $specials{heredoc} eq '1')
7075
and not @tableSeparatorStack
7076
and not $specials{embedded}
7077
)
7078
{
7079
# handle $/ locally
7080
local($/);
7081
7082
# update statistics
7083
$statistics{cache}[0]++;
7084
7085
# well, switch to paragraph mode (depending on the paragraph type)!
7086
if ($parser->{USER}->{INPUT}=~/^<<(\w+)/)
7087
{$/="\n$1";}
7088
elsif ($parser->{USER}->{INPUT}=~/^(?
7089
{$/="\n\\END_TABLE";}
7090
else
7091
{$/='';}
7092
7093
# store current position
7094
my $lexerPosition=tell($inHandle);
7095
7096
# read *current* paragraph completely (take care - we may have read it completely yet!)
7097
seek($inHandle, $lexerPosition-length($parser->{USER}->{INPUT}), 0) unless $parser->{USER}->{INPUT}=~/^<<(\w+)/ or $parser->{USER}->{INPUT}=~/^(?
7098
my $paragraph=<$inHandle>;
7099
$paragraph=join('', $parser->{USER}->{INPUT}, $paragraph) if $parser->{USER}->{INPUT}=~/^<<(\w+)/ or $parser->{USER}->{INPUT}=~/^(?
7100
7101
# count the lines in the paragraph read
7102
my $plines=0;
7103
$plines++ while $paragraph=~/(\n)/g;
7104
$plines-- unless $parser->{USER}->{INPUT}=~/^<<(\w+)/ or $parser->{USER}->{INPUT}=~/^(?
7105
7106
# remove trailing whitespaces (to avoid checksumming them)
7107
$paragraph=~s/\n+$//;
7108
7109
# anything interesting found?
7110
if (defined $paragraph)
7111
{
7112
# build checksum (of paragraph *and* headline level offset)
7113
my $checksum=sha1_base64(join('+', exists $flags{headlineLevelOffset} ? $flags{headlineLevelOffset} : 0, $paragraph));
7114
7115
# warn "---> Searching checksum for this paragraph:\n-----\n$paragraph\n- by $checksum --\n";
7116
# check paragraph to be known
7117
if (
7118
exists $checksums->{$sourceFile}
7119
and exists $checksums->{$sourceFile}{$checksum}
7120
and (
7121
not defined $checksums->{$sourceFile}{$checksum}[3]
7122
or $checksums->{$sourceFile}{$checksum}[3] eq $macroChecksum
7123
)
7124
and (
7125
not defined $checksums->{$sourceFile}{$checksum}[4]
7126
or $checksums->{$sourceFile}{$checksum}[4] eq $varChecksum
7127
)
7128
)
7129
{
7130
# Do *not* reset the checksum flag for new checksums - we already read the
7131
# empty lines, and a new paragraph may follow! *But* deactivate the current
7132
# checksum to avoid multiple storage - we already stored it, right?
7133
$flags{checksummed}=0;
7134
7135
# reset input buffer - it is all handled (take care to remove a final newline
7136
# if the paragraph was closed by a string - this would normally be read in a
7137
# per line processing, but it remained in the file in paragraph mode)
7138
$/="\n";
7139
scalar(<$inHandle>) if $parser->{USER}->{INPUT}=~/^<<(\w+)/ or $parser->{USER}->{INPUT}=~/^(?
7140
$parser->{USER}->{INPUT}='';
7141
7142
# warn "===========> PARAGRAPH CACHE HIT!! ($lineNrs{$inHandle}/$sourceFile/$checksum) <=================\n$paragraph-----\n";
7143
# use Data::Dumper; warn Dumper($checksums->{$sourceFile}{$checksum});
7144
7145
# update statistics
7146
$statistics{cache}[1]++;
7147
7148
# update line counter
7149
# warn "----> Old line: $lineNrs{$inHandle}\n";
7150
$lineNrs{$inHandle}+=$plines;
7151
# warn "----> New line: $lineNrs{$inHandle}\n";
7152
7153
# update anchors
7154
$anchors->add($_, $checksums->{$sourceFile}{$checksum}[5]{$_}, $flags{headlinenr})
7155
foreach keys %{$checksums->{$sourceFile}{$checksum}[5]};
7156
7157
# The next steps depend - follow the provided hint. We may have to reinvoke
7158
# the parser to restore a state.
7159
# perl 5.6 # unless (exists $checksums->{$sourceFile}{$checksum}[2])
7160
unless (defined $checksums->{$sourceFile}{$checksum}[2])
7161
{
7162
# direct case - add the already known part directly to the stream
7163
push(@{$resultStreamRef->[STREAM_TOKENS]}, @{$checksums->{$sourceFile}{$checksum}[0]});
7164
7165
# update tag finish memory
7166
_updateTagFinishMem(scalar(@{$resultStreamRef->[STREAM_TOKENS]}));
7167
7168
# Well done this paragraph - go on!
7169
shift(@inLine);
7170
redo;
7171
}
7172
else
7173
{
7174
# more complex case - reinvoke the parser to update its states
7175
return($checksums->{$sourceFile}{$checksum}[2], [dclone($checksums->{$sourceFile}{$checksum}[0]), $lineNrs{$inHandle}]);
7176
}
7177
}
7178
7179
# flag that we are going to build an associated stream
7180
$flags{checksummed}=[$checksum, scalar(@{$resultStreamRef->[STREAM_TOKENS]}), $plines];
7181
# warn "---> Started checksumming for\n-----\n$paragraph\n---(", $plines+1, " line(s))\n";
7182
7183
# restart anchor logging
7184
$anchors->checkpoint(1);
7185
}
7186
7187
# reset file pointer
7188
seek($inHandle, $lexerPosition, 0);
7189
}
7190
7191
# update the checksum flag: we are *within* a paragraph, do not checksum
7192
# until we reach the next empty line
7193
$flags{checksum}=0;
7194
}
7195
7196
# detect things at the beginning of a *real* line at the beginning of a paragraph
7197
# (which nevertheless might have been stacked)
7198
if ( not $lineFromStack
7199
or ( defined $previousStackLines[0]
7200
and not ref($previousStackLines[0])
7201
and $previousStackLines[0]=~/\n$/
7202
)
7203
)
7204
{
7205
my @rc=_lineStartResearch($parser);
7206
return(@rc) if shift(@rc);
7207
}
7208
}
7209
}
7210
7211
# trace, if necessary
7212
warn '[Trace] Lexing ', ref($parser->{USER}->{INPUT}) ? 'a prepared part' : qq("$parser->{USER}->{INPUT}"), ".\n" if $flags{trace} & TRACE_LEXER;
7213
7214
# Reference found? (Usually placed by _stackInput().)
7215
return _refLexed($parser) if ref($parser->{USER}->{INPUT});
7216
7217
# if the paragraph was just filtered, there might be certain operations to perform
7218
# (as usual at the beginning of a new paragraph)
7219
if ($parserState==STATE_PFILTERED)
7220
{
7221
my @rc=_lineStartResearch($parser);
7222
return(@rc) if shift(@rc);
7223
}
7224
7225
# scan for heredoc close hints
7226
if ($specials{heredoc} and $specials{heredoc} ne '1' and $parser->{USER}->{INPUT}=~/^($specials{heredoc})$/)
7227
{
7228
# trace, if necessary
7229
warn "[Trace] Lexer: Heredoc close hint $1 in line $lineNrs{$inHandle}.\n" if $flags{trace} & TRACE_LEXER;
7230
7231
# update input line
7232
$parser->{USER}->{INPUT}='';
7233
7234
# reset heredoc setting
7235
$specials{heredoc}=1;
7236
7237
# reply token
7238
return('Heredoc_close', [$1, $lineNrs{$inHandle}]);
7239
}
7240
7241
# can we take the rest of the line at *once*?
7242
if (($parserState==STATE_COMMENT or $parserState==STATE_VERBATIM) and $parser->{USER}->{INPUT} ne "\n")
7243
{
7244
# grab line and chomp if necessary
7245
my $line=$parser->{USER}->{INPUT};
7246
chomp($line) unless $parserState==STATE_VERBATIM;
7247
7248
# update input line (restore trailing newline if it will be used to detect paragraph completion)
7249
$parser->{USER}->{INPUT}=$parserState==STATE_VERBATIM ? '' : "\n";
7250
7251
# trace, if necessary
7252
warn qq([Trace] Lexer: word "$line" in line $lineNrs{$inHandle}.\n) if $flags{trace} & TRACE_LEXER;
7253
7254
# supply result
7255
return('Word', [$line, $lineNrs{$inHandle}]);
7256
}
7257
7258
# reply a token
7259
for ($parser->{USER}->{INPUT})
7260
{
7261
# declare scopies
7262
my ($found, $sfound);
7263
7264
# check for table separators, if necessary (these are the most common strings)
7265
if (@tableSeparatorStack)
7266
{
7267
# check for a column separator
7268
s/^$tableSeparatorStack[0][0]//,
7269
(($flags{trace} & TRACE_LEXER) and warn("[Trace] Lexer: table column separator in line $lineNrs{$inHandle}.\n")),
7270
return('Table_separator', ['c', $lineNrs{$inHandle}]) if /^($tableSeparatorStack[0][0])/;
7271
7272
# check for row separator
7273
s/^$tableSeparatorStack[0][1]//,
7274
(($flags{trace} & TRACE_LEXER) and warn("[Trace] Lexer: table row separator in line $lineNrs{$inHandle}.\n")),
7275
return('Table_separator', ['r', $lineNrs{$inHandle}]) if /^($tableSeparatorStack[0][1])/;
7276
}
7277
7278
# reply next token: EOL?
7279
if (/^(\n)/)
7280
{
7281
if ($lexerFlags{eol}==LEXER_TOKEN)
7282
{
7283
$found=$1;
7284
warn("[Trace] Lexer: EOL in line $lineNrs{$inHandle}.\n") if $flags{trace} & TRACE_LEXER;
7285
s/^$1//;
7286
return('EOL', [$found, $lineNrs{$inHandle}]);
7287
}
7288
elsif ($lexerFlags{eol}==LEXER_EMPTYLINE)
7289
{
7290
# flag "empty line" as wished
7291
warn("[Trace] Lexer: EOL -> Empty_line in line $lineNrs{$inHandle}.\n") if $flags{trace} & TRACE_LEXER;
7292
s/^$1//;
7293
return('Empty_line', ['', $lineNrs{$inHandle}]);
7294
}
7295
elsif ($lexerFlags{eol}==LEXER_SPACE)
7296
{
7297
# flag "space" as wished and reply a simple whitespace
7298
warn("[Trace] Lexer: EOL -> Space in line $lineNrs{$inHandle}.\n") if $flags{trace} & TRACE_LEXER;
7299
s/^$1//;
7300
return('Space', [' ', $lineNrs{$inHandle}]);
7301
}
7302
else
7303
{die "[BUG] Unhandled EOL directive $lexerFlags{eol}.";}
7304
}
7305
7306
# reply next token: scan for Ils if necessary
7307
$found=$1, s/^$1//,
7308
(($flags{trace} & TRACE_LEXER) and warn("[Trace] Lexer: Ils in line $lineNrs{$inHandle}.\n")),
7309
return('Ils', [$found, $lineNrs{$inHandle}]) if $parserState==STATE_PFILTERED and /^$lexerPatterns{space}/;
7310
7311
# reply next token: scan for spaces
7312
$found=$1, s/^$1//,
7313
(($flags{trace} & TRACE_LEXER) and warn("[Trace] Lexer: Space in line $lineNrs{$inHandle}.\n")),
7314
return('Space', [$found, $lineNrs{$inHandle}]) if /^$lexerPatterns{space}/;
7315
7316
# reply next token: scan for paragraph filter delimiters ("||" and "|")
7317
$found=$1, s/^\Q$1//,
7318
(($flags{trace} & TRACE_LEXER) and warn(qq([Trace] Lexer: Paragraph filter delimiter "$found" in line $lineNrs{$inHandle}.\n))),
7319
return($found, [$found, $lineNrs{$inHandle}]) if /^$lexerPatterns{pfilterDelimiter}/ and $specials{pfilter};
7320
7321
# reply next token: scan for here doc openers
7322
$found=$1, s/^<<$1//,
7323
(($flags{trace} & TRACE_LEXER) and warn("[Trace] Lexer: Heredoc opener $found in line $lineNrs{$inHandle}.\n")),
7324
return('Heredoc_open', [$found, $lineNrs{$inHandle}]) if /^<<(\w+)/ and $specials{heredoc} eq '1';
7325
7326
# reply next token: scan for SPECIAL tagnames: \TABLE
7327
$found=$1, s/^\\$1//,
7328
(($flags{trace} & TRACE_LEXER) and warn("[Trace] Lexer: Table starts in line $lineNrs{$inHandle}.\n")),
7329
return('Table', [$found, $lineNrs{$inHandle}]) if $specials{tag} and /^$lexerPatterns{table}/;
7330
7331
# reply next token: scan for SPECIAL tagnames: \END_TABLE
7332
$found=$1, s/^\\$1//,
7333
(($flags{trace} & TRACE_LEXER) and warn("[Trace] Lexer: Table completed in line $lineNrs{$inHandle}.\n")),
7334
return('Tabled', [$found, $lineNrs{$inHandle}]) if $specials{tag} and /^$lexerPatterns{endTable}/;
7335
7336
# reply next token: scan for SPECIAL tagnames: \EMBED
7337
$found=$1, s/^\\$1//,
7338
(($flags{trace} & TRACE_LEXER) and warn("[Trace] Lexer: Embedding starts in line $lineNrs{$inHandle}.\n")),
7339
return('Embed', [$found, $lineNrs{$inHandle}]) if $specials{tag} and /^$lexerPatterns{embed}/;
7340
7341
# reply next token: scan for SPECIAL tagnames: \END_EMBED
7342
$found=$1, s/^\\$1//,
7343
(($flags{trace} & TRACE_LEXER) and warn("[Trace] Lexer: Embedding completed in line $lineNrs{$inHandle}.\n")),
7344
return('Embedded', [$found, $lineNrs{$inHandle}]) if $specials{embedded} and /^$lexerPatterns{endEmbed}/;
7345
7346
# reply next token: scan for SPECIAL tagnames: \INCLUDE
7347
$found=$1, s/^\\$1//,
7348
(($flags{trace} & TRACE_LEXER) and warn("[Trace] Lexer: Including starts in line $lineNrs{$inHandle}.\n")),
7349
return('Include', [$found, $lineNrs{$inHandle}]) if $specials{tag} and /^$lexerPatterns{include}/;
7350
7351
# reply next token: scan for tagnames
7352
$found=$1, s/^\\$1//,
7353
(($flags{trace} & TRACE_LEXER) and warn("[Trace] Lexer: Tag opener $found in line $lineNrs{$inHandle}.\n")),
7354
return('Tag_name', [$found, $lineNrs{$inHandle}]) if $specials{tag} and /^$lexerPatterns{tag}/ and (exists $tagsRef->{$1} or exists $macros{$1});
7355
7356
# reply next token: scan for special characters
7357
$found=$1, s/^\Q$1//,
7358
(($flags{trace} & TRACE_LEXER) and warn("[Trace] Lexer: Special $found in line $lineNrs{$inHandle}.\n")),
7359
return($found, [$found, $lineNrs{$inHandle}]) if /^$patternNlbBackslash(\S)/ and exists $specials{$1} and $specials{$1};
7360
7361
# reply next token: scan for definition list items
7362
$found=$1, s/^$1//,
7363
(($flags{trace} & TRACE_LEXER) and warn("[Trace] Lexer: Colon in line $lineNrs{$inHandle}.\n")),
7364
return('Colon', [$found, $lineNrs{$inHandle}]) if $specials{colon} and /^$lexerPatterns{colon}/;
7365
7366
# reply next token: search for named variables (which need to be defined except at the
7367
# beginning of a new assignment paragraph)
7368
$found=$1, s/^\$$1//,
7369
(($flags{trace} & TRACE_LEXER) and warn(qq([Trace] Lexer: Named variable "$found" in line $lineNrs{$inHandle}.\n))),
7370
return('Named_variable', [$found, $lineNrs{$inHandle}])
7371
if /^$lexerPatterns{namedVar}(=?)/
7372
and (
7373
($parserState==STATE_DEFAULT and defined($2))
7374
or exists $variables{$1}
7375
);
7376
7377
# reply next token: search for symbolic variables (these cannot be used in assignments,
7378
# so handling is easier)
7379
$found=$2, s/^\$$1//,
7380
(($flags{trace} & TRACE_LEXER) and warn(qq([Trace] Lexer: Symbolic variable "$found" in line $lineNrs{$inHandle}.\n))),
7381
return('Symbolic_variable', [$found, $lineNrs{$inHandle}])
7382
if /^$lexerPatterns{symVar}/ and exists $variables{$2};
7383
7384
# flag that this paragraph *might* use macros someday, if there is still something being no tag and no
7385
# macro, but looking like a tag or a macro (somebody could *later* declare it a real macro, so the cache
7386
# needs to check macro definitions)
7387
$flags{checksummed}[3]=1
7388
if $specials{tag} and /^$lexerPatterns{tag}/
7389
and not (exists $flags{checksummed} and not $flags{checksummed});
7390
7391
# likewise, flag that this paragraph *might* use variables someday, if there is still something being no variable,
7392
# but looking like a variable (somebody could *later* declare it a real var, so the cache
7393
# needs to check variable definitions)
7394
$flags{checksummed}[4]=1
7395
if /($lexerPatterns{namedVarKernel})|($lexerPatterns{symVarKernel})/
7396
and not (exists $flags{checksummed} and not $flags{checksummed});
7397
7398
# remove guarding \\, if necessary
7399
s/^\\// unless $specials{heredoc}
7400
or (defined $lexerFlags{backsl} and $lexerFlags{backsl}==LEXER_TOKEN)
7401
or $parserState==STATE_EMBEDDING
7402
or $parserState==STATE_PFILTER
7403
or $parserState==STATE_CONDITION
7404
or $parserState==STATE_DEFINITION;
7405
7406
# reply next token: scan for numbers, if necessary
7407
$found=$1, s/^$1//,
7408
(($flags{trace} & TRACE_LEXER) and warn("[Trace] Lexer: Number $found in line $lineNrs{$inHandle}.\n")),
7409
return('Number', [$found, $lineNrs{$inHandle}]) if $specials{number} and /^(\d+)/;
7410
7411
unless ($flags{noboost})
7412
{
7413
# build set of characters to be special
7414
my $special=join('', '([', (map {exists $specials2patterns{$_} ? $specials2patterns{$_} : $_} grep(($specials{$_} and (length==1 or exists $specials2patterns{$_})), keys %specials)), '\n\\\\', '])');
7415
$special=qr($special|(\|{1,2})) if $specials{pfilter};
7416
$special=qr($special|($tableSeparatorStack[0][0])|($tableSeparatorStack[0][1])) if @tableSeparatorStack;
7417
$special=qr($special|(($lexerPatterns{namedVar})|($lexerPatterns{symVar})));
7418
7419
# reply next token: scan for word or single character (declared as "Word" as well)
7420
#warn("~~~~~~~~~> $special\n");
7421
#warn("---------> $_");
7422
$found=$1, s/^\Q$1//,
7423
#warn("=====> $found\n\n"),
7424
(($flags{trace} & TRACE_LEXER) and warn(qq([Trace] Lexer: (Boosted) word "$found" in line $lineNrs{$inHandle}.\n))),
7425
return('Word', [$found, $lineNrs{$inHandle}])
7426
if $_!~/^$special/ and /^(.+?)($special|($))/;
7427
}
7428
7429
# reply next token: scan for word or single character (declared as "Word" as well)
7430
$found=$1, s/^\Q$1//,
7431
(($flags{trace} & TRACE_LEXER) and warn(qq([Trace] Lexer: Word "$found" in line $lineNrs{$inHandle}.\n))),
7432
return('Word', [$found, $lineNrs{$inHandle}]) if /^($patternWUmlauts)/ or /^(\S)/;
7433
7434
# everything should be handled - this code should never be executed!
7435
die qq([BUG] $sourceFile, line $lineNrs{$inHandle}: No symbol found in "$_"!\n);
7436
}
7437
}
7438
7439
7440
# evaluate a tag condition (can possibly be generalized: this is just a piece of code)
7441
sub _evalTagCondition
7442
{
7443
# get parameters
7444
my ($code, $file, $line)=@_;
7445
confess "[BUG] Missing code parameter.\n" unless defined $code;
7446
confess "[BUG] Missing file parameter.\n" unless defined $file;
7447
confess "[BUG] Missing line parameter.\n" unless defined $line;
7448
7449
# declare variables
7450
my ($rc);
7451
7452
# Does the caller want to evaluate the code?
7453
if ($safeObject)
7454
{
7455
# update active contents base data, if necessary
7456
if ($flags{activeBaseData})
7457
{
7458
no strict 'refs';
7459
${join('::', ref($safeObject) ? $safeObject->root : 'main', 'PerlPoint')}=dclone($flags{activeBaseData});
7460
}
7461
7462
# make the code a string and evaluate it
7463
warn "[Trace] $sourceFile, line $line: Evaluating this code:\n\n$code\n\n\n" if $flags{trace} & TRACE_ACTIVE;
7464
7465
# invoke perl to compute the result
7466
$rc=ref($safeObject) ? $safeObject->reval($code) : eval(join(' ', '{package main; no strict;', $code, '}'));
7467
7468
# check result
7469
_semerr($_[0], "$file, line $line: tag condition could not be evaluated: $@.") if $@;
7470
}
7471
7472
# supply result
7473
$rc;
7474
}
7475
7476
# reference lexed: reply appropriate token
7477
sub _refLexed
7478
{
7479
# get parameters
7480
my ($parser)=@_;
7481
7482
# we got an already prepared stream part or a delayed token
7483
if (ref($parser->{USER}->{INPUT}) eq 'PerlPoint::Parser::DelayedToken')
7484
{
7485
my $delayedToken=$parser->{USER}->{INPUT};
7486
$parser->{USER}->{INPUT}='';
7487
return($delayedToken->token, $delayedToken->value);
7488
}
7489
else
7490
{
7491
my $streamedPart=$parser->{USER}->{INPUT};
7492
$parser->{USER}->{INPUT}='';
7493
return('StreamedPart', [$streamedPart, $lineNrs{$inHandle}]);
7494
}
7495
}
7496
7497
7498
sub _lineStartResearch
7499
{
7500
# get parameters
7501
my ($parser)=@_;
7502
7503
# scan for indented lines, if necessary
7504
if ($parser->{USER}->{INPUT}=~/^(\s+)/)
7505
{
7506
if ($lexerFlags{ils}==LEXER_TOKEN)
7507
{
7508
# trace, if necessary
7509
warn "[Trace] Lexer: Ils in line $lineNrs{$inHandle}.\n" if $flags{trace} & TRACE_LEXER;
7510
7511
# update input buffer and reply the token (contents is necessary as well)
7512
my $ils=$1;
7513
$parser->{USER}->{INPUT}=~s/^$1//;
7514
return(1, 'Ils', [$ils, $lineNrs{$inHandle}]);
7515
}
7516
elsif ($lexerFlags{ils}==LEXER_IGNORE)
7517
{
7518
warn "[Trace] Lexer: Ils in line $lineNrs{$inHandle} is ignored.\n" if $flags{trace} & TRACE_LEXER;
7519
$parser->{USER}->{INPUT}=~s/^(\s+)//;
7520
}
7521
}
7522
7523
# scan for a need of a virtual token opening a new paragraph
7524
# (to avoid parser state trouble caused by filters when the parser needs a lookahead
7525
# to detect the next paragraph)
7526
# warn "------> state $parserState (", STATE_DEFAULT, "), flag $flags{virtualParagraphStart}, $lexerFlagsOfPreviousState{cbell}\n";
7527
if ($parserState==STATE_DEFAULT and $flags{virtualParagraphStart} and $lexerFlagsOfPreviousState{cbell} ne LEXER_IGNORE)
7528
{
7529
warn "[Trace] Inserted virtual token to enable clean parser lookahead after pfilter invokation.\n" if $flags{trace} & TRACE_LEXER;
7530
return(1, 'Word', ['', $lineNrs{$inHandle}])
7531
if $lexerFlagsOfPreviousState{cbell} eq 'Ils'
7532
or $parser->{USER}->{INPUT}!~/^$lexerFlagsOfPreviousState{cbell}/;
7533
}
7534
7535
# scan for a new paragraph opened by a tag, if necessary
7536
if (($parserState==STATE_DEFAULT or $parserState==STATE_PFILTERED) and $parser->{USER}->{INPUT}=~/^\\/)
7537
{
7538
# remain in default state, but switch to its tag mode
7539
_stateManager(STATE_DEFAULT_TAGMODE);
7540
}
7541
7542
# flag that there is no token to return
7543
0;
7544
}
7545
7546
# ----------------------------------------------------------------------------------------------
7547
# Internal function: error message display.
7548
# ----------------------------------------------------------------------------------------------
7549
sub _Error
7550
{
7551
# get parameters
7552
my ($parser)=@_;
7553
7554
# declare base indention
7555
my $baseIndentation=' ' x length('[Error] ');
7556
7557
# use $_[0]->YYCurtok to display the recognized *token* if necessary
7558
# - for users convenience, it is suppressed in the message
7559
warn "\n\n[Error] $sourceFile, ",
7560
${$parser->YYCurval}[1] > 0 ? "line ${$parser->YYCurval}[1]" : 'all sources read',
7561
(exists $statistics{cache} and $statistics{cache}[1]) ? ' (or below because of cache hits)'
7562
: (),
7563
': found ',
7564
defined ${$parser->YYCurval}[0] ? qq("${$parser->YYCurval}[0]") : 'nothing',
7565
", expected:\n$baseIndentation",
7566
' ' x length('or '),
7567
join("\n${baseIndentation}or ",
7568
map {
7569
exists $tokenDescriptions{$_} ? defined $tokenDescriptions{$_} ? $tokenDescriptions{$_}
7570
: ()
7571
: $_
7572
} sort grep($_!~/cache_hit$/, $parser->YYExpect)
7573
),
7574
".\n\n";
7575
7576
# visualize error position
7577
warn(
7578
(map {my $l=$_->[1]; chomp($l); "$baseIndentation$l\n"} reverse @inLine==1 ? @inLine : @inLine[0, -1]), "",
7579
$baseIndentation, ' ' x ($inLine[0][0]-length($parser->{USER}->{INPUT})-1), "^\n",
7580
$baseIndentation, '_' x ($inLine[0][0]-length($parser->{USER}->{INPUT})-1), '|', "\n\n\n"
7581
) if @inLine;
7582
}
7583
7584
# ----------------------------------------------------------------------------------------------
7585
# Internal function: state manager.
7586
# ----------------------------------------------------------------------------------------------
7587
sub _stateManager
7588
{
7589
# get parameter
7590
my ($newState)=@_;
7591
7592
# check parameter
7593
confess "[BUG] Invalid new state $newState passed.\n" unless $newState==STATE_DEFAULT
7594
or $newState==STATE_DEFAULT_TAGMODE
7595
or $newState==STATE_TEXT
7596
or $newState==STATE_UPOINT
7597
or $newState==STATE_OPOINT
7598
or $newState==STATE_DPOINT
7599
or $newState==STATE_DPOINT_ITEM
7600
or $newState==STATE_BLOCK
7601
or $newState==STATE_VERBATIM
7602
or $newState==STATE_EMBEDDING
7603
or $newState==STATE_PFILTER
7604
or $newState==STATE_PFILTERED
7605
or $newState==STATE_CONDITION
7606
or $newState==STATE_HEADLINE_LEVEL
7607
or $newState==STATE_HEADLINE
7608
or $newState==STATE_TABLE
7609
or $newState==STATE_DEFINITION
7610
or $newState==STATE_CONTROL
7611
or $newState==STATE_COMMENT;
7612
7613
# store the new state
7614
$parserState=$newState;
7615
7616
# enter new state: default
7617
$newState==STATE_DEFAULT and do
7618
{
7619
# buffer last states lexer flags (take care of a clean init)
7620
%lexerFlagsOfPreviousState=%lexerFlags ? %lexerFlags : (cbell => LEXER_IGNORE);
7621
7622
# prepare lexer
7623
@lexerFlags{qw(ils eol el cbell)}=(LEXER_TOKEN, LEXER_EMPTYLINE, LEXER_IGNORE, LEXER_IGNORE);
7624
7625
# activate special characters as necessary
7626
@specials{('.', '/', '*', '#', '=', '<', '>', '{', '}' , '-', '?', '@', '+', '~', 'heredoc', 'colon', 'tag', 'embedded', 'number', 'pfilter')}=(1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1);
7627
7628
# trace, if necessary
7629
warn "[Trace] Entered default state.\n" if $flags{trace} & TRACE_SEMANTIC;
7630
7631
# well done
7632
return;
7633
};
7634
7635
# enter new state: paragraph filter installation
7636
$newState==STATE_PFILTER and do
7637
{
7638
# prepare lexer
7639
@lexerFlags{qw(ils eol el cbell)}=(LEXER_TOKEN, LEXER_EMPTYLINE, LEXER_IGNORE, LEXER_IGNORE);
7640
7641
# activate special characters as necessary
7642
@specials{('.', '/', '*', '#', '=', '<', '>', '{', '}' , '-', '?', '@', '+', '~', 'heredoc', 'colon', 'tag', 'embedded', 'number', 'pfilter')}=(1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1);
7643
7644
# trace, if necessary
7645
warn "[Trace] Entered pfilter installation state.\n" if $flags{trace} & TRACE_SEMANTIC;
7646
7647
# well done
7648
return;
7649
};
7650
7651
# enter new state: paragraph filter (similar to default except for the name)
7652
$newState==STATE_PFILTERED and do
7653
{
7654
# prepare lexer
7655
@lexerFlags{qw(ils eol el cbell)}=(LEXER_TOKEN, LEXER_EMPTYLINE, LEXER_IGNORE, LEXER_IGNORE);
7656
7657
# activate special characters as necessary
7658
@specials{('.', '/', '*', '#', '=', '<', '>', '{', '}' , '-', '?', '@', '+', '~', 'heredoc', 'colon', 'tag', 'embedded', 'number', 'pfilter')}=(1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1);
7659
7660
# trace, if necessary
7661
warn "[Trace] Entered postfilter default state.\n" if $flags{trace} & TRACE_SEMANTIC;
7662
7663
# well done
7664
return;
7665
};
7666
7667
7668
# enter new state: default in tag mode (same as default, but a paragraph starting with a tag delays switching to other
7669
# modes, so we have to explicitly disable the paragraph opener specials)
7670
$newState==STATE_DEFAULT_TAGMODE and do
7671
{
7672
# prepare lexer
7673
@lexerFlags{qw(ils eol el cbell)}=(LEXER_TOKEN, LEXER_EMPTYLINE, LEXER_IGNORE, LEXER_IGNORE);
7674
7675
# activate special characters as necessary
7676
@specials{('.', '/', '*', '#', '=', '<', '>', '{', '}' , '-', '?', '@', '+', '~', 'heredoc', 'colon', 'tag', 'embedded', 'number', 'pfilter')}=(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0);
7677
7678
# trace, if necessary
7679
warn "[Trace] Entered default state in tag mode.\n" if $flags{trace} & TRACE_SEMANTIC;
7680
7681
# well done
7682
return;
7683
};
7684
7685
# enter new state: headline body
7686
($newState==STATE_HEADLINE or $newState==STATE_HEADLINE_LEVEL) and do
7687
{
7688
# prepare lexer
7689
@lexerFlags{qw(ils eol el cbell)}=(LEXER_IGNORE, LEXER_SPACE, LEXER_TOKEN, LEXER_IGNORE);
7690
7691
# activate special characters as necessary
7692
@specials{('.', '/', '*', '#', '=', '<', '>', '{', '}' , '-', '?', '@', '+', '~', 'heredoc', 'colon', 'tag', 'embedded', 'number', 'pfilter')}=(0, 0, 0, 0, $newState==STATE_HEADLINE ? 0 : 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0);
7693
7694
# trace, if necessary
7695
warn "[Trace] Entered headline ", $newState==STATE_HEADLINE ? 'body' : 'level', " state.\n" if $flags{trace} & TRACE_SEMANTIC;
7696
7697
# well done
7698
return;
7699
};
7700
7701
# enter new state: comment
7702
$newState==STATE_COMMENT and do
7703
{
7704
# prepare lexer
7705
@lexerFlags{qw(ils eol el cbell)}=(LEXER_IGNORE, LEXER_EMPTYLINE, LEXER_IGNORE, LEXER_IGNORE);
7706
7707
# activate special characters as necessary
7708
@specials{('.', '/', '*', '#', '=', '<', '>', '{', '}' , '-', '?', '@', '+', '~', 'heredoc', 'colon', 'tag', 'embedded', 'number', 'pfilter')}=(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
7709
7710
# trace, if necessary
7711
warn "[Trace] Entered comment state.\n" if $flags{trace} & TRACE_SEMANTIC;
7712
7713
# well done
7714
return;
7715
};
7716
7717
# enter new state: text
7718
$newState==STATE_TEXT and do
7719
{
7720
# prepare lexer
7721
@lexerFlags{qw(ils eol el cbell)}=(LEXER_IGNORE, LEXER_SPACE, LEXER_TOKEN, LEXER_IGNORE);
7722
7723
# activate special characters as necessary
7724
@specials{('.', '/', '*', '#', '=', '<', '>', '{', '}' , '-', '?', '@', '+', '~', 'heredoc', 'colon', 'tag', 'embedded', 'number', 'pfilter')}=(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0);
7725
7726
# trace, if necessary
7727
warn "[Trace] Entered text state.\n" if $flags{trace} & TRACE_SEMANTIC;
7728
7729
# well done
7730
return;
7731
};
7732
7733
# enter new state: text
7734
$newState==STATE_TABLE and do
7735
{
7736
# prepare lexer
7737
@lexerFlags{qw(ils eol el cbell)}=(LEXER_SPACE, LEXER_TOKEN, LEXER_TOKEN, LEXER_IGNORE);
7738
7739
# activate special characters as necessary
7740
@specials{('.', '/', '*', '#', '=', '<', '>', '{', '}' , '-', '?', '@', '+', '~', 'heredoc', 'colon', 'tag', 'embedded', 'number', 'pfilter')}=(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0);
7741
7742
# trace, if necessary
7743
warn "[Trace] Entered table paragraph state.\n" if $flags{trace} & TRACE_SEMANTIC;
7744
7745
# well done
7746
return;
7747
};
7748
7749
# enter new state: text
7750
$newState==STATE_DEFINITION and do
7751
{
7752
# prepare lexer
7753
@lexerFlags{qw(ils eol el cbell)}=(LEXER_IGNORE, LEXER_SPACE, LEXER_TOKEN, LEXER_IGNORE);
7754
7755
# activate special characters as necessary
7756
@specials{('.', '/', '*', '#', '=', '<', '>', '{', '}' , '-', '?', '@', '+', '~', 'heredoc', 'colon', 'tag', 'embedded', 'number', 'pfilter')}=(0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0);
7757
7758
# trace, if necessary
7759
warn "[Trace] Entered macro definition state.\n" if $flags{trace} & TRACE_SEMANTIC;
7760
7761
# well done
7762
return;
7763
};
7764
7765
# enter new state: unordered list point - defined item
7766
($newState==STATE_DPOINT_ITEM) and do
7767
{
7768
# prepare lexer
7769
@lexerFlags{qw(ils eol el cbell)}=(LEXER_IGNORE, LEXER_SPACE, LEXER_TOKEN, LEXER_TOKEN);
7770
7771
# activate special characters as necessary
7772
@specials{('.', '/', '*', '#', '=', '<', '>', '{', '}' , '-', '?', '@', '+', '~', 'heredoc', 'colon', 'tag', 'embedded', 'number', 'pfilter')}=(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0);
7773
7774
# trace, if necessary
7775
warn "[Trace] Entered definition item state.\n" if $flags{trace} & TRACE_SEMANTIC;
7776
7777
# well done
7778
return;
7779
};
7780
7781
# enter new state: list point
7782
($newState==STATE_UPOINT or $newState==STATE_OPOINT or $newState==STATE_DPOINT) and do
7783
{
7784
# prepare lexer
7785
@lexerFlags{qw(ils eol el cbell)}=(LEXER_IGNORE, LEXER_SPACE, LEXER_TOKEN, qr([*#:]));
7786
7787
# activate special characters as necessary
7788
@specials{('.', '/', '*', '#', '=', '<', '>', '{', '}' , '-', '?', '@', '+', '~', 'heredoc', 'colon', 'tag', 'embedded', 'number', 'pfilter')}=(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0);
7789
7790
# trace, if necessary
7791
warn "[Trace] Entered point state.\n" if $flags{trace} & TRACE_SEMANTIC;
7792
7793
# well done
7794
return;
7795
};
7796
7797
# enter new state: block
7798
$newState==STATE_BLOCK and do
7799
{
7800
# prepare lexer
7801
@lexerFlags{qw(ils eol el cbell)}=(LEXER_SPACE, LEXER_TOKEN, LEXER_TOKEN, 'Ils');
7802
7803
# activate special characters as necessary
7804
@specials{('.', '/', '*', '#', '=', '<', '>', '{', '}' , '-', '?', '@', '+', '~', 'heredoc', 'colon', 'tag', 'embedded', 'number', 'pfilter')}=(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0);
7805
7806
# trace, if necessary
7807
warn "[Trace] Entered block state.\n" if $flags{trace} & TRACE_SEMANTIC;
7808
7809
# well done
7810
return;
7811
};
7812
7813
# enter new state: verbatim block
7814
$newState==STATE_VERBATIM and do
7815
{
7816
# prepare lexer
7817
@lexerFlags{qw(ils eol el cbell)}=(LEXER_SPACE, LEXER_TOKEN, LEXER_TOKEN, LEXER_IGNORE);
7818
7819
# activate special characters as necessary
7820
@specials{('.', '/', '*', '#', '=', '<', '>', '{', '}' , '-', '?', '@', '+', '~', 'heredoc', 'colon', 'tag', 'embedded', 'number', 'pfilter')}=(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0);
7821
7822
# trace, if necessary
7823
warn "[Trace] Entered verbatim state.\n" if $flags{trace} & TRACE_SEMANTIC;
7824
7825
# well done
7826
return;
7827
};
7828
7829
# enter new state: embedding
7830
$newState==STATE_EMBEDDING and do
7831
{
7832
# prepare lexer
7833
@lexerFlags{qw(ils eol el cbell)}=(LEXER_SPACE, LEXER_TOKEN, LEXER_TOKEN, LEXER_IGNORE);
7834
7835
# activate special characters as necessary
7836
@specials{('.', '/', '*', '#', '=', '<', '>', '{', '}' , '-', '?', '@', '+', '~', 'heredoc', 'colon', 'tag', 'embedded', 'number', 'pfilter')}=(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0);
7837
7838
# trace, if necessary
7839
warn "[Trace] Entered embedding state.\n" if $flags{trace} & TRACE_SEMANTIC;
7840
7841
# well done
7842
return;
7843
};
7844
7845
# enter new state: condition (very similar to embedding, naturally)
7846
$newState==STATE_CONDITION and do
7847
{
7848
# prepare lexer
7849
@lexerFlags{qw(ils eol el cbell)}=(LEXER_SPACE, LEXER_SPACE, LEXER_TOKEN, LEXER_IGNORE);
7850
7851
# activate special characters as necessary
7852
@specials{('.', '/', '*', '#', '=', '<', '>', '{', '}' , '-', '?', '@', '+', '~', 'heredoc', 'colon', 'tag', 'embedded', 'number', 'pfilter')}=(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
7853
7854
# trace, if necessary
7855
warn "[Trace] Entered condition state.\n" if $flags{trace} & TRACE_SEMANTIC;
7856
7857
# well done
7858
return;
7859
};
7860
7861
# enter new state: unordered list point
7862
$newState==STATE_CONTROL and do
7863
{
7864
# prepare lexer
7865
@lexerFlags{qw(ils eol el cbell)}=(LEXER_IGNORE, LEXER_IGNORE, LEXER_TOKEN, LEXER_IGNORE);
7866
7867
# activate special characters as necessary
7868
@specials{('.', '/', '*', '#', '=', '<', '>', '{', '}' , '-', '?', '@', '+', '~', 'heredoc', 'colon', 'tag', 'embedded', 'number', 'pfilter')}=(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
7869
7870
# trace, if necessary
7871
warn "[Trace] Entered control state.\n" if $flags{trace} & TRACE_SEMANTIC;
7872
7873
# well done
7874
return;
7875
};
7876
7877
# check yourself
7878
confess "[BUG] Unhandled state $newState.\n";
7879
}
7880
7881
7882
=pod
7883
7884
=head2 run()
7885
7886
This function starts the parser to process a number of specified files.
7887
7888
B
7889
All parameters except of the I parameter are named (pass them by hash).
7890
7891
=over 4
7892
7893
=item activeBaseData
7894
7895
This optional parameter allows to pass common data to all active contents
7896
(conditions, embedded and included Perl) by a I. By convention,
7897
a translator at least passes the target language and user settings by
7898
7899
activeBaseData => {
7900
targetLanguage => "lang",
7901
userSettings => \%userSettings,
7902
},
7903
7904
User settings are intended to allow the specification of per call settings by a
7905
user, e.g. to include special parts. By using this convention, users can easily
7906
specify such a part the following way
7907
7908
? flagSet('setting')
7909
7910
Special part.
7911
7912
? 1
7913
7914
It is up to a translator author to declare translator specific settings (and to
7915
document them). The passed values can be as complex as necessary as long as they
7916
can be duplicated by C.
7917
7918
Whenever active contents is invoked, the passed hash reference is copied
7919
(duplicated by C) into the Safe objects namespace
7920
(see I) as a global variable $PerlPoint. This way, modifications by
7921
invoked code do not effect subsequently called code snippets, base data are
7922
always fresh.
7923
7924
=item activeDataInit
7925
7926
Reserved to pass hook functions to be called preparing every active contents
7927
invokation. I
7928
7929
=item cache
7930
7931
This optional parameter controls source file paragraph caching.
7932
7933
By default, a source file is parsed completely everytime you pass it to the
7934
parser. This is no problem with tiny sources but can delay your work if you
7935
are dealing with large sources which have to be translated periodically into
7936
presentations while they are written. Typically most of the paragraphs remain
7937
unchanged from version to version, but nevertheless everything is usually
7938
reparsed which means a waste of time. Well, to improve this a paragraph
7939
cache can be activated by setting this option to B.
7940
7941
The parser caches each I individually. That means
7942
if three files are passed to the parser with activated caching, three cache
7943
files will be written. They are placed in the source file directory, named
7944
..ppcache. Please note that the paragraphs of I sources
7945
are cached in the cache file of the I document because they may have to
7946
be evaluated differently depending on inclusion context.
7947
7948
What acceleration can be expected? Well, this I
7949
depends on your source structure. Efficiency will grow with longer paragraphs,
7950
reused paragraphs and paragraph number. It will be reduced by heavy usage
7951
of active contents and embedding because every paragraph that refers
7952
to parts defined externally is not strongly determined by itself and therefore
7953
it cannot be cached. Here is a list of all reasons which cause a paragraph to
7954
be excluded from caching:
7955
7956
=over 4
7957
7958
=item Embedded parts
7959
7960
Obviously dynamic parts may change from one version to another, but even static
7961
parts could have to be interpreted differently because a user can set up new
7962
Is.
7963
7964
=item Included files
7965
7966
An \INCLUDE tag immediately disables caching for the paragraph it resides in
7967
because the loaded file may change its contents. This is not really a
7968
restriction because the included paragraphs themselves I cached if possible.
7969
7970
=item Filtered paragraphs
7971
7972
A paragraph filter can transform a source paragraph in whatever the author of
7973
a Perl function might think is useful, potentially depending on highly dynamical
7974
data. So it cannot be determined by the parser what the final translation of a
7975
certain source paragraph will be.
7976
7977
=item Document stream entry points
7978
7979
Depending on the parsers configuration, these points can be transformed into
7980
headlines or remain unchanged, so there is no fixed up mapping between a
7981
source paragraph and its streamed expression.
7982
7983
=back
7984
7985
Even with these restrictions about 70% of a real life document of more than
7986
150 paragraphs could be cached. This saved more than 60% of parsing time in
7987
subsequent translator calls.
7988
7989
New cache entries are always I which means that old entries are never
7990
replaced and a cache file tends to grow. If you ever wish to clean up a
7991
cache file completely pass B to this option.
7992
7993
To deactivate caching explicitly pass B.
7994
I
7995
7996
Settings can be combined by I.
7997
7998
# clean up the cache, then refill it
7999
cache => CACHE_CLEANUP+CACHE_ON,
8000
8001
# clean up the cache and deactivate it
8002
cache => CACHE_CLEANUP+CACHE_OFF,
8003
8004
The B value is overwritten by any other setting.
8005
8006
It is suggested to make this setting available to translator users to let
8007
them decide if a cache should be used.
8008
8009
I that there is a problem with line numbers if paragraphs are
8010
restored from cache because of the behaviour of perls paragraph mode. In this
8011
mode, the <> operator reads in any number of newlines between paragraphs but
8012
supplies only one of them. That is why I do not get the real number of lines
8013
in a paragraph and therefore cannot store them. To work around this, two
8014
strategies can be used. First, do not use more than exactly one newline
8015
between paragraphs. (This strategy is not for real life users, of course,
8016
but in this case restored numbers would be correct.) Second, remember that
8017
source line numbers are only interesting in error messages. If the parser
8018
detects an error, it therefore says: error "there or later" when a cache hit
8019
already occured. If the real number is wished the parser could be reinvoked
8020
then with deactivated cache and will report it.
8021
8022
I occurs if you parse on a UNIX
8023
system but your document (or parts of it) were written in DOS format. The
8024
paragraph mode reads such a document I. Please replace the line
8025
ending character sequences system appropriate. (If you are using C
8026
under Solaris please invoke it with option C<-ascii> to do this.)
8027
8028
More, Perls paragraph mode and PerlPoint treat whitespace lines differently.
8029
Because of the way it works, paragraph mode does not recognize them as "empty"
8030
while PerlPoint I for reasons of usability (invisible characters should
8031
not make a difference). This means that lines containing only whitespaces
8032
separate PerlPoint paragraphs but not "Perl" paragraphs, making the cache
8033
working wrong especially in examples. If paragraphs unintentionally disappear
8034
in the resulting presentation, please check the "empty lines" before them.
8035
8036
Consistent cache data depend on the versions of the parser, of constant
8037
declarations and of the module B which is used internally. If the
8038
parser detects a significant change in one of these versions, existing
8039
caches are automatically rebuilt.
8040
8041
I cache files are not locked while they are used.
8042
If you need this feature please let me know.
8043
8044
=item criticalSemanticErrors
8045
8046
If set to a true value, semantic errors will cause the parser to terminate
8047
immediately. This defaults to false: errors are accumulated and finally
8048
reported.
8049
8050
=item display
8051
8052
This parameter is optional. It controls the display of runtime messages
8053
like informations or warnings. By default, all messages are displayed. You
8054
can suppress these informations partially or completely by passing one or
8055
more of the "DISPLAY_..." variables declared in B.
8056
Constants should be combined by addition.
8057
8058
=item docstreams2skip
8059
8060
by default, all document streams are made part of the result, but by this
8061
parameter one can I certain streams (all remaining ones will be
8062
streamed as usual).
8063
8064
The list should be supplied by an array reference.
8065
8066
It is suggested to take the values of this parameter from a user option,
8067
which by convention should be named C<-skipstream>.
8068
8069
=item docstreaming
8070
8071
specifies the way the parser handles stream entry points. The value passed
8072
might be either C, C or C.
8073
8074
C instructs the parser to transform the entry points
8075
into I, one level below the current real headline level. This
8076
is an easy to implement and convenient way of docstream handling seems to
8077
make sense in most target formats.
8078
8079
C hides all streams except of the main stream. The effect
8080
is similar to a call with I set for all document streams
8081
in a source.
8082
8083
C treats the entry points as entry points and streams
8084
them as such. This is the default if the parameter is omitted.
8085
8086
Please note that filters applied by I work regardless of
8087
the I configuration which only affects the way the parser
8088
passes docstream data to a backend.
8089
8090
It is recommended to take the value of this parameter from a user option,
8091
which by convention should be named C<-docstreaming>. (A converter can
8092
define various more modes than provided by the parser and implement them
8093
itself, of course. See C for a reference implementation.)
8094
8095
8096
=item files
8097
8098
a reference to an array of files to be scanned.
8099
8100
Files are treated as PerlPoint sources except when their name has the
8101
prefix C, as in C. With this prefix, the
8102
parser tries to automatically tranform the source into PerlPoint,
8103
using a standard import filter for the format indicated by the file
8104
extension (C in our example). The filter must be installed as
8105
Cuppercased format nameE>, e.g.
8106
C.
8107
8108
=item filter
8109
8110
a regular expression describing the target language. This setting, if used,
8111
prevents all embedded or included source code of other languages than the set
8112
one from inclusion into the generated stream. This accelerates both parsing
8113
and backend handling. The pattern is evaluated case insensitively.
8114
8115
Example: pass "html|perl" to allow HTML and Perl.
8116
8117
To illustrate this, imagine a translator to PostScript. If it reads a Perl
8118
Point file which includes native HTML, this translator cannot handle such code.
8119
The backend would have to skip the HTML statements. With a "PostScript" filter,
8120
the HTML code will not appear in the stream.
8121
8122
This enables PerlPoint texts prepared for various target languages. If an
8123
author really needs plain target language code to be embedded into PerlPoint,
8124
he could provide versions for various languages. Translators using a filter
8125
will then receive exactly the code of their target language, if provided.
8126
8127
Please note that you cannot filter out PerlPoint code or example files.
8128
8129
By default, no filter is set.
8130
8131
8132
=item headlineLinks
8133
8134
this optional flag causes the parser to register all headline
8135
titles as anchors automatically. (Headlines are stored without
8136
possibly included tags which are stripped off.)
8137
8138
Registering anchors does \I mean there are anchors included
8139
to the stream, it just means that they are known to exist at
8140
parsing time because they are added to an internal C
8141
object which is passed to all tag hooks and can be evaluated there.
8142
See \C and C for details.
8143
8144
It is recommended to make use of this feature if your converter
8145
automatically makes headlines an anchor named like the headline
8146
(this feature was introduced by Lorenz Domkes C initially).
8147
(Nevertheless, usefulness may depend on dealing with the parsers
8148
anchor collection in tag hooks. See the documentations of used
8149
tag modules for details.)
8150
8151
If your converter does not support automatic headline anchors
8152
the mentioned way, it is recommended to omit this option because
8153
it could confuse tag hooks that evaluate the parsers anchor collection.
8154
8155
8156
=item libpath
8157
8158
An optional reference to an array of library pathes to be searched for
8159
files specified by \INCLUDE tags. This array is intended to be filled
8160
by directories specified via an converter option. By convention, this
8161
option is named C and should be enabled multiple times
8162
(C).
8163
8164
Please note that library pathes can be set via environment variable
8165
C as well, but directories specified via C are
8166
searched I.
8167
8168
8169
=item linehints
8170
8171
If set to a true value, the parser will embed line hints into the stream
8172
whenever a new source line begins.
8173
8174
A line hint directive is provided as
8175
8176
[
8177
DIRECTIVE_NEW_LINE, DIRECTIVE_START,
8178
{file=>filename, line=>number}
8179
]
8180
8181
and is suggested to be handled by a backend callback.
8182
8183
Please note that currently source line numbers are not guaranteed to be
8184
correct if stream parts are restored from I (see there for details).
8185
8186
The default value is 0.
8187
8188
=item nestedTables
8189
8190
This is an optional flag which is by default set to 0, indicating if the parser
8191
shall accept nested tables or not. Table nesting can produce very nice results
8192
if it is supported by the target language. HTML, for example, allows to nest
8193
tables, but other languages I. So, using this feature can really improve
8194
the results if a user is focussed on supporting certain target formats only. If I want
8195
to produce nothing but HTML, why should I take care of target formats not able
8196
to handle table nesting? On the other hand, I a document shall be translated
8197
into several formats, it might cause trouble to nest tables therein.
8198
8199
Because of this, it is suggested to let converter users decide if they want to
8200
enable table nesting or not. If the target format does not support nesting, I
8201
recommend to disable nesting completely.
8202
8203
8204
=item object
8205
8206
the parser object made by I;
8207
8208
=item safe
8209
8210
an object of the B class which comes with perl. It is used to evaluate
8211
embedded Perl code in a safe environment. By letting the caller of I
8212
provide this object, a translator author can make the level of safety fully
8213
configurable by users. Usually, the following should work
8214
8215
use Safe;
8216
...
8217
$parser->run(safe=>new Safe, ...);
8218
8219
Safe is a really good module but unfortunately limited in loading modules
8220
transparently. So if a user wants to use modules in his embedded code, he
8221
might fail to get it working in a Safe compartment. If safety does not matter,
8222
he can decide to execute it without Safe, with full Perl access. To switch
8223
on this mode, pass a true scalar value (but no reference) instead of a Safe
8224
object.
8225
8226
To make all PerlPoint converters behave similarly, it is recommended to provide
8227
two related options C<-activeContents> and C<-safeOpcode>. C<-activeContents>
8228
should flag that active contents shall be evaluated, while C<-safeOpcode>
8229
controls the level of security. A special level C should mean that all
8230
code can b executed without any restriction, while any other settings should be
8231
treated as an opcode to configure the Safe object. So, the recommended rules
8232
are: pass 0 unless C<-activeContents> is set. Pass 1 if the converter was
8233
called with C<-activeContents> I C<-safeOpcode ALL>. Pass a Safe object
8234
and configure it according to the users C<-safeOpcode> settings if
8235
C<-activeContents> is used but without C<-safeOpcode ALL>. See C
8236
for an implementation example.
8237
8238
Active Perl contents is I if this setting is omitted or if anything
8239
else than a B object is passed. (There are currently three types of active
8240
contents: embedded or included Perl and condition paragraphs.)
8241
8242
8243
=item predeclaredVars
8244
8245
Variables are usually set by assignment paragraphs. However, it may be useful
8246
for a converter to predeclare a set of them to provide certain settings to the
8247
users. Predeclared variables, as any other PerlPoint variables, can be used
8248
both in pure PerlPoint and in active contents. To help users distinguish them
8249
from user defined vars, their names will be I.
8250
8251
Just pass a hash of variable name / value pairs:
8252
8253
$parser->run(
8254
...
8255
predeclaredVars => {
8256
CONVERTER_NAME => 'pp2xy',
8257
CONVERTER_VERSION => $VERSION,
8258
...
8259
},
8260
);
8261
8262
Non capitalized variable names will be capitalized without further notice.
8263
8264
Please note that variables currently can only be scalars. Different data types
8265
will not be accepted by the parser.
8266
8267
Predeclared variables should be mentioned in the converters documentation.
8268
8269
The parser itself makes use of this feature by declaring C<_PARSER_VERSION>
8270
(the version of this module used to parse the source) and _STARTDIR (the full
8271
path of the startup directory, as reported by C).
8272
8273
C needs C to take effect.
8274
8275
8276
=item skipcomments
8277
8278
By default comments are streamed and can be converted into comments of the target language.
8279
But often they are of limited use in generated files: especially if they are intended to
8280
help the author of a document, not the reader of the source of generated results. So with
8281
this option one can suppress comments from being streamed.
8282
8283
It is suggested to get this setting via user option,
8284
which by convention should be named C<-skipcomments>.
8285
8286
=item stream
8287
8288
A reference to an array where the generated output stream should be stored in.
8289
8290
Application programmers may want to tie this array if the target ASCII
8291
texts are expected to be large (long ASCII texts can result in large stream
8292
data which may occupy a lot of memory). Because of the fact that the parser
8293
stores stream data I, memory consumption can be reduced
8294
significantly by tying the stream array.
8295
8296
It is recommended to pass an empty array. Stored data will not be overwritten,
8297
the parser I its data instead (by C).
8298
8299
=item trace
8300
8301
This parameter is optional. It is intended to activate trace code while the method
8302
runs. You may pass any of the "TRACE_..." constants declared in B,
8303
combined by addition as in the following example:
8304
8305
# show the traces of both
8306
# lexical and syntactical analysis
8307
trace => TRACE_LEXER+TRACE_PARSER,
8308
8309
If you omit this parameter or pass TRACE_NOTHING, no traces will be displayed.
8310
8311
=item var2stream
8312
8313
If set to a true value, the parser will propagate variable settings into the stream
8314
by adding additional C directives.
8315
8316
A variable propagation has the form
8317
8318
[
8319
DIRECTIVE_VARSET, DIRECTIVE_START,
8320
{var=>varname, value=>value}
8321
]
8322
8323
and is suggested to be handled by a backend callback.
8324
8325
The default value is 0.
8326
8327
=item vispro
8328
8329
activates "process visualization" which simply means that a user will see
8330
progress messages while the parser processes documents. The I
8331
value of this setting determines how often the progress message shall be
8332
updated, by a I:
8333
8334
# inform every five chapters
8335
vispro => 5,
8336
8337
Process visualization is automatically suppressed unless STDERR is
8338
connected to a terminal, if this option is omitted, I was set
8339
to C or parser Is are activated.
8340
8341
=back
8342
8343
B
8344
A "true" value in case of success, "false" otherwise. A call is performed
8345
successfully if there was neither a syntactical nor a semantic error in the
8346
parsed files.
8347
8348
B
8349
8350
$parser->run(
8351
stream => \@streamData,
8352
files => \@ARGV,
8353
filter => 'HTML',
8354
cache => CACHE_ON,
8355
trace => TRACE_PARAGRAPHS,
8356
);
8357
8358
=cut
8359
sub run
8360
{
8361
# get parameters
8362
my ($me, @pars)=@_;
8363
8364
# build parameter hash
8365
confess "[BUG] The number of parameters should be even.\n" if @pars%2;
8366
my %pars=@pars;
8367
8368
# and check parameters
8369
confess "[BUG] Missing object parameter.\n" unless $me;
8370
confess "[BUG] Object parameter is no ", __PACKAGE__, " object.\n" unless ref $me and ref $me eq __PACKAGE__;
8371
confess "[BUG] Missing stream array reference parameter.\n" unless $pars{stream};
8372
confess "[BUG] Stream array reference parameter is no array reference.\n" unless ref $pars{stream} and ref $pars{stream} eq 'ARRAY';
8373
confess "[BUG] Missing file list reference parameter.\n" unless $pars{files};
8374
confess "[BUG] File list reference parameter is no array reference.\n" unless ref $pars{files} and ref $pars{files} eq 'ARRAY';
8375
confess "[BUG] You should pass at least one file to parse.\n" unless @{$pars{files}};
8376
confess "[BUG] Active base data reference is no hash reference.\n" if exists $pars{activeBaseData} and ref $pars{activeBaseData} ne 'HASH';
8377
confess "[BUG] Active data initializer is no code reference.\n" if exists $pars{activeDataInit} and ref $pars{activeDataInit} ne 'CODE';
8378
confess "[BUG] Document stream skip list is no array reference.\n" if exists $pars{docstreams2skip} and ref $pars{docstreams2skip} ne 'ARRAY';
8379
if (exists $pars{filter})
8380
{
8381
eval "'lang'=~/$pars{filter}/";
8382
confess qq([BUG] Invalid filter expression "$pars{filter}": $@.\n) if $@;
8383
}
8384
8385
# variables
8386
my ($rc, %docHints)=(1);
8387
8388
# init internal data
8389
(
8390
$resultStreamRef, # 1
8391
$safeObject, # 2
8392
$flags{trace}, # 3
8393
$flags{display}, # 4
8394
$flags{filter}, # 5
8395
$flags{linehints}, # 6
8396
$flags{var2stream}, # 7
8397
$flags{cache}, # 8
8398
$flags{cached}, # 9
8399
$flags{vis}, # 10
8400
$flags{activeBaseData}, # 11
8401
$flags{activeDataInit}, # 12
8402
$flags{nestedTables}, # 13
8403
$flags{headlineLinks}, # 14
8404
$flags{skipcomments}, # 15
8405
$flags{docstreams2skip}, # 16
8406
$flags{docstreaming}, # 17
8407
$flags{criticalSemantics}, # 18
8408
$macroChecksum, # 19
8409
$varChecksum, # 20
8410
$anchors, # 21
8411
)=(
8412
$pars{stream}, # 1
8413
( # 2
8414
exists $pars{safe}
8415
and defined $pars{safe}
8416
) ? ref($pars{safe}) eq 'Safe' ? $pars{safe}
8417
: 1
8418
: 0,
8419
exists $pars{trace} ? $pars{trace} : TRACE_NOTHING, # 3
8420
exists $pars{display} ? $pars{display} : DISPLAY_ALL, # 4
8421
exists $pars{filter} ? $pars{filter} : '', # 5
8422
(exists $pars{linehints} and $pars{linehints}), # 6
8423
(exists $pars{var2stream} and $pars{var2stream}), # 7
8424
exists $pars{cache} ? $pars{cache} : CACHE_OFF, # 8
8425
0, # 9
8426
exists $pars{vispro} ? $pars{vispro} : 0, # 10
8427
exists $pars{activeBaseData} ? $pars{activeBaseData} : 0, # 11
8428
exists $pars{activeDataInit} ? $pars{activeDataInit} : 0, # 12
8429
exists $pars{nestedTables} ? $pars{nestedTables} : 0, # 13
8430
exists $pars{headlineLinks} ? $pars{headlineLinks} : 0, # 14
8431
(exists $pars{skipcomments} and $pars{skipcomments}), # 15
8432
exists $pars{docstreams2skip} ? {map {($_ => undef)} @{$pars{docstreams2skip}}} : 0, # 16
8433
exists $pars{docstreaming} ? $pars{docstreaming} : DSTREAM_DEFAULT, # 17
8434
exists $pars{criticalSemanticErrors} ? $pars{criticalSemanticErrors} : 0, # 18
8435
0, # 19
8436
0, # 20
8437
PerlPoint::Anchors->new, # 21
8438
);
8439
8440
# prepare stream data structure and appropriate handlers
8441
unless (@$resultStreamRef and $resultStreamRef->[STREAM_IDENT] eq '__PerlPoint_stream__')
8442
{
8443
# empty stream
8444
@$resultStreamRef=();
8445
# initiate
8446
@{$resultStreamRef}[
8447
STREAM_IDENT,
8448
STREAM_TOKENS,
8449
STREAM_HEADLINES,
8450
]=(
8451
'__PerlPoint_stream__', # stream identifier;
8452
[], # base stream;
8453
[], # headline stream;
8454
);
8455
}
8456
8457
# declare helper subroutines to be used in active contents
8458
if ($safeObject)
8459
{
8460
my $code=<<'EOC';
8461
8462
unless (defined *main::flagSet{CODE})
8463
{
8464
# check if at least one of a set of flags is set
8465
# - define functions anonymously to avoid redefinition in case the condition is not matched
8466
*main::flagSet=sub
8467
{
8468
# declare and init variable
8469
my $rc=0;
8470
8471
# check flags
8472
foreach (@_)
8473
{$rc=1, last if exists $PerlPoint->{userSettings}{$_};}
8474
8475
# supply result
8476
$rc;
8477
};
8478
8479
# provide the value of a PerlPoint variable
8480
# - define function anonymously to avoid redefinition in case the condition is not matched
8481
*main::varValue=sub {${join('::', 'main', $_[0])};};
8482
}
8483
8484
# complete compartment code
8485
EOC
8486
8487
ref($safeObject) ? $safeObject->reval($code) : eval("{package main; no strict; $code}");
8488
die "[BUG] Bug in function definition, please inform developer: $@" if $@;
8489
}
8490
8491
# predeclare variables
8492
_predeclareVariables({_PARSER_VERSION=>$PerlPoint::Parser::VERSION, _STARTDIR=>cwd()});
8493
8494
# store initial variables, if necessary
8495
if (exists $pars{predeclaredVars})
8496
{
8497
# check data format
8498
confess "[BUG] Please pass predeclared variables by a hash reference .\n" unless ref($pars{predeclaredVars}) eq 'HASH';
8499
8500
# declare
8501
_predeclareVariables($pars{predeclaredVars});
8502
}
8503
8504
# update visualization flag
8505
$flags{vis}=0 unless $flags{vis}
8506
and not $flags{display} & &DISPLAY_NOINFO
8507
and not $flags{trace}>TRACE_NOTHING
8508
and -t STDERR;
8509
8510
# init more
8511
@flags{qw(skipInput headlineLevelOffset headlineLevel olist virtualParagraphStart)}=(0) x 5;
8512
delete $flags{ifilters};
8513
$statistics{cache}[1]=0 if $flags{cache} & CACHE_ON;
8514
8515
# init even more
8516
%paragraphTypeStrings=(
8517
DIRECTIVE_HEADLINE() => 'headline',
8518
DIRECTIVE_TEXT() => 'text',
8519
DIRECTIVE_UPOINT() => 'unordered list point',
8520
DIRECTIVE_ULIST() => 'list',
8521
DIRECTIVE_OPOINT() => 'ordered list point',
8522
DIRECTIVE_OLIST() => 'list',
8523
DIRECTIVE_DPOINT() => 'definition list point',
8524
DIRECTIVE_DLIST() => 'list',
8525
DIRECTIVE_BLOCK() => 'block',
8526
DIRECTIVE_VERBATIM() => 'verbatim block',
8527
DIRECTIVE_TAG() => 'tag',
8528
DIRECTIVE_LIST_RSHIFT() => 'right list shifter',
8529
DIRECTIVE_LIST_LSHIFT() => 'left list shifter',
8530
DIRECTIVE_COMMENT() => 'comment',
8531
);
8532
# check tag declarations
8533
unless (ref($PerlPoint::Tags::tagdefs) eq 'HASH')
8534
{
8535
# warn user
8536
warn "[Warn] No tags are declared. No tags will be detected.\n" unless $flags{display} & DISPLAY_NOWARN;
8537
8538
# init shortcut pointer
8539
$tagsRef={};
8540
}
8541
else
8542
{
8543
# ok, there are tags, make a shortcut
8544
$tagsRef=$PerlPoint::Tags::tagdefs;
8545
}
8546
8547
# build an array of include pathes - specified via environment variable PERLPOINTLIB
8548
# and parameter "libpath"
8549
confess "[BUG] Please pass library pathes by an array reference .\n" if exists $pars{libpath} and not ref($pars{libpath}) eq 'ARRAY';
8550
push(@libraryPath,
8551
exists $pars{libpath} ? @{$pars{libpath}} : (),
8552
exists $ENV{PERLPOINTLIB} ? split(/\s*;\s*/, $ENV{PERLPOINTLIB}) : (),
8553
);
8554
8555
# welcome user
8556
unless ($flags{display} & DISPLAY_NOINFO)
8557
{
8558
print STDERR "[Info] The PerlPoint parser ";
8559
{
8560
no strict 'refs';
8561
print STDERR ${join('::', __PACKAGE__, 'VERSION')};
8562
}
8563
warn " starts.\n";
8564
warn " Active contents is ", $safeObject ? ref($safeObject) ? 'safely evaluated' : 'risky evaluated' : 'ignored', ".\n";
8565
8566
# report cache mode
8567
warn " Paragraph cache is ", ($flags{cache} & CACHE_ON) ? '' : 'de', "activated.\n";
8568
}
8569
8570
# save current directory
8571
my $startupDirectory=cwd();
8572
8573
# scan all input files
8574
foreach my $file (@{$pars{files}})
8575
{
8576
# scopies
8577
my $specifiedFile=$file;
8578
8579
# scan for an import directive
8580
if ($file=~/^IMPORT:(.+)/)
8581
{
8582
# replace the original file by a temporary one ...
8583
my ($tmpHandle, $tmpFilename)=tempfile(UNLINK => ($flags{trace} & TRACE_TMPFILES ? 0 : 1));
8584
$file=$tmpFilename;
8585
8586
# which imports the real file
8587
my $realfile=abs_path($specifiedFile=$1);
8588
print $tmpHandle qq(\n\n\\INCLUDE{import=1 file="$realfile"}\n\n);
8589
close($tmpHandle);
8590
8591
# due to the extra level chances are we have to to accept a first paragraph that is not a headline
8592
$flags{complainedAbout1stHeadline}='IMPORT' unless exists $flags{complainedAbout1stHeadline} and $flags{complainedAbout1stHeadline} eq '1';
8593
}
8594
8595
# inform user
8596
warn "[Info] Processing $specifiedFile ...\n" unless $flags{display} & DISPLAY_NOINFO;
8597
8598
# init input stack
8599
@inputStack=([]);
8600
8601
# init nesting stack
8602
@nestedSourcefiles=($file);
8603
8604
# update source file nesting level hint
8605
_predeclareVariables({_SOURCE_LEVEL=>scalar(@nestedSourcefiles)});
8606
8607
# update file hint
8608
$sourceFile=$file;
8609
8610
# open file and make the new handle the parsers input
8611
open($inHandle, $file) or confess("[Fatal] Could not open input file $file.\n");
8612
binmode($inHandle);
8613
8614
# store the filename in the list of opened sources, to avoid circular reopening
8615
# (it would be more perfect to store the complete path, is there a module for this?)
8616
$openedSourcefiles{$file}=1;
8617
8618
# change into the source directory
8619
chdir(dirname($file));
8620
8621
# (cleanup and) read old checksums as necessary
8622
my $cachefile=sprintf(".%s.ppcache", basename($file));
8623
if (($flags{cache} & CACHE_CLEANUP) and -e $cachefile)
8624
{
8625
warn " Resetting paragraph cache for $specifiedFile.\n" unless $flags{display} & DISPLAY_NOINFO;
8626
unlink($cachefile);
8627
}
8628
if (($flags{cache} & CACHE_ON) and -e $cachefile)
8629
{
8630
$checksums=retrieve($cachefile) ;
8631
#use Data::Dumper; warn Dumper($checksums);
8632
8633
# clean up old format caches
8634
unless (
8635
exists $checksums->{sha1_base64('version')}
8636
and $checksums->{sha1_base64('version')}>=0.38
8637
8638
and exists $checksums->{sha1_base64('constants')}
8639
and $checksums->{sha1_base64('constants')}==$PerlPoint::Constants::VERSION
8640
8641
and exists $checksums->{sha1_base64('Storable')}
8642
and $checksums->{sha1_base64('Storable')}==$Storable::VERSION
8643
)
8644
{
8645
warn " Paragraph cache for $specifiedFile is rebuilt because of an old format.\n" unless $flags{display} & DISPLAY_NOINFO;
8646
unlink($cachefile);
8647
$checksums={};
8648
}
8649
}
8650
8651
# store cache builder version and constant declarations version
8652
if ($flags{cache} & CACHE_ON)
8653
{
8654
$checksums->{sha1_base64('version')}=$PerlPoint::Parser::VERSION;
8655
$checksums->{sha1_base64('constants')}=$PerlPoint::Constants::VERSION;
8656
$checksums->{sha1_base64('Storable')}=$Storable::VERSION;
8657
}
8658
8659
# store a document start directive (done here to save memory)
8660
push(@{$resultStreamRef->[STREAM_TOKENS]}, [\%docHints, DIRECTIVE_DOCUMENT, DIRECTIVE_START, basename($file)]);
8661
8662
# update tag finish memory by the way
8663
_updateTagFinishMem(scalar(@{$resultStreamRef->[STREAM_TOKENS]}));
8664
8665
# enter first (and most common) lexer state
8666
_stateManager(STATE_DEFAULT);
8667
8668
# flag that the next paragraph can be checksummed, if so
8669
$flags{checksum}=1 if $flags{cache} & CACHE_ON;
8670
8671
# set a timestamp, if helpful
8672
$flags{started}=time unless $flags{display} & DISPLAY_NOINFO;
8673
8674
# parse input
8675
$rc=($rc and $me->YYParse(yylex=>\&_lexer, yyerror=>\&_Error, yydebug => ($flags{trace} & TRACE_PARSER) ? 0x1F : 0x00));
8676
8677
# stop time, if necessary
8678
warn "\n $specifiedFile was parsed in ", time-$flags{started}, " seconds.\n" unless $flags{display} & DISPLAY_NOINFO;
8679
8680
# store a document completion directive (done here to save memory)
8681
push(@{$resultStreamRef->[STREAM_TOKENS]}, [\%docHints, DIRECTIVE_DOCUMENT, DIRECTIVE_COMPLETE, basename($file)]);
8682
8683
# reset the input handle and flags
8684
$readCompletely=0;
8685
8686
# store checksums, if necessary
8687
store($checksums, $cachefile) if ($flags{cache} & CACHE_ON)
8688
and $flags{cached}
8689
and defined $checksums and %$checksums;
8690
8691
# close the input file
8692
close($inHandle);
8693
$inHandle=new IO::File;
8694
8695
# back to startup directory
8696
chdir($startupDirectory);
8697
}
8698
8699
8700
# make a simple helper backend object
8701
my $helperBackend=new PerlPoint::Backend(
8702
name => 'parsers helper backend',
8703
display => DISPLAY_NOINFO+DISPLAY_NOWARN,
8704
8705
trace => TRACE_NOTHING,
8706
);
8707
8708
# get toc
8709
$helperBackend->bind($resultStreamRef);
8710
my $toc=$helperBackend->toc;
8711
8712
# store headlines as anchors, if necessary
8713
if (@$toc and $flags{headlineLinks})
8714
{
8715
# scopies
8716
my ($headlineNr, @headlinePath)=(0);
8717
8718
foreach (@$toc)
8719
{
8720
# update headline counter
8721
$headlineNr++;
8722
8723
# get data
8724
my ($level, $title)=@$_;
8725
8726
# skip empty headlines
8727
next unless $title;
8728
8729
# update headline path and numbers
8730
$headlinePath[$level]=$title;
8731
8732
# store both plain and composite headlines in the anchor object
8733
$anchors->add($title, $title, $headlineNr);
8734
$anchors->add(join('|', map {defined($_) ? $_ : ''} @headlinePath[$_..$level]), $title, $headlineNr) for (1..$level-1);
8735
}
8736
}
8737
8738
# add complete headline titles to streamed headline tokens,
8739
# move abbreviation, docstream and variable hints into data section
8740
if (@$toc)
8741
{
8742
# scopy
8743
my (@headlinePath, @shortcutPath, @levelPath, @pagenumPath);
8744
8745
for (my $index=0; $index<=$#{$toc}; ++$index)
8746
{
8747
# build a more readable shortcut
8748
my $ref=$resultStreamRef->[STREAM_TOKENS][$resultStreamRef->[STREAM_HEADLINES][$index]];
8749
8750
# get toc data
8751
my ($level, $title)=@{$toc->[$index]};
8752
8753
# adapt arrays to get rid of previous data - important in case someone skips several levels
8754
# (jumping from level 5 to 100 etc.)
8755
$#headlinePath=$#shortcutPath=$#levelPath=$#pagenumPath=$level;
8756
8757
# update headline pathes and numbers
8758
$headlinePath[$level]=$title;
8759
$shortcutPath[$level]=$ref->[0]{shortcut} ? $ref->[0]{shortcut} : $title;
8760
$levelPath[$level]++;
8761
$pagenumPath[$level]=$index+1; # real page number, no index
8762
8763
my $docstreams=delete($ref->[0]{docstreams});
8764
my $variables=delete($ref->[0]{vars});
8765
push (
8766
@$ref,
8767
$toc->[$index][1],
8768
delete($ref->[0]{shortcut}),
8769
$flags{docstreaming}==DSTREAM_DEFAULT ? [sort keys %$docstreams] : {},
8770
8771
# store headline path data in the streamed token
8772
[
8773
dclone([@headlinePath[1..$level]]),
8774
dclone([@shortcutPath[1..$level]]),
8775
dclone([@levelPath[1..$level]]),
8776
dclone([@pagenumPath[1..$level]]),
8777
$variables,
8778
],
8779
);
8780
}
8781
}
8782
8783
# finish tags, if necessary
8784
if (@$pendingTags==3)
8785
{
8786
# get number of tokens
8787
my $lastIndex=$#{$resultStreamRef->[STREAM_TOKENS]};
8788
8789
# handle all marked sections
8790
foreach my $section (@{$pendingTags->[2]})
8791
{
8792
# scan the stream till all pending tags were handled,
8793
# begin as near as possible
8794
for (my $position=$section->[0]; $position<=$lastIndex; $position++)
8795
{
8796
# get token
8797
my $token=$resultStreamRef->[STREAM_TOKENS][$position];
8798
8799
# skip everything except tag beginners of tags with finish hooks
8800
next unless ref($token)
8801
and $token->[STREAM_DIR_TYPE]==DIRECTIVE_TAG
8802
and $token->[STREAM_DIR_STATE]==DIRECTIVE_START
8803
and exists $tagsRef->{$token->[STREAM_DIR_DATA]}{finish};
8804
8805
# make an option hash
8806
my $options=dclone($token->[STREAM_DIR_DATA+1]);
8807
8808
# call hook function (use eval() to guard yourself)
8809
my $rc;
8810
eval {$rc=&{$tagsRef->{$token->[STREAM_DIR_DATA]}{finish}}($options, $anchors, join('-', @headlineIds))};
8811
8812
# check result
8813
unless ($@)
8814
{
8815
{
8816
# Error? (Treat syntactic errors as semantic ones at this point to give PARSING_FAILED a meaning.)
8817
++$_semerr, last if $rc==PARSING_ERROR or $rc==PARSING_FAILED;
8818
8819
# update options (might be modified, and checking for a difference
8820
# might take more time then just copying the replied values)
8821
$token->[STREAM_DIR_DATA+1]=$options;
8822
8823
# all right? (several values just mean "ok" at this point)
8824
last if $rc==PARSING_OK or $rc==PARSING_COMPLETED;
8825
8826
# backend hints to store?
8827
$token->[STREAM_DIR_HINTS]{ignore}=1, last if $rc==PARSING_IGNORE;
8828
$token->[STREAM_DIR_HINTS]{hide}=1, last if $rc==PARSING_ERASE;
8829
8830
# something is wrong here
8831
warn "[Warn] Tags ", $token->[STREAM_DIR_DATA], " tag finish hook replied unexpected result $rc, ignored.\n";
8832
}
8833
}
8834
else
8835
{warn "[Warn] Error in tags ", $token->[STREAM_DIR_DATA], " finish hook (ignored): $@\n"}
8836
8837
# update counter and leave loop if all pending tags in this section were handled
8838
last unless --$section->[1];
8839
}
8840
}
8841
}
8842
8843
# clean up
8844
undef $pendingTags;
8845
8846
8847
# success?
8848
if ($rc and not $_semerr)
8849
{
8850
# display a summary
8851
warn <
8852
8853
[Info] Input ok.
8854
8855
Statistics:
8856
-----------
8857
${\(_statisticsHelper(DIRECTIVE_HEADLINE))},
8858
${\(_statisticsHelper(DIRECTIVE_TEXT))},
8859
${\(_statisticsHelper(DIRECTIVE_UPOINT))},
8860
${\(_statisticsHelper(DIRECTIVE_OPOINT))},
8861
${\(_statisticsHelper(DIRECTIVE_DPOINT))},
8862
${\(_statisticsHelper(DIRECTIVE_BLOCK))},
8863
${\(_statisticsHelper(DIRECTIVE_VERBATIM))},
8864
${\(_statisticsHelper(DIRECTIVE_TAG))}
8865
${\(_statisticsHelper(DIRECTIVE_LIST_RSHIFT))},
8866
${\(_statisticsHelper(DIRECTIVE_LIST_LSHIFT))},
8867
and ${\(_statisticsHelper(DIRECTIVE_COMMENT))} were detected.
8868
8869
EOM
8870
8871
# add cache informations, if necessary
8872
warn ' ' x length('[Info] '), int(100*$statistics{cache}[1]/$statistics{cache}[0]+0.5), "% of all checked paragraphs were restored from cache.\n\n" if $flags{cache} & CACHE_ON and not $flags{display} & DISPLAY_NOINFO;
8873
}
8874
else
8875
{
8876
# display a summary
8877
warn "[Info] Input contains $_semerr semantic error", $_semerr>1?'s':'', ".\n" if $_semerr;
8878
}
8879
8880
# inform user
8881
warn "[Info] Parsing completed.\n\n" unless $flags{display} & DISPLAY_NOINFO;
8882
8883
# reply success state
8884
$rc and not $_semerr;
8885
}
8886
8887
8888
# report a semantic error, terminate process if necessary
8889
sub _semerr
8890
{
8891
my $parser=shift;
8892
warn "[Error ", ++$_semerr, "] ", @_, "\n";
8893
$parser->YYAbort if $flags{criticalSemantics};
8894
}
8895
8896
# ------------------------------------------------------
8897
# A tiny helper function intended for internal use only.
8898
# ------------------------------------------------------
8899
sub _statisticsHelper
8900
{
8901
# get and check parameters
8902
my ($type)=@_;
8903
confess "[BUG] Missing type parameter.\n" unless defined $type;
8904
8905
# declare variables
8906
my ($nr)=(exists $statistics{$type} and $statistics{$type}) ? $statistics{$type} : 0;
8907
8908
# reply resulting string
8909
join('', "$nr ", $paragraphTypeStrings{$type}, $nr==1 ? '' : 's');
8910
}
8911
8912
sub _updateChecksums
8913
{
8914
# get and check parameters
8915
my ($streamPart, $parserReinvokationHint)=@_;
8916
confess "[BUG] Missing stream part parameter.\n" unless defined $streamPart;
8917
confess "[BUG] Stream part parameter is no reference.\n" unless ref($streamPart);
8918
8919
# certain paragraph types are not cached intentionally
8920
return if not ($flags{cache} & CACHE_ON)
8921
or exists {
8922
DIRECTIVE_COMMENT() => 1,
8923
}->{$streamPart->[0][STREAM_DIR_TYPE]};
8924
8925
if (exists $flags{checksummed} and $flags{checksummed})
8926
{
8927
$checksums->{$sourceFile}{$flags{checksummed}[0]}=[
8928
dclone($streamPart),
8929
$flags{checksummed}[2],
8930
$parserReinvokationHint ? $parserReinvokationHint : (),
8931
defined $flags{checksummed}[3] ? $macroChecksum : (),
8932
defined $flags{checksummed}[4] ? $varChecksum : (),
8933
$anchors->reportNew,
8934
];
8935
# use Data::Dumper;
8936
# warn Dumper($streamPart);
8937
$flags{checksummed}=undef;
8938
8939
# note that something new was cached
8940
$flags{cached}=1;
8941
}
8942
}
8943
8944
8945
# --------------------------------------------------------
8946
# Extend all table rows to the number of columns found
8947
# in the first table line ("table headline"). On request,
8948
# automatically format the first table line as "headline".
8949
# --------------------------------------------------------
8950
sub _normalizeTableRows
8951
{
8952
# get and check parameters
8953
my ($stream, $autoHeadline)=@_;
8954
confess "[BUG] Missing stream part reference parameter.\n" unless defined $stream;
8955
confess "[BUG] Stream part reference parameter is no array reference.\n" unless ref($stream) eq 'ARRAY';
8956
confess "[BUG] Missing headline mode parameter.\n" unless defined $autoHeadline;
8957
8958
# declare variables
8959
my ($refColumns, $maxColumns, $columns, $nested, @flags, @improvedStream)=(0, 0, 0.5, 0, 1);
8960
8961
# remove whitespaces at the beginning and end of the stream, if necessary
8962
shift(@$stream) if $stream->[0]=~/^\s*$/; $stream->[0]=~s/^\s+//;
8963
pop(@$stream) if $stream->[-1]=~/^\s*$/; $stream->[-1]=~s/\s+$//;
8964
8965
# process the received stream
8966
foreach (@$stream)
8967
{
8968
# search for *embedded* tables - which are already normalized!
8969
$nested+=($_->[STREAM_DIR_STATE]==DIRECTIVE_START ? 1 : -1)
8970
if ref($_) eq 'ARRAY' and $_->[STREAM_DIR_TYPE]==DIRECTIVE_TAG and $_->[STREAM_DIR_DATA] eq 'TABLE';
8971
8972
# Inside an embedded table? Just pass the stream unchanged then.
8973
push(@improvedStream, $_), next if $nested;
8974
8975
# check state, set flags
8976
$flags[1]=(ref($_) eq 'ARRAY' and $_->[STREAM_DIR_TYPE]==DIRECTIVE_TAG);
8977
$flags[2]=($flags[1] and $_->[STREAM_DIR_DATA] eq 'TABLE_COL');
8978
$flags[3]=($flags[1] and $_->[STREAM_DIR_STATE]==DIRECTIVE_COMPLETE and $_->[STREAM_DIR_DATA] eq 'TABLE_ROW');
8979
$flags[4]=1 if $flags[2] and $_->[STREAM_DIR_STATE]==DIRECTIVE_START;
8980
$flags[4]=0 if $flags[2] and $_->[STREAM_DIR_STATE]==DIRECTIVE_COMPLETE;
8981
8982
# update counter of current row columns
8983
$columns+=0.5 if $flags[2];
8984
8985
# end of column reached?
8986
if ($flags[2] and not $flags[4])
8987
{
8988
# remove all trailing whitespaces in the last recent data entry,
8989
# remove data which becomes empty this way
8990
$improvedStream[-1]=~s/\s+$//;
8991
pop(@improvedStream) unless length($improvedStream[-1]);
8992
}
8993
8994
# first data after opening a new column?
8995
if ($flags[4] and not $flags[2])
8996
{
8997
# reset flag
8998
$flags[4]=0;
8999
9000
# remove all leading whitespaces, skip data which becomes empty this way
9001
s/^\s+//;
9002
next unless length($_);
9003
}
9004
9005
# table headline row?
9006
if ($flags[0])
9007
{
9008
# ok: mark columns as headline parts if necessary, take other elements unchanged
9009
push(@improvedStream, ($flags[2] and $autoHeadline) ? [@{$_}[STREAM_DIR_HINTS .. STREAM_DIR_STATE], 'TABLE_HL'] : $_);
9010
# at the end of this first row, marks that it is reached, store the number
9011
# of its columns as a reference for the complete table, and reset the column counter
9012
# (which will be used slightly differently in the following lines)
9013
$flags[0]=0, $refColumns=$maxColumns=$columns, $columns=0 if $flags[3];
9014
}
9015
else
9016
{
9017
# this is a content row (take care to preserve the order of operations here)
9018
9019
# end of table row reached?
9020
if ($flags[3])
9021
{
9022
# yes: insert additional columns, if necessary
9023
push(
9024
@improvedStream,
9025
[{}, DIRECTIVE_TAG, DIRECTIVE_START, 'TABLE_COL'],
9026
[{}, DIRECTIVE_TAG, DIRECTIVE_COMPLETE, 'TABLE_COL'],
9027
) for 1 .. ($refColumns-$columns);
9028
9029
# reset column counter
9030
$columns=0;
9031
}
9032
9033
# update maximum number of columns, if necessary
9034
$maxColumns=$columns if $columns>$maxColumns;
9035
9036
# in any case, copy this stream part
9037
push(@improvedStream, $_);
9038
}
9039
}
9040
9041
# replace original stream by the improved variant
9042
@$stream=@improvedStream;
9043
9044
# supply the number of columns in the table row *and* the maximum number of columns
9045
($refColumns, $maxColumns);
9046
}
9047
9048
9049
# predeclare variables
9050
sub _predeclareVariables
9051
{
9052
# get and check parameters
9053
my ($declarations, $preserveNames)=@_;
9054
confess "[BUG] Missing declaration parameter.\n" unless defined $declarations;
9055
confess "[BUG] Declaration parameter is no hash reference.\n" unless ref($declarations) eq 'HASH';
9056
9057
# transform variable names, if necessary
9058
{
9059
my $c=0;
9060
%$declarations=map {$c++; $c%2 ? uc : $_} %$declarations unless $preserveNames;
9061
}
9062
9063
# handle every setting (keys are sorted for test puposes only, to make the stream reproducable)
9064
foreach my $var (sort {$a cmp $b} keys %$declarations)
9065
{
9066
# check data format
9067
confess "[BUG] Predeclared variable $var is no scalar.\n" if ref($declarations->{$var});
9068
9069
# store the variable - with an uppercased name
9070
$variables{$var}=$declarations->{$var};
9071
9072
# propagate the setting to the stream, if necessary
9073
push(@{$resultStreamRef->[STREAM_TOKENS]}, [{}, DIRECTIVE_VARSET, DIRECTIVE_START, {var=>$var, value=>$declarations->{$var}}]) if $flags{var2stream};
9074
9075
# make the new variable setting available to embedded Perl code, if necessary
9076
if ($safeObject)
9077
{
9078
no strict 'refs';
9079
${join('::', ref($safeObject) ? $safeObject->root : 'main', $var)}=$declarations->{$var};
9080
}
9081
}
9082
9083
# update tag finish memory by the way
9084
_updateTagFinishMem(scalar(@{$resultStreamRef->[STREAM_TOKENS]}));
9085
}
9086
9087
9088
# update tag finish memory
9089
sub _updateTagFinishMem
9090
{
9091
# get and check parameters
9092
my ($lastKnownStreamIndex)=@_;
9093
confess "[BUG] Missing last known stream index parameter.\n" unless defined $lastKnownStreamIndex;
9094
9095
# update tag finish memory, if necessary
9096
if ($pendingTags->[1])
9097
{
9098
# store current collection
9099
push(@{$pendingTags->[2]}, [@{$pendingTags}[0, 1]]);
9100
9101
# reset tag counter
9102
$pendingTags->[1]=0;
9103
}
9104
9105
# in any case, update the "last known index" memory
9106
$pendingTags->[0]=$lastKnownStreamIndex;
9107
}
9108
9109
9110
9111
# set import filter, if necessary (by setting an import function - a user function is *not* overwritten!)
9112
sub _setImportFilter
9113
{
9114
# get and check parameters
9115
my ($parser, $optionHash)=@_;
9116
confess "[BUG] Missing parser parameter.\n" unless $parser;
9117
confess "[BUG] Missing option hash parameter.\n" unless defined $optionHash;
9118
confess "[BUG] Option hash parameter is no hash reference.\n" unless ref($optionHash) eq 'HASH';
9119
9120
# anything to do?
9121
if (
9122
not exists $optionHash->{ifilter} # there is no functional import filter set yet
9123
and exists $optionHash->{import} # but there is a type specific import filter set yet
9124
and not ( # and there is not ...
9125
exists $flags{ifilters}{lc($optionHash->{import})} # ... a general import filter known yet
9126
and not defined $flags{ifilters}{lc($optionHash->{import})} # ... which flags that there is no such filter
9127
)
9128
)
9129
{
9130
# parser options allow to use input filters of other languages, if this is the case we find that the
9131
# value of the general import filter is a special string which holds the name of that language
9132
my $filterLang=lc(
9133
(
9134
exists $flags{ifilters}{lc($optionHash->{import})}
9135
and $flags{ifilters}{lc($optionHash->{import})}=~/^MAP:\s*(\w+)$/
9136
) ? $flags{ifilters}{lc($1)} : $optionHash->{import}
9137
);
9138
9139
# first time we need this import filter?
9140
unless (exists $flags{ifilters}{$filterLang})
9141
{
9142
# so, there is a chance to find such a filter via general modules, search for such a module
9143
eval
9144
{
9145
# no strict subs
9146
no strict;
9147
9148
# build module name
9149
my $moduleName=join('::', 'PerlPoint::Import', uc($filterLang));
9150
9151
# try to load the module
9152
my $evalCode="require $moduleName;";
9153
ref($safeObject) ? $safeObject->reval($evalCode) : eval $evalCode;
9154
die $@ if $@;
9155
9156
# check for the import function specified by the API, store the code reference to the function
9157
# found or the undefined value otherwise, which will avoid repeated searches (store it both
9158
# for the filter language and the file language, which might differ due to filter mapping)
9159
$evalCode="exists \$${moduleName}::{importFilter}";
9160
$flags{ifilters}{lc($optionHash->{import})}=$flags{ifilters}{$filterLang}=join('::', $moduleName, 'importFilter()') if ref($safeObject) ? $safeObject->reval($evalCode) : eval $evalCode;
9161
};
9162
9163
# check success
9164
$parser->_semerr("Could not load $optionHash->{import} import filter module: $@."), return undef if $@;
9165
}
9166
9167
# now, set a functional filter, if possible
9168
$optionHash->{ifilter}=$flags{ifilters}{$filterLang}
9169
if exists $flags{ifilters}{$filterLang} and defined $flags{ifilters}{$filterLang};
9170
}
9171
9172
# flag success
9173
1;
9174
}
9175
9176
# perform paragraph filter calls
9177
sub _pfilterCall
9178
{
9179
# get and check parameters
9180
my ($parser, $filters, $pstream, $lineNr)=@_;
9181
confess "[BUG] Missing parser parameter.\n" unless $parser;
9182
confess "[BUG] Missing filter list.\n" unless $filters;
9183
confess "[BUG] Filter list is no array reference.\n" unless ref($filters) eq 'ARRAY';
9184
confess "[BUG] Missing paragraph stream.\n" unless $pstream;
9185
confess "[BUG] Paragraph stream is no array reference.\n" unless ref($pstream) eq 'ARRAY';
9186
confess "[BUG] Missing line number.\n" unless $lineNr;
9187
9188
9189
# declare and init variables
9190
my ($streamRef, %tableCounters);
9191
$retranslationBuffer='';
9192
9193
# build retranslator, if necessary
9194
unless ($retranslator)
9195
{
9196
# scopy
9197
my ($verbatimFlag)=(0);
9198
9199
# the retranslator is a backend object
9200
$retranslator=new PerlPoint::Backend(
9201
name => 'retranslator',
9202
display => DISPLAY_NOINFO+DISPLAY_NOWARN,
9203
trace => TRACE_NOTHING,
9204
);
9205
9206
# various callbacks perform the retranslation
9207
$retranslator->register(DIRECTIVE_SIMPLE, sub
9208
{
9209
# get parameters
9210
my ($opcode, $mode, @contents)=@_;
9211
9212
# add contents to the source text collection,
9213
# double backslashes (if they are here, they were guarded originally),
9214
# and restore ">" characters as if they were guarded
9215
(my $text=join('', @contents));
9216
$text=~s/([\\>])/\\$1/g unless $verbatimFlag;
9217
$retranslationBuffer.=$text;
9218
}
9219
);
9220
9221
$retranslator->register(DIRECTIVE_HEADLINE, sub
9222
{
9223
# get parameters
9224
my ($opcode, $mode, $level)=@_;
9225
9226
# add preceeding "=" characters
9227
$retranslationBuffer.=('=' x $level) if $mode==DIRECTIVE_START;
9228
}
9229
);
9230
9231
$retranslator->register(DIRECTIVE_VERBATIM, sub
9232
{
9233
# get parameters
9234
my ($opcode, $mode)=@_;
9235
9236
# cover contents
9237
$verbatimFlag=1, $retranslationBuffer.="<
9238
$verbatimFlag=0, $retranslationBuffer.="EOE\n" if $mode==DIRECTIVE_COMPLETE;
9239
}
9240
);
9241
9242
my $handleListPoint=sub
9243
{
9244
# get parameters
9245
my ($opcode, $mode, @data)=@_;
9246
9247
# act mode dependend
9248
if ($mode==DIRECTIVE_START)
9249
{$retranslationBuffer.=$opcode==DIRECTIVE_UPOINT ? '* ' : $opcode==DIRECTIVE_OPOINT ? '# ' : ':';}
9250
else
9251
{$retranslationBuffer.="\n\n"}
9252
};
9253
9254
my $handleDListPointItem=sub
9255
{
9256
# get parameters
9257
my ($opcode, $mode, @data)=@_;
9258
9259
# complete the item part if necessary
9260
$retranslationBuffer.=': ' if $mode==DIRECTIVE_COMPLETE;
9261
};
9262
9263
my $handleListShift=sub
9264
{
9265
# get parameters
9266
my ($opcode, $mode, $offset)=@_;
9267
9268
# anything to do?
9269
$retranslationBuffer.=join('',
9270
$opcode==DIRECTIVE_LIST_RSHIFT ? '>' : '<',
9271
"$offset\n\n",
9272
) if $mode==DIRECTIVE_START;
9273
};
9274
9275
$retranslator->register($_, $handleListPoint) foreach (DIRECTIVE_UPOINT, DIRECTIVE_OPOINT, DIRECTIVE_DPOINT);
9276
$retranslator->register($_, $handleListShift) foreach (DIRECTIVE_LIST_LSHIFT, DIRECTIVE_LIST_RSHIFT);
9277
$retranslator->register(DIRECTIVE_DPOINT_ITEM, $handleDListPointItem);
9278
9279
$retranslator->register(DIRECTIVE_TAG, sub
9280
{
9281
# get parameters
9282
my ($opcode, $mode, $tag, $settings, $bodyHint)=@_;
9283
9284
# table tags need special care, is it one?
9285
unless ($tag=~/^TABLE/)
9286
{
9287
# it can happen that perl complains about an undefined value here
9288
# even if no such value is to be find in debugging
9289
local($^W)=0;
9290
9291
# act mode dependend
9292
$retranslationBuffer.=$mode==DIRECTIVE_START ? join('', "\\$tag", (defined $settings and %$settings and grep(!/^__/, keys %$settings)) ? join('', '{', join(' ', map {qq($_="$settings->{$_}")} grep(!/^__/, keys %$settings)), '}') : (), ((defined $bodyHint and $bodyHint) ? '<' : ())) : ((defined $bodyHint and $bodyHint) ? '>' : ());
9293
}
9294
else
9295
{
9296
# TABLE declared by paragraph?
9297
if ($tag eq 'TABLE' and exists $settings->{__paragraph__})
9298
{
9299
# translate TABLE into paragraph start or completion
9300
$retranslationBuffer.=$mode==DIRECTIVE_START ? join('', '@', $settings->{separator}, "\n") : '';
9301
# init counters, store separators
9302
@tableCounters{qw(row col rowsep colsep)}=(0, 0, "\n", " $settings->{separator} ");
9303
}
9304
# TABLE declared by tags?
9305
elsif ($tag eq 'TABLE')
9306
{
9307
# translate TABLE into TABLE and END_TABLE
9308
$retranslationBuffer.=$mode==DIRECTIVE_START ? join('', '\TABLE{', join(' ', map {qq($_="$settings->{$_}")} grep(!/^__/, keys %$settings)), '}', $settings->{rowseparator} eq '\\\n' ? "\n" : '') : join('', $settings->{rowseparator} eq '\\\n' ? "\n" : '', '\END_TABLE');
9309
# init counters, store separators
9310
@tableCounters{qw(row col rowsep colsep)}=(0, 0, $settings->{rowseparator} eq '\\\n' ? "\n" : $settings->{rowseparator}, $settings->{separator} eq '\\\n' ? "\n" : " $settings->{separator} ");
9311
}
9312
# TABLE_ROW?
9313
elsif ($tag eq 'TABLE_ROW')
9314
{
9315
# we only need to act at startup
9316
if ($mode==DIRECTIVE_START)
9317
{
9318
# write a row separator if there was a row before
9319
$retranslationBuffer.=$tableCounters{rowsep} if $tableCounters{row};
9320
# update row counter, reset column counter
9321
$tableCounters{row}++;
9322
$tableCounters{col}=0;
9323
}
9324
}
9325
# TABLE_HL or TABLE_COL?
9326
elsif ($tag=~/TABLE_(HL|COL)/)
9327
{
9328
# we only need to act at startup
9329
if ($mode==DIRECTIVE_START)
9330
{
9331
# write a column separator if there was a column before
9332
$retranslationBuffer.=$tableCounters{colsep} if $tableCounters{col};
9333
# update row counter
9334
$tableCounters{col}++;
9335
}
9336
}
9337
}
9338
}
9339
);
9340
}
9341
9342
# embed paragraph stream into a structure looking like a complete stream
9343
@{$streamRef}[
9344
STREAM_IDENT,
9345
STREAM_TOKENS,
9346
STREAM_HEADLINES,
9347
]=(
9348
'__PerlPoint_stream__', # stream identifier;
9349
$pstream, # base stream: paragraph stream;
9350
[], # headline stream (dummy);
9351
);
9352
9353
# retranslate paragraph
9354
$retranslator->run($streamRef);
9355
9356
# init paragraph text
9357
# $retranslationBuffer=join('', @{$pstream}[1..($#{$pstream}-1)]);
9358
9359
# warn "BUFFER: $retranslationBuffer\n";
9360
9361
foreach my $perl (@$filters)
9362
{
9363
# we provide the paragraph text simply - for a general solution, we need to use an object
9364
# of a handy subclass of PerlPoint::Backend (still to be written)
9365
{
9366
no strict 'refs';
9367
${join('::', ref($safeObject) ? $safeObject->root : 'main', '_pfilterText')}=$retranslationBuffer;
9368
${join('::', ref($safeObject) ? $safeObject->root : 'main', '_pfilterType')}=$paragraphTypeStrings{$pstream->[0][1]};
9369
}
9370
9371
# inform user
9372
warn qq([Trace] $sourceFile, line $lineNr: Running paragraph filter "$perl".\n) if $flags{trace} & TRACE_ACTIVE;
9373
9374
# call the filter
9375
$retranslationBuffer=ref($safeObject) ? $safeObject->reval($perl) : eval(join(' ', '{package main; no strict;', $perl, '}'));
9376
9377
# check result
9378
if ($@)
9379
{
9380
# inform user, if necessary
9381
_semerr($parser, qq($sourceFile, line $lineNr: paragraph filter "$perl" could not be evaluated: $@.));
9382
9383
# stop processing, flag error
9384
return undef;
9385
}
9386
}
9387
9388
# success: reply result (embed it into empty lines to avoid paragraph mismatch)
9389
defined $retranslationBuffer ? [("\n") x 2, split(/(\n)/, $retranslationBuffer), ("\n") x 2] : '';
9390
}
9391
9392
=pod
9393
9394
=head2 anchors()
9395
9396
A class method that supplied all anchors collected by the parser.
9397
9398
Example:
9399
9400
my $anchors=PerlPoint::Parser::anchors;
9401
9402
=cut
9403
sub anchors
9404
{$anchors;}
9405
9406
1;
9407
9408
9409
# declare a helper package used for token "delay" after bodyless macros
9410
# (implemented the oo way to determine the data)
9411
package PerlPoint::Parser::DelayedToken;
9412
9413
# even this tiny package needs modules!
9414
use Carp;
9415
9416
# make an object holding the token name and its value
9417
sub new
9418
{
9419
# get parameter
9420
my ($class, $token, $value)=@_;
9421
9422
# check parameters
9423
confess "[BUG] Missing class name.\n" unless $class;
9424
confess "[BUG] Missing token parameter.\n" unless $token;
9425
confess "[BUG] Missing token value parameter.\n" unless defined $value;
9426
9427
# build and reply object
9428
bless([$token, $value], $class);
9429
}
9430
9431
# reply token
9432
sub token {$_[0]->[0];}
9433
9434
# reply value
9435
sub value {$_[0]->[1];}
9436
9437
1;
9438
9439
9440
# = POD TRAILER SECTION =================================================================
9441
9442
=pod
9443
9444
=head1 EXAMPLE
9445
9446
The following code shows a minimal but complete parser.
9447
9448
# pragmata
9449
use strict;
9450
9451
# load modules
9452
use PerlPoint::Parser;
9453
9454
# declare variables
9455
my (@streamData);
9456
9457
# build parser
9458
my ($parser)=new PerlPoint::Parser;
9459
# and call it
9460
$parser->run(
9461
stream => \@streamData,
9462
files => \@ARGV,
9463
);
9464
9465
=head1 NOTES
9466
9467
=head2 Converter namespace
9468
9469
It is suggested to B operating in namespace B. In order to emulate
9470
the behaviour of the B module by C in case a user wishes to get
9471
full Perl access for active contents, active contents needs to be executed in
9472
this namespace. Safe does not allow to change this, so the documented default
9473
for "saved" and "not saved" active contents I to be C. This means
9474
that both the parser and active contents will pollute C. Prevent from being
9475
effected by choosing a different converter namespace. The B
9476
hyrarchy is reserved for this purpose. The recommended namespace is
9477
C>, e.g. C.
9478
9479
=head2 Format
9480
9481
The PerlPoint format was initially designed by I,
9482
who wrote an HTML slide generator for it, too.
9483
9484
I added a number of additional, useful and interesting
9485
features to the original implementation. At a certain point, we
9486
decided to redesign the tool to make it a base for slide generation
9487
not only into HTML but into various document description languages.
9488
9489
The PerlPoint format implemented by this parser version is slightly
9490
different from the original design. Presentations written for Perl
9491
Point 1.0 will I pass the parser but can simply be converted
9492
into the new format. We designed the new format as a team of
9493
I, I and me.
9494
9495
=head2 Storable updates
9496
9497
From version 0.24 on the Storable module is a prerequisite of the
9498
parser package because Storable is used to store and retrieve cache
9499
data in files. If you update your Storable installation it I
9500
happen that its internal format changes and therefore stored cache
9501
data becomes unreadable. To avoid this, the parser automatically
9502
rebuilds existing caches in case of Storable updates.
9503
9504
=head1 FILES
9505
9506
If Is are used, the parser writes cache files where the initial
9507
sources are stored. They are named ..ppcache.
9508
9509
=head1 SEE ALSO
9510
9511
=over 4
9512
9513
=item PerlPoint::Backend
9514
9515
A frame class to write backends basing on the I.
9516
9517
=item PerlPoint::Constants
9518
9519
Constants used by parser functions and in the I.
9520
9521
=item PerlPoint::Tags
9522
9523
Tag declaration base class.
9524
9525
=item pp2sdf
9526
9527
A reference implementation of a PerlPoint converter, distributed with the parser package.
9528
9529
=item pp2html
9530
9531
The inital PerlPoint tool designed and provided by Tom Christiansen. A new translator
9532
by I using B.
9533
9534
=back
9535
9536
9537
=head1 SUPPORT
9538
9539
A PerlPoint mailing list is set up to discuss usage, ideas,
9540
bugs, suggestions and translator development. To subscribe,
9541
please send an empty message to perlpoint-subscribe@perl.org.
9542
9543
If you prefer, you can contact me via perl@jochen-stenzel.de
9544
as well.
9545
9546
9547
=head1 AUTHOR
9548
9549
Copyright (c) Jochen Stenzel (perl@jochen-stenzel.de), 1999-2001.
9550
All rights reserved.
9551
9552
This module is free software, you can redistribute it and/or modify it
9553
under the terms of the Artistic License distributed with Perl version
9554
5.003 or (at your option) any later version. Please refer to the
9555
Artistic License that came with your Perl distribution for more
9556
details.
9557
9558
The Artistic License should have been included in your distribution of
9559
Perl. It resides in the file named "Artistic" at the top-level of the
9560
Perl source tree (where Perl was downloaded/unpacked - ask your
9561
system administrator if you dont know where this is). Alternatively,
9562
the current version of the Artistic License distributed with Perl can
9563
be viewed on-line on the World-Wide Web (WWW) from the following URL:
9564
http://www.perl.com/perl/misc/Artistic.html.
9565
9566
B is built using B a way that users
9567
have I to explicitly install B themselves. According
9568
to the copyright note of B I have to mention the following:
9569
9570
"The Parse::Yapp module and its related modules and shell
9571
scripts are copyright (c) 1998-1999 Francois Desarmenien,
9572
France. All rights reserved.
9573
9574
You may use and distribute them under the terms of either
9575
the GNU General Public License or the Artistic License, as
9576
specified in the Perl README file."
9577
9578
9579
=head1 DISCLAIMER
9580
9581
This software is distributed in the hope that it will be useful, but
9582
is provided "AS IS" WITHOUT WARRANTY OF ANY KIND, either expressed or
9583
implied, INCLUDING, without limitation, the implied warranties of
9584
MERCHANTABILITY and FITNESS FOR A PARTICULAR PURPOSE.
9585
9586
The ENTIRE RISK as to the quality and performance of the software
9587
IS WITH YOU (the holder of the software). Should the software prove
9588
defective, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR
9589
CORRECTION.
9590
9591
IN NO EVENT WILL ANY COPYRIGHT HOLDER OR ANY OTHER PARTY WHO MAY CREATE,
9592
MODIFY, OR DISTRIBUTE THE SOFTWARE BE LIABLE OR RESPONSIBLE TO YOU OR TO
9593
ANY OTHER ENTITY FOR ANY KIND OF DAMAGES (no matter how awful - not even
9594
if they arise from known or unknown flaws in the software).
9595
9596
Please refer to the Artistic License that came with your Perl
9597
distribution for more details.
9598
9599
=cut
9600
9601
1;