2 /* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
3 Written by James Clark (jjc@jclark.com)
5 This file is part of groff.
7 groff is free software; you can redistribute it and/or modify it under
8 the terms of the GNU General Public License as published by the Free
9 Software Foundation; either version 2, or (at your option) any later
12 groff is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
17 You should have received a copy of the GNU General Public License along
18 with groff; see the file COPYING. If not, write to the Free Software
19 Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
27 implement_ptable(char)
29 PTABLE(char) macro_table
;
31 class macro_input
: public input
{
35 macro_input(const char *);
41 class argument_macro_input
: public input
{
48 argument_macro_input(const char *, int, char **);
49 ~argument_macro_input();
54 input::input() : next(0)
62 int input::get_location(const char **, int *)
67 file_input::file_input(FILE *f
, const char *fn
)
68 : lineno(0), ptr(""), filename(fn
)
73 file_input::~file_input()
78 int file_input::read_line()
87 else if (illegal_input_char(c
))
88 lex_error("illegal input character code %1", c
);
95 if (line
.length() == 0)
97 if (!(line
.length() >= 3 && line
[0] == '.' && line
[1] == 'P'
98 && (line
[2] == 'S' || line
[2] == 'E' || line
[2] == 'F')
99 && (line
.length() == 3 || line
[3] == ' ' || line
[3] == '\n'
100 || compatible_flag
))) {
102 ptr
= line
.contents();
108 int file_input::get()
110 if (*ptr
!= '\0' || read_line())
111 return (unsigned char)*ptr
++;
116 int file_input::peek()
118 if (*ptr
!= '\0' || read_line())
119 return (unsigned char)*ptr
;
124 int file_input::get_location(const char **fnp
, int *lnp
)
131 macro_input::macro_input(const char *str
)
133 p
= s
= strsave(str
);
136 macro_input::~macro_input()
141 int macro_input::get()
143 if (p
== 0 || *p
== '\0')
146 return (unsigned char)*p
++;
149 int macro_input::peek()
151 if (p
== 0 || *p
== '\0')
154 return (unsigned char)*p
;
157 // Character respresenting $1. Must be illegal input character.
160 char *process_body(const char *body
)
162 char *s
= strsave(body
);
164 for (int i
= 0; s
[i
] != '\0'; i
++)
165 if (s
[i
] == '$' && s
[i
+1] >= '0' && s
[i
+1] <= '9') {
167 s
[j
++] = ARG1
+ s
[++i
] - '1';
176 argument_macro_input::argument_macro_input(const char *body
, int ac
, char **av
)
179 for (int i
= 0; i
< argc
; i
++)
181 p
= s
= process_body(body
);
185 argument_macro_input::~argument_macro_input()
187 for (int i
= 0; i
< argc
; i
++)
192 int argument_macro_input::get()
196 return (unsigned char)*ap
++;
201 while (*p
>= ARG1
&& *p
<= ARG1
+ 8) {
203 if (i
< argc
&& argv
[i
] != 0 && argv
[i
][0] != '\0') {
205 return (unsigned char)*ap
++;
210 return (unsigned char)*p
++;
213 int argument_macro_input::peek()
217 return (unsigned char)*ap
;
222 while (*p
>= ARG1
&& *p
<= ARG1
+ 8) {
224 if (i
< argc
&& argv
[i
] != 0 && argv
[i
][0] != '\0') {
226 return (unsigned char)*ap
;
231 return (unsigned char)*p
;
235 static input
*current_input
;
238 static void push(input
*);
240 static int get_char();
241 static int peek_char();
242 static int get_location(const char **fnp
, int *lnp
);
243 static void push_back(unsigned char c
, int was_bol
= 0);
247 input
*input_stack::current_input
= 0;
248 int input_stack::bol_flag
= 0;
250 inline int input_stack::bol()
255 void input_stack::clear()
257 while (current_input
!= 0) {
258 input
*tem
= current_input
;
259 current_input
= current_input
->next
;
265 void input_stack::push(input
*in
)
267 in
->next
= current_input
;
271 void lex_init(input
*top
)
273 input_stack::clear();
274 input_stack::push(top
);
279 while (input_stack::get_char() != EOF
)
283 int input_stack::get_char()
285 while (current_input
!= 0) {
286 int c
= current_input
->get();
288 bol_flag
= c
== '\n';
291 // don't pop the top-level input off the stack
292 if (current_input
->next
== 0)
294 input
*tem
= current_input
;
295 current_input
= current_input
->next
;
301 int input_stack::peek_char()
303 while (current_input
!= 0) {
304 int c
= current_input
->peek();
307 if (current_input
->next
== 0)
309 input
*tem
= current_input
;
310 current_input
= current_input
->next
;
316 class char_input
: public input
{
324 char_input::char_input(int n
) : c((unsigned char)n
)
328 int char_input::get()
335 int char_input::peek()
340 void input_stack::push_back(unsigned char c
, int was_bol
)
342 push(new char_input(c
));
346 int input_stack::get_location(const char **fnp
, int *lnp
)
348 for (input
*p
= current_input
; p
; p
= p
->next
)
349 if (p
->get_location(fnp
, lnp
))
354 string context_buffer
;
360 void interpolate_macro_with_args(const char *body
)
364 for (int i
= 0; i
< 9; i
++)
368 enum { NORMAL
, IN_STRING
, IN_STRING_QUOTED
} state
= NORMAL
;
370 token_buffer
.clear();
372 c
= input_stack::get_char();
374 lex_error("end of input while scanning macro arguments");
377 if (state
== NORMAL
&& level
== 0 && (c
== ',' || c
== ')')) {
378 if (token_buffer
.length() > 0) {
379 token_buffer
+= '\0';
380 argv
[argc
] = strsave(token_buffer
.contents());
382 // for `foo()', argc = 0
383 if (argc
> 0 || c
!= ')' || i
> 0)
387 token_buffer
+= char(c
);
401 state
= IN_STRING_QUOTED
;
403 case IN_STRING_QUOTED
:
408 } while (c
!= ')' && c
!= EOF
);
409 input_stack::push(new argument_macro_input(body
, argc
, argv
));
412 static int docmp(const char *s1
, int n1
, const char *s2
, int n2
)
415 int r
= memcmp(s1
, s2
, n1
);
419 int r
= memcmp(s1
, s2
, n2
);
423 return memcmp(s1
, s2
, n1
);
426 int lookup_keyword(const char *str
, int len
)
428 static struct keyword
{
456 "diameter", DIAMETER
,
473 "invisible", INVISIBLE
,
502 "thickness", THICKNESS
,
516 const keyword
*start
= table
;
517 const keyword
*end
= table
+ sizeof(table
)/sizeof(table
[0]);
518 while (start
< end
) {
519 // start <= target < end
520 const keyword
*mid
= start
+ (end
- start
)/2;
522 int cmp
= docmp(str
, len
, mid
->name
, strlen(mid
->name
));
533 int get_token_after_dot(int c
)
535 // get_token deals with the case where c is a digit
538 input_stack::get_char();
539 c
= input_stack::peek_char();
541 input_stack::get_char();
542 context_buffer
= ".ht";
546 input_stack::get_char();
547 c
= input_stack::peek_char();
549 input_stack::get_char();
550 c
= input_stack::peek_char();
552 input_stack::get_char();
553 c
= input_stack::peek_char();
555 input_stack::get_char();
556 c
= input_stack::peek_char();
558 input_stack::get_char();
559 context_buffer
= ".height";
562 input_stack::push_back('h');
564 input_stack::push_back('g');
566 input_stack::push_back('i');
568 input_stack::push_back('e');
570 input_stack::push_back('h');
573 input_stack::get_char();
574 context_buffer
= ".x";
577 input_stack::get_char();
578 context_buffer
= ".y";
581 input_stack::get_char();
582 c
= input_stack::peek_char();
584 input_stack::get_char();
585 c
= input_stack::peek_char();
587 input_stack::get_char();
588 c
= input_stack::peek_char();
590 input_stack::get_char();
591 c
= input_stack::peek_char();
593 input_stack::get_char();
594 c
= input_stack::peek_char();
596 input_stack::get_char();
597 context_buffer
= ".center";
600 input_stack::push_back('e');
602 input_stack::push_back('t');
604 input_stack::push_back('n');
606 input_stack::push_back('e');
608 context_buffer
= ".c";
611 input_stack::get_char();
612 c
= input_stack::peek_char();
614 input_stack::get_char();
615 context_buffer
= ".ne";
619 input_stack::get_char();
620 context_buffer
= ".nw";
624 context_buffer
= ".n";
629 input_stack::get_char();
630 c
= input_stack::peek_char();
632 input_stack::get_char();
633 c
= input_stack::peek_char();
635 input_stack::get_char();
636 context_buffer
= ".end";
639 input_stack::push_back('n');
640 context_buffer
= ".e";
643 context_buffer
= ".e";
646 input_stack::get_char();
647 c
= input_stack::peek_char();
649 input_stack::get_char();
650 c
= input_stack::peek_char();
652 input_stack::get_char();
653 c
= input_stack::peek_char();
655 input_stack::get_char();
656 c
= input_stack::peek_char();
658 input_stack::get_char();
659 context_buffer
= ".width";
662 input_stack::push_back('t');
664 context_buffer
= ".wid";
667 input_stack::push_back('i');
669 context_buffer
= ".w";
672 input_stack::get_char();
673 c
= input_stack::peek_char();
675 input_stack::get_char();
676 context_buffer
= ".se";
680 input_stack::get_char();
681 context_buffer
= ".sw";
686 input_stack::get_char();
687 c
= input_stack::peek_char();
689 input_stack::get_char();
690 c
= input_stack::peek_char();
692 input_stack::get_char();
693 c
= input_stack::peek_char();
695 input_stack::get_char();
696 context_buffer
= ".start";
699 input_stack::push_back('r');
701 input_stack::push_back('a');
703 input_stack::push_back('t');
705 context_buffer
= ".s";
710 input_stack::get_char();
711 c
= input_stack::peek_char();
713 input_stack::get_char();
714 c
= input_stack::peek_char();
716 input_stack::get_char();
717 context_buffer
= ".top";
720 input_stack::push_back('o');
722 context_buffer
= ".t";
725 input_stack::get_char();
726 c
= input_stack::peek_char();
728 input_stack::get_char();
729 c
= input_stack::peek_char();
731 input_stack::get_char();
732 c
= input_stack::peek_char();
734 input_stack::get_char();
735 context_buffer
= ".left";
737 input_stack::push_back('f');
739 input_stack::push_back('e');
741 context_buffer
= ".l";
744 input_stack::get_char();
745 c
= input_stack::peek_char();
747 input_stack::get_char();
748 c
= input_stack::peek_char();
750 input_stack::get_char();
751 context_buffer
= ".rad";
754 input_stack::push_back('a');
757 input_stack::get_char();
758 c
= input_stack::peek_char();
760 input_stack::get_char();
761 c
= input_stack::peek_char();
763 input_stack::get_char();
764 c
= input_stack::peek_char();
766 input_stack::get_char();
767 context_buffer
= ".right";
769 input_stack::push_back('h');
771 input_stack::push_back('g');
773 input_stack::push_back('i');
775 context_buffer
= ".r";
778 input_stack::get_char();
779 c
= input_stack::peek_char();
781 input_stack::get_char();
782 c
= input_stack::peek_char();
784 input_stack::get_char();
785 c
= input_stack::peek_char();
787 input_stack::get_char();
788 c
= input_stack::peek_char();
790 input_stack::get_char();
791 c
= input_stack::peek_char();
793 input_stack::get_char();
794 context_buffer
= ".bottom";
797 input_stack::push_back('o');
799 input_stack::push_back('t');
801 context_buffer
= ".bot";
804 input_stack::push_back('o');
806 context_buffer
= ".b";
809 context_buffer
= '.';
814 int get_token(int lookup_flag
)
816 context_buffer
.clear();
819 int bol
= input_stack::bol();
820 int c
= input_stack::get_char();
821 if (bol
&& c
== command_char
) {
822 token_buffer
.clear();
824 // the newline is not part of the token
826 c
= input_stack::peek_char();
827 if (c
== EOF
|| c
== '\n')
829 input_stack::get_char();
830 token_buffer
+= char(c
);
832 context_buffer
= token_buffer
;
843 int d
= input_stack::peek_char();
845 context_buffer
= '\\';
848 input_stack::get_char();
853 c
= input_stack::get_char();
854 } while (c
!= '\n' && c
!= EOF
);
856 context_buffer
= '\n';
859 context_buffer
= '"';
860 token_buffer
.clear();
862 c
= input_stack::get_char();
864 context_buffer
+= '\\';
865 c
= input_stack::peek_char();
867 input_stack::get_char();
869 context_buffer
+= '"';
872 token_buffer
+= '\\';
874 else if (c
== '\n') {
875 error("newline in string");
879 error("missing `\"'");
883 context_buffer
+= '"';
887 context_buffer
+= char(c
);
888 token_buffer
+= char(c
);
906 if (n
> (INT_MAX
- 9)/10) {
912 context_buffer
+= char(c
);
913 c
= input_stack::peek_char();
914 if (c
== EOF
|| !csdigit(c
))
916 c
= input_stack::get_char();
921 token_double
*= 10.0;
922 token_double
+= c
- '0';
923 context_buffer
+= char(c
);
924 c
= input_stack::peek_char();
925 if (c
== EOF
|| !csdigit(c
))
927 c
= input_stack::get_char();
929 // if somebody asks for 1000000000000th, we will silently
930 // give them INT_MAXth
931 double temp
= token_double
; // work around gas 1.34/sparc bug
932 if (token_double
> INT_MAX
)
941 context_buffer
+= char(c
);
942 input_stack::get_char();
946 context_buffer
+= '.';
947 input_stack::get_char();
951 c
= input_stack::peek_char();
952 if (!c
== EOF
|| !csdigit(c
))
954 input_stack::get_char();
955 context_buffer
+= char(c
);
958 token_double
+= factor
*(c
- '0');
960 if (c
!= 'e' && c
!= 'E') {
961 if (c
== 'i' || c
== 'I') {
962 context_buffer
+= char(c
);
963 input_stack::get_char();
973 input_stack::get_char();
974 c
= input_stack::peek_char();
976 if (c
== '+' || c
== '-') {
978 input_stack::get_char();
979 c
= input_stack::peek_char();
980 if (c
== EOF
|| !csdigit(c
)) {
981 input_stack::push_back(sign
);
982 input_stack::push_back(echar
);
985 context_buffer
+= char(echar
);
986 context_buffer
+= char(sign
);
989 if (c
== EOF
|| !csdigit(c
)) {
990 input_stack::push_back(echar
);
993 context_buffer
+= char(echar
);
995 input_stack::get_char();
996 context_buffer
+= char(c
);
999 c
= input_stack::peek_char();
1000 if (c
== EOF
|| !csdigit(c
))
1002 input_stack::get_char();
1003 context_buffer
+= char(c
);
1004 n
= n
*10 + (c
- '0');
1008 if (c
== 'i' || c
== 'I') {
1009 context_buffer
+= char(c
);
1010 input_stack::get_char();
1012 token_double
*= pow(10.0, n
);
1016 input_stack::get_char();
1017 c
= input_stack::peek_char();
1019 input_stack::get_char();
1021 context_buffer
+= "nd";
1024 input_stack::push_back('n');
1027 input_stack::get_char();
1028 c
= input_stack::peek_char();
1030 input_stack::get_char();
1032 context_buffer
+= "rd";
1035 input_stack::push_back('r');
1038 input_stack::get_char();
1039 c
= input_stack::peek_char();
1041 input_stack::get_char();
1043 context_buffer
+= "th";
1046 input_stack::push_back('t');
1049 input_stack::get_char();
1050 c
= input_stack::peek_char();
1052 input_stack::get_char();
1054 context_buffer
+= "st";
1057 input_stack::push_back('s');
1065 c
= input_stack::peek_char();
1067 input_stack::get_char();
1068 c
= input_stack::peek_char();
1070 input_stack::get_char();
1071 context_buffer
= "'th";
1075 input_stack::push_back('t');
1077 context_buffer
= "'";
1082 c
= input_stack::peek_char();
1083 if (c
!= EOF
&& csdigit(c
)) {
1086 context_buffer
= '.';
1089 return get_token_after_dot(c
);
1092 c
= input_stack::peek_char();
1094 input_stack::get_char();
1095 c
= input_stack::peek_char();
1097 input_stack::get_char();
1098 context_buffer
= "<->";
1099 return DOUBLE_ARROW_HEAD
;
1101 context_buffer
= "<-";
1102 return LEFT_ARROW_HEAD
;
1104 else if (c
== '=') {
1105 input_stack::get_char();
1106 context_buffer
= "<=";
1109 context_buffer
= "<";
1112 c
= input_stack::peek_char();
1114 input_stack::get_char();
1115 context_buffer
= "->";
1116 return RIGHT_ARROW_HEAD
;
1118 context_buffer
= "-";
1121 c
= input_stack::peek_char();
1123 input_stack::get_char();
1124 context_buffer
= "!=";
1127 context_buffer
= "!";
1130 c
= input_stack::peek_char();
1132 input_stack::get_char();
1133 context_buffer
= ">=";
1134 return GREATEREQUAL
;
1136 context_buffer
= ">";
1139 c
= input_stack::peek_char();
1141 input_stack::get_char();
1142 context_buffer
= "==";
1145 context_buffer
= "=";
1148 c
= input_stack::peek_char();
1150 input_stack::get_char();
1151 context_buffer
= "&&";
1154 context_buffer
= "&";
1157 c
= input_stack::peek_char();
1159 input_stack::get_char();
1160 context_buffer
= "||";
1163 context_buffer
= "|";
1166 if (c
!= EOF
&& csalpha(c
)) {
1167 token_buffer
.clear();
1170 c
= input_stack::peek_char();
1171 if (c
== EOF
|| (!csalnum(c
) && c
!= '_'))
1173 input_stack::get_char();
1174 token_buffer
+= char(c
);
1176 int tok
= lookup_keyword(token_buffer
.contents(),
1177 token_buffer
.length());
1179 context_buffer
= token_buffer
;
1184 token_buffer
+= '\0';
1185 def
= macro_table
.lookup(token_buffer
.contents());
1186 token_buffer
.set_length(token_buffer
.length() - 1);
1189 input_stack::get_char();
1190 interpolate_macro_with_args(def
);
1193 input_stack::push(new macro_input(def
));
1197 context_buffer
= token_buffer
;
1198 if (csupper(token_buffer
[0]))
1205 context_buffer
= char(c
);
1206 return (unsigned char)c
;
1215 token_buffer
.clear();
1216 int c
= input_stack::get_char();
1217 while (c
== ' ' || c
== '\t' || c
== '\n')
1218 c
= input_stack::get_char();
1220 lex_error("missing delimiter");
1223 context_buffer
= char(c
);
1224 int had_newline
= 0;
1227 enum { NORMAL
, IN_STRING
, IN_STRING_QUOTED
, DELIM_END
} state
= NORMAL
;
1229 c
= input_stack::get_char();
1231 lex_error("missing closing delimiter");
1236 else if (!had_newline
)
1237 context_buffer
+= char(c
);
1260 case IN_STRING_QUOTED
:
1267 if (c
== '"' || c
== '\n')
1270 state
= IN_STRING_QUOTED
;
1273 // This case it just to shut cfront 2.0 up.
1277 if (state
== DELIM_END
)
1286 int t
= get_token(0); // do not expand what we are defining
1287 if (t
!= VARIABLE
&& t
!= LABEL
) {
1288 lex_error("can only define variable or placename");
1291 token_buffer
+= '\0';
1292 string nm
= token_buffer
;
1293 const char *name
= nm
.contents();
1294 if (!get_delimited())
1296 token_buffer
+= '\0';
1297 macro_table
.define(name
, strsave(token_buffer
.contents()));
1302 int t
= get_token(0); // do not expand what we are undefining
1303 if (t
!= VARIABLE
&& t
!= LABEL
) {
1304 lex_error("can only define variable or placename");
1307 token_buffer
+= '\0';
1308 macro_table
.define(token_buffer
.contents(), 0);
1312 class for_input
: public input
{
1316 int by_is_multiplicative
;
1321 for_input(char *, double, int, double, char *);
1327 for_input::for_input(char *vr
, double t
, int bim
, double b
, char *bd
)
1328 : var(vr
), to(t
), by_is_multiplicative(bim
), by(b
), body(bd
), p(body
),
1333 for_input::~for_input()
1339 int for_input::get()
1345 return (unsigned char)*p
++;
1346 if (!done_newline
) {
1351 if (!lookup_variable(var
, &val
)) {
1352 lex_error("body of `for' terminated enclosing block");
1355 if (by_is_multiplicative
)
1359 define_variable(var
, val
);
1369 int for_input::peek()
1374 return (unsigned char)*p
;
1378 if (!lookup_variable(var
, &val
))
1380 if (by_is_multiplicative
) {
1390 return (unsigned char)*body
;
1393 void do_for(char *var
, double from
, double to
, int by_is_multiplicative
,
1394 double by
, char *body
)
1396 define_variable(var
, from
);
1398 input_stack::push(new for_input(var
, to
, by_is_multiplicative
, by
, body
));
1402 void do_copy(const char *filename
)
1405 FILE *fp
= fopen(filename
, "r");
1407 lex_error("can't open `%1': %2", filename
, strerror(errno
));
1410 input_stack::push(new file_input(fp
, filename
));
1413 class copy_thru_input
: public input
{
1423 virtual int inget() = 0;
1425 copy_thru_input(const char *b
, const char *u
);
1431 class copy_file_thru_input
: public copy_thru_input
{
1434 copy_file_thru_input(input
*, const char *b
, const char *u
);
1435 ~copy_file_thru_input();
1439 copy_file_thru_input::copy_file_thru_input(input
*i
, const char *b
,
1441 : in(i
), copy_thru_input(b
, u
)
1445 copy_file_thru_input::~copy_file_thru_input()
1450 int copy_file_thru_input::inget()
1458 class copy_rest_thru_input
: public copy_thru_input
{
1460 copy_rest_thru_input(const char *, const char *u
);
1464 copy_rest_thru_input::copy_rest_thru_input(const char *b
, const char *u
)
1465 : copy_thru_input(b
, u
)
1469 int copy_rest_thru_input::inget()
1472 int c
= next
->get();
1475 if (next
->next
== 0)
1485 copy_thru_input::copy_thru_input(const char *b
, const char *u
)
1489 body
= process_body(b
);
1495 copy_thru_input::~copy_thru_input()
1501 int copy_thru_input::get()
1505 return (unsigned char)*ap
++;
1518 while (*p
>= ARG1
&& *p
<= ARG1
+ 8) {
1519 int i
= *p
++ - ARG1
;
1520 if (i
< argc
&& line
[argv
[i
]] != '\0') {
1521 ap
= line
.contents() + argv
[i
];
1522 return (unsigned char)*ap
++;
1526 return (unsigned char)*p
++;
1531 int copy_thru_input::peek()
1535 return (unsigned char)*ap
;
1546 while (*p
>= ARG1
&& *p
<= ARG1
+ 8) {
1547 int i
= *p
++ - ARG1
;
1548 if (i
< argc
&& line
[argv
[i
]] != '\0') {
1549 ap
= line
.contents() + argv
[i
];
1550 return (unsigned char)*ap
;
1554 return (unsigned char)*p
;
1559 int copy_thru_input::get_line()
1569 if (c
== EOF
|| c
== '\n')
1574 } while (c
!= '\n' && c
!= EOF
);
1577 argv
[argc
++] = line
.length();
1581 } while (c
!= ' ' && c
!= '\n');
1584 if (until
!= 0 && argc
> 0 && strcmp(&line
[argv
[0]], until
) == 0) {
1588 return argc
> 0 || c
== '\n';
1591 class simple_file_input
: public input
{
1592 const char *filename
;
1596 simple_file_input(FILE *, const char *);
1597 ~simple_file_input();
1600 int get_location(const char **, int *);
1603 simple_file_input::simple_file_input(FILE *p
, const char *s
)
1604 : filename(s
), fp(p
), lineno(1)
1608 simple_file_input::~simple_file_input()
1610 // don't delete the filename
1614 int simple_file_input::get()
1617 while (illegal_input_char(c
)) {
1618 error("illegal input character code %1", c
);
1626 int simple_file_input::peek()
1629 while (illegal_input_char(c
)) {
1630 error("illegal input character code %1", c
);
1638 int simple_file_input::get_location(const char **fnp
, int *lnp
)
1646 void copy_file_thru(const char *filename
, const char *body
, const char *until
)
1649 FILE *fp
= fopen(filename
, "r");
1651 lex_error("can't open `%1': %2", filename
, strerror(errno
));
1654 input
*in
= new copy_file_thru_input(new simple_file_input(fp
, filename
),
1656 input_stack::push(in
);
1659 void copy_rest_thru(const char *body
, const char *until
)
1661 input_stack::push(new copy_rest_thru_input(body
, until
));
1664 void push_body(const char *s
)
1666 input_stack::push(new char_input('\n'));
1667 input_stack::push(new macro_input(s
));
1672 char *get_thru_arg()
1674 int c
= input_stack::peek_char();
1676 input_stack::get_char();
1677 c
= input_stack::peek_char();
1679 if (c
!= EOF
&& csalpha(c
)) {
1680 // looks like a macro
1681 input_stack::get_char();
1684 c
= input_stack::peek_char();
1685 if (c
== EOF
|| (!csalnum(c
) && c
!= '_'))
1687 input_stack::get_char();
1688 token_buffer
+= char(c
);
1690 context_buffer
= token_buffer
;
1691 token_buffer
+= '\0';
1692 char *def
= macro_table
.lookup(token_buffer
.contents());
1694 return strsave(def
);
1695 // I guess it wasn't a macro after all; so push the macro name back.
1696 // -2 because we added a '\0'
1697 for (int i
= token_buffer
.length() - 2; i
>= 0; i
--)
1698 input_stack::push_back(token_buffer
[i
]);
1700 if (get_delimited()) {
1701 token_buffer
+= '\0';
1702 return strsave(token_buffer
.contents());
1708 int lookahead_token
= -1;
1709 string old_context_buffer
;
1713 if (lookahead_token
== -1) {
1714 old_context_buffer
= context_buffer
;
1715 lookahead_token
= get_token(1);
1722 assert(lookahead_token
== -1);
1723 if (delim_flag
== 2) {
1724 if ((yylval
.str
= get_thru_arg()) != 0)
1730 if (get_delimited()) {
1731 token_buffer
+= '\0';
1732 yylval
.str
= strsave(token_buffer
.contents());
1741 if (lookahead_token
>= 0) {
1742 t
= lookahead_token
;
1743 lookahead_token
= -1;
1759 yylval
.n
= token_int
;
1762 yylval
.x
= token_double
;
1766 token_buffer
+= '\0';
1767 if (!input_stack::get_location(&yylval
.lstr
.filename
,
1768 &yylval
.lstr
.lineno
)) {
1769 yylval
.lstr
.filename
= 0;
1770 yylval
.lstr
.lineno
= -1;
1772 yylval
.lstr
.str
= strsave(token_buffer
.contents());
1776 token_buffer
+= '\0';
1777 yylval
.str
= strsave(token_buffer
.contents());
1780 // change LEFT to LEFT_CORNER when followed by OF
1781 old_context_buffer
= context_buffer
;
1782 lookahead_token
= get_token(1);
1783 if (lookahead_token
== OF
)
1788 // change RIGHT to RIGHT_CORNER when followed by OF
1789 old_context_buffer
= context_buffer
;
1790 lookahead_token
= get_token(1);
1791 if (lookahead_token
== OF
)
1792 return RIGHT_CORNER
;
1796 // recognise UPPER only before LEFT or RIGHT
1797 old_context_buffer
= context_buffer
;
1798 lookahead_token
= get_token(1);
1799 if (lookahead_token
!= LEFT
&& lookahead_token
!= RIGHT
) {
1800 yylval
.str
= strsave("upper");
1806 // recognise LOWER only before LEFT or RIGHT
1807 old_context_buffer
= context_buffer
;
1808 lookahead_token
= get_token(1);
1809 if (lookahead_token
!= LEFT
&& lookahead_token
!= RIGHT
) {
1810 yylval
.str
= strsave("lower");
1816 // recognise TOP only before OF
1817 old_context_buffer
= context_buffer
;
1818 lookahead_token
= get_token(1);
1819 if (lookahead_token
!= OF
) {
1820 yylval
.str
= strsave("top");
1826 // recognise BOTTOM only before OF
1827 old_context_buffer
= context_buffer
;
1828 lookahead_token
= get_token(1);
1829 if (lookahead_token
!= OF
) {
1830 yylval
.str
= strsave("bottom");
1836 // recognise CENTER only before OF
1837 old_context_buffer
= context_buffer
;
1838 lookahead_token
= get_token(1);
1839 if (lookahead_token
!= OF
) {
1840 yylval
.str
= strsave("center");
1846 // recognise START only before OF
1847 old_context_buffer
= context_buffer
;
1848 lookahead_token
= get_token(1);
1849 if (lookahead_token
!= OF
) {
1850 yylval
.str
= strsave("start");
1856 // recognise END only before OF
1857 old_context_buffer
= context_buffer
;
1858 lookahead_token
= get_token(1);
1859 if (lookahead_token
!= OF
) {
1860 yylval
.str
= strsave("end");
1871 void lex_error(const char *message
,
1876 const char *filename
;
1878 if (!input_stack::get_location(&filename
, &lineno
))
1879 error(message
, arg1
, arg2
, arg3
);
1881 error_with_file_and_line(filename
, lineno
, message
, arg1
, arg2
, arg3
);
1884 void lex_warning(const char *message
,
1889 const char *filename
;
1891 if (!input_stack::get_location(&filename
, &lineno
))
1892 warning(message
, arg1
, arg2
, arg3
);
1894 warning_with_file_and_line(filename
, lineno
, message
, arg1
, arg2
, arg3
);
1897 void yyerror(const char *s
)
1899 const char *filename
;
1901 const char *context
= 0;
1902 if (lookahead_token
== -1) {
1903 if (context_buffer
.length() > 0) {
1904 context_buffer
+= '\0';
1905 context
= context_buffer
.contents();
1909 if (old_context_buffer
.length() > 0) {
1910 old_context_buffer
+= '\0';
1911 context
= old_context_buffer
.contents();
1914 if (!input_stack::get_location(&filename
, &lineno
)) {
1916 if (context
[0] == '\n' && context
[1] == '\0')
1917 error("%1 before newline", s
);
1919 error("%1 before `%2'", s
, context
);
1922 error("%1 at end of picture", s
);
1926 if (context
[0] == '\n' && context
[1] == '\0')
1927 error_with_file_and_line(filename
, lineno
, "%1 before newline", s
);
1929 error_with_file_and_line(filename
, lineno
, "%1 before `%2'",
1933 error_with_file_and_line(filename
, lineno
, "%1 at end of picture", s
);