Visual Servoing Platform  version 3.4.0
vpLex.cpp
1 /****************************************************************************
2  *
3  * ViSP, open source Visual Servoing Platform software.
4  * Copyright (C) 2005 - 2019 by Inria. All rights reserved.
5  *
6  * This software is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  * See the file LICENSE.txt at the root directory of this source
11  * distribution for additional information about the GNU GPL.
12  *
13  * For using ViSP with software that can not be combined with the GNU
14  * GPL, please contact Inria about acquiring a ViSP Professional
15  * Edition License.
16  *
17  * See http://visp.inria.fr for more information.
18  *
19  * This software was developed at:
20  * Inria Rennes - Bretagne Atlantique
21  * Campus Universitaire de Beaulieu
22  * 35042 Rennes Cedex
23  * France
24  *
25  * If you have questions regarding the use of this file, please contact
26  * Inria at visp@inria.fr
27  *
28  * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
29  * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
30  *
31  * Description:
32  * Le module "lex.c" contient les procedures de gestion
33  * de l'analyse lexicale de l'analyseur lexicale "lex"
34  * d'un fichier source dont la grammaire possede
35  * les symboles terminaux suivants (ecrit en "LEX", UNIX) :
36  *
37  * Authors:
38  * Jean-Luc CORRE
39  *
40  *****************************************************************************/
41 
42 #include "vpKeyword.h"
43 #include "vpMy.h"
44 #include "vpToken.h"
45 
46 #include <ctype.h>
47 #include <fcntl.h>
48 #include <math.h>
49 #include <stdarg.h>
50 #include <stdio.h>
51 #include <stdlib.h>
52 #include <string.h>
53 #ifndef DOXYGEN_SHOULD_SKIP_THIS
54 
55 static void count(void);
56 static void next_source(void);
57 
58 void lexerr(const char *path, ...);
59 
60 /* Codes des symboles terminaux */
61 
62 #define NULT 0 /* caractere non valide */
63 #define EOBT 1 /* fin de buffer */
64 #define EOFT 2 /* fin de fichier */
65 #define EOLT 3 /* fin de ligne */
66 #define CMTT 4 /* commentaire */
67 #define IDNT 5 /* identificateur */
68 #define INTT 6 /* nombre entier */
69 #define FPTT 7 /* nombre flottant */
70 #define SGNT 8 /* signe +/- */
71 #define SPCT 9 /* caractere blanc */
72 #define STGT 10 /* caractere de chaine */
73 #define NBRT 11 /* nombre de codes */
74 
75 /* Drapeaux des caracteres */
76 
77 #define _NULT 0x00 /* caractere non valide */
78 #define _CMTT 0x01 /* commentaire */
79 #define _FPTT 0x02 /* nombre flottant */
80 #define _IDNT 0x04 /* identificateur */
81 #define _INTT 0x08 /* nombre entier */
82 #define _SGNT 0x10 /* signe +/- */
83 #define _STGT 0x20 /* caractere de chaine */
84 
85 /* Caracteres sentinelles */
86 
87 #define ASCII_NBR 128 /* nombre de codes ASCII*/
88 
89 #ifndef EOB
90 #define EOB (-2) /* fin de buffer */
91 #endif
92 #ifndef EOF
93 #define EOF (-1) /* fin de fichier */
94 #endif
95 #ifndef EOL
96 #define EOL 10 /* fin de ligne */
97 #endif
98 
99 #define CHAR_NBR 130 /* nombre de caracteres */
100 
101 /* Tests des drapeaux */
102 
103 #define isnult(c) (scantbl[c] == _NULT)
104 #define iscmtt(c) (scantbl[c] & _CMTT)
105 #define isfptt(c) (scantbl[c] & _FPTT)
106 #define isidnt(c) (scantbl[c] & _IDNT)
107 #define isintt(c) (scantbl[c] & _INTT)
108 #define issgnt(c) (scantbl[c] & _SGNT)
109 #define isstgt(c) (scantbl[c] & _STGT)
110 
111 /*
112  * Codes des messages d'erreur de l'analyseur lexicale.
113  */
114 #define E_UNKNOWN 0
115 #define E_SYMBOL 1
116 #define E_CMT_EOF 2
117 #define E_FLOAT 3
118 #define E_INT 4
119 #define E_KEYWORD 5
120 #define E_STG_EOF 6
121 #define E_STG_EOL 7
122 #define E_STRING 8
123 #define E_9 9
124 
125 const char *lex_errtbl[] = {/* table des messages d'erreur */
126  "error unknown",
127  "symbol undefined",
128  "unexpected EOF in comment",
129  "float expected",
130  "int expected",
131  "keyword expected",
132  "unexpected EOF in string or char constant",
133  "newline in string or char constant",
134  "string expected",
135  ""};
136 
137 char *mytext = NULL;
138 int mylength = 0;
139 int mylineno = 1;
140 unsigned int mycolumno = 0;
141 float myfloat = 0.0;
142 int myint = 0;
143 
144 static char *mysptr; /* tete de lecture de la ligne courante */
145 static char *myline; /* debut de la ligne courante */
146 static char *lastline; /* derniere ligne du buffer d'entree */
147 
148 static Byte *chtbl; /* premiers caracteres des terminaux */
149 static Byte *scantbl; /* caracteres suivants des terminaux */
150 
151 /*
152  * La procedure "open_lex" alloue et initialise les variables utilisees
153  * par l'analyseur lexical "lex".
154  */
155 void open_lex(void)
156 {
157  if ((chtbl = (Byte *)malloc(CHAR_NBR * sizeof(Byte))) == NULL ||
158  (scantbl = (Byte *)malloc(CHAR_NBR * sizeof(Byte))) == NULL) {
159  static char proc_name[] = "open_lex";
160  perror(proc_name);
161  exit(1);
162  }
163  chtbl += 2; /* 2 sentinelles non affichables */
164  scantbl += 2;
165 
166  /* initialise les premiers caracteres des symboles terminaux */
167 
168  for (int i = 0; i < ASCII_NBR; i++) {
169  if (isalpha(i))
170  chtbl[i] = IDNT;
171  else if (isdigit(i))
172  chtbl[i] = INTT;
173  else if (isspace(i))
174  chtbl[i] = SPCT;
175  else
176  switch (i) {
177  case '"':
178  chtbl[i] = STGT;
179  break;
180  case '+':
181  case '-':
182  chtbl[i] = SGNT;
183  break;
184  case '.':
185  chtbl[i] = FPTT;
186  break;
187  case '/':
188  chtbl[i] = CMTT;
189  break;
190  case '_':
191  chtbl[i] = IDNT;
192  break;
193  default:
194  chtbl[i] = NULT;
195  break;
196  }
197  }
198 
199  /* Initialise les sentinelles comme des terminaux. */
200 
201  chtbl[EOB] = EOBT;
202  chtbl[EOF] = EOFT;
203  chtbl[EOL] = EOLT;
204 
205  /* Initialise les caracteres suivants des symboles terminaux. */
206 
207  for (int i = 0; i < ASCII_NBR; i++) {
208  if (isalpha(i))
209  scantbl[i] = _CMTT | _IDNT | _STGT;
210  else if (isdigit(i))
211  scantbl[i] = _CMTT | _IDNT | _INTT | _STGT;
212  else
213  switch (i) {
214  case '"':
215  scantbl[i] = _CMTT;
216  break;
217  case '+':
218  case '-':
219  scantbl[i] = _CMTT | _SGNT | _STGT;
220  break;
221  case '.':
222  scantbl[i] = _CMTT | _FPTT | _STGT;
223  break;
224  case '/':
225  scantbl[i] = _STGT;
226  break;
227  case '_':
228  scantbl[i] = _CMTT | _IDNT | _STGT;
229  break;
230  default:
231  scantbl[i] = _CMTT | _STGT;
232  break;
233  }
234  }
235 
236  /* Initialise les sentinelles comme des terminaux. */
237 
238  scantbl[EOB] = _NULT;
239  scantbl[EOF] = _NULT;
240  scantbl[EOL] = _NULT;
241 }
242 
243 /*
244  * La procedure "close_lex" libere les variables utilisees
245  * par l'analyseur lexical "lex".
246  */
247 void close_lex(void)
248 {
249  free((char *)(chtbl - 2)); /* voir "open_lex" pour "- 2" */
250  free((char *)(scantbl - 2));
251 }
252 
253 #define ECHO printf("%c", *(mysptr))
254 #define CURC (*((signed char *)mysptr)) /* caractere courant */
255 #define NEXTC (*((signed char *)mysptr + 1)) /* caractere suivant */
256 #define PREVC (*((signed char *)mysptr - 1)) /* caractere precedent */
257 
258 /*
259  * La procedure "lex" contient l'analyseur lexical.
260  * Note :
261  * La tete de lecture (mysptr) n'est pas systematiquement avancee apres
262  *lecture. Le caractere courant est celui sous la tete de lecture. Ainsi on
263  *accede de maniere symetrique aux caracteres precedent et suivant. Sortie :
264  * Code du symbole terminale analyse.
265  */
266 int lex(void)
267 {
268 lex_loop:
269 
270  for (; chtbl[(int)CURC] == SPCT; mysptr++) {
271  }; /* saute les espaces */
272 
273  switch (chtbl[(int)CURC]) {
274 
275  case NULT:
276  mytext = mysptr; /* sauvegarde le jeton */
277  mysptr++;
278  return (*mytext);
279  break;
280  case EOBT:
281  next_source();
282  goto lex_loop;
283  break;
284  case EOFT:
285  mytext = mysptr; /* sauvegarde le jeton */
286  return (T_EOF);
287  break;
288  case EOLT:
289  if (mysptr == lastline)
290  next_source();
291  else
292  mysptr++;
293  mylineno++;
294  myline = mysptr;
295  goto lex_loop;
296  break;
297  case CMTT:
298  mytext = mysptr; /* sauvegarde le jeton */
299  mysptr++;
300  if (CURC != '*')
301  return (*mytext);
302  mysptr++;
303  comment:
304  for (; iscmtt((int)CURC); mysptr++) {
305  };
306  switch (chtbl[(int)CURC]) {
307  case EOBT:
308  next_source();
309  goto comment;
310  break;
311  case EOFT:
312  lexerr("start", lex_errtbl[E_CMT_EOF], NULL);
313  return (T_EOF);
314  break;
315  case EOLT:
316  if (mysptr == lastline)
317  next_source();
318  else
319  mysptr++;
320  mylineno++;
321  myline = mysptr;
322  goto comment;
323  break;
324  case CMTT:
325  if (PREVC == '*') { /* veritable fin */
326  mysptr++;
327  goto lex_loop;
328  }
329  mysptr++; /* pseudo fin */
330  goto comment;
331  break;
332  }
333  break;
334  case IDNT:
335  mytext = mysptr; /* sauvegarde le jeton */
336  mysptr++;
337  for (; isidnt((int)CURC); mysptr++) {
338  };
339  mylength = (int)(mysptr - mytext);
340  return (get_symbol(mytext, mylength));
341  break;
342  case INTT:
343  mytext = mysptr; /* sauvegarde le jeton */
344  int_part:
345  myint = (int)(CURC - '0');
346  mysptr++;
347  for (; isintt((int)CURC); mysptr++)
348  myint = myint * 10 + (int)(CURC - '0');
349  switch (CURC) {
350  case '.': /* lecture fraction */
351  float_part:
352  mysptr++;
353  for (; isintt((int)CURC); mysptr++) {
354  };
355  if (CURC != 'E' && CURC != 'e') {
356  myfloat = (float)atof(mytext);
357  /* FC
358  printf("mytext %s, myfloat %f\n",mytext,myfloat);
359  */
360  return (T_FLOAT);
361  }
362  break;
363  case 'E': /* lecture exposant */
364  case 'e':
365  mysptr++;
366  if (isintt((int)CURC))
367  mysptr++;
368  else if (issgnt((int)CURC) && isintt((int)NEXTC))
369  mysptr += 2;
370  else {
371  mysptr--;
372  myfloat = (float)atof(mytext);
373  return (T_FLOAT);
374  }
375  for (; isintt((int)CURC); mysptr++) {
376  };
377  myfloat = (float)atof(mytext);
378  return (T_FLOAT);
379  break;
380  default:
381  if (*mytext == '-')
382  myint = -myint;
383  return (T_INT);
384  break;
385  }
386  break;
387  case FPTT:
388  mytext = mysptr; /* sauvegarde le jeton */
389  mysptr++;
390  if (!isintt((int)CURC)) /* pas de fraction */
391  return (*mytext);
392  goto float_part;
393  break;
394  case SGNT:
395  mytext = mysptr; /* sauvegarde le jeton */
396  mysptr++;
397  if (isintt((int)CURC))
398  goto int_part;
399  if (isfptt((int)CURC) && isintt((int)NEXTC))
400  goto float_part;
401  return (*mytext);
402  break;
403  case STGT:
404  mytext = mysptr; /* sauvegarde le jeton */
405  mysptr++;
406  string:
407  for (; isstgt((int)CURC); mysptr++) {
408  };
409  switch (chtbl[(int)CURC]) {
410  case EOBT:
411  next_source();
412  goto string;
413  break;
414  case EOFT:
415  lexerr("start", lex_errtbl[E_STG_EOF], NULL);
416  return ('\n');
417  break;
418  case EOLT:
419  lexerr("start", lex_errtbl[E_STG_EOL], NULL);
420  return ('\n');
421  break;
422  case STGT:
423  if (PREVC != '\\') { /* veritable fin */
424  mytext++;
425  mylength = (int)(mysptr - mytext);
426  mysptr++;
427  return (T_STRING);
428  }
429  mysptr++; /* pseudo fin */
430  goto string;
431  break;
432  }
433  break;
434  default:
435  ECHO;
436  mysptr++;
437  goto lex_loop;
438  break;
439  }
440  return (T_EOF);
441 }
442 
443 /*
444  * La procedure "lexecho" contient l'analyseur lexical "lex" :
445  * 1 Analyse le fichier source,
446  * 2 Affiche le fichier source sur le fichier "f",
447  * 3 Stoppe devant le jeton "token".
448  * Note :
449  * La tete de lecture (mysptr) n'est pas systematiquement avancee apres
450  *lecture. Le caractere courant est celui sous la tete de lecture. Ainsi on
451  *accede de maniere symetrique aux caracteres precedent et suivant. Entree :
452  * f Fichier en sortie.
453  * token Jeton de fin de rechercher.
454  * Sortie :
455  * Code du symbole terminale analyse.
456  */
457 int lexecho(FILE *f, int token)
458 {
459 lex_loop:
460  for (; chtbl[(int)CURC] == SPCT; mysptr++) /* saute les espaces */
461  fwrite(mysptr, 1, 1, f);
462 
463  switch (chtbl[(int)CURC]) {
464 
465  case NULT:
466  mytext = mysptr; /* sauvegarde le jeton */
467  mysptr++;
468  if (token != *mytext)
469  fwrite(mytext, 1, 1, f);
470  return (*mytext);
471  break;
472  case EOBT:
473  next_source();
474  goto lex_loop;
475  break;
476  case EOFT:
477  mytext = mysptr; /* sauvegarde le jeton */
478  return (T_EOF);
479  break;
480  case EOLT:
481  fwrite(mysptr, 1, 1, f);
482  if (mysptr == lastline)
483  next_source();
484  else
485  mysptr++;
486  mylineno++;
487  myline = mysptr;
488  goto lex_loop;
489  break;
490  case CMTT:
491  fwrite(mysptr, 1, 1, f);
492  mytext = mysptr; /* sauvegarde le jeton */
493  mysptr++;
494  if (CURC != '*')
495  return (*mytext);
496  fwrite(mysptr, 1, 1, f);
497  mysptr++;
498  comment:
499  for (; iscmtt((int)CURC); mysptr++)
500  fwrite(mysptr, 1, 1, f);
501  switch (chtbl[(int)CURC]) {
502  case EOBT:
503  next_source();
504  goto comment;
505  break;
506  case EOFT:
507  lexerr("start", lex_errtbl[E_CMT_EOF], NULL);
508  return (T_EOF);
509  break;
510  case EOLT:
511  fwrite(mysptr, 1, 1, f);
512  if (mysptr == lastline)
513  next_source();
514  else
515  mysptr++;
516  mylineno++;
517  myline = mysptr;
518  goto comment;
519  break;
520  case CMTT:
521  fwrite(mysptr, 1, 1, f);
522  if (PREVC == '*') { /* veritable fin */
523  mysptr++;
524  goto lex_loop;
525  }
526  mysptr++; /* pseudo fin */
527  goto comment;
528  break;
529  }
530  break;
531  case IDNT:
532  mytext = mysptr; /* sauvegarde le jeton */
533  mysptr++;
534  for (; isidnt((int)CURC); mysptr++) {
535  };
536  mylength = (int)(mysptr - mytext);
537  if (token != get_symbol(mytext, mylength))
538  fwrite(mytext, (size_t)mylength, 1, f);
539  return (get_symbol(mytext, mylength));
540  break;
541  case INTT:
542  mytext = mysptr; /* sauvegarde le jeton */
543  int_part:
544  mysptr++;
545  for (; isintt((int)CURC); mysptr++) {
546  };
547  switch (CURC) {
548  case '.': /* lecture fraction */
549  float_part:
550  mysptr++;
551  for (; isintt((int)CURC); mysptr++) {
552  };
553  if (CURC != 'E' && CURC != 'e') {
554  if (token != T_FLOAT)
555  fwrite(mytext, (size_t)(mysptr - mytext), 1, f);
556  return (T_FLOAT);
557  }
558  break;
559  case 'E': /* lecture exposant */
560  case 'e':
561  mysptr++;
562  if (isintt((int)CURC))
563  mysptr++;
564  else if (issgnt((int)CURC) && isintt((int)NEXTC))
565  mysptr += 2;
566  else {
567  mysptr--;
568  if (token != T_FLOAT)
569  fwrite(mytext, (size_t)(mysptr - mytext), 1, f);
570  return (T_FLOAT);
571  }
572  for (; isintt((int)CURC); mysptr++) {
573  };
574  if (token != T_FLOAT)
575  fwrite(mytext, (size_t)(mysptr - mytext), 1, f);
576  return (T_FLOAT);
577  break;
578  default:
579  if (token != T_INT)
580  fwrite(mytext, (size_t)(mysptr - mytext), 1, f);
581  return (T_INT);
582  break;
583  }
584  break;
585  case FPTT:
586  mytext = mysptr; /* sauvegarde le jeton */
587  mysptr++;
588  if (!isintt((int)CURC)) { /* pas de fraction */
589  if (token != *mytext)
590  fwrite(mytext, 1, 1, f);
591  return (*mytext);
592  }
593  goto float_part;
594  break;
595  case SGNT:
596  mytext = mysptr; /* sauvegarde le jeton */
597  mysptr++;
598  if (isintt((int)CURC))
599  goto int_part;
600  if (isfptt((int)CURC) && isintt((int)NEXTC))
601  goto float_part;
602  if (token != *mytext)
603  fwrite(mytext, 1, 1, f);
604  return (*mytext);
605  break;
606  case STGT:
607  fwrite(mysptr, 1, 1, f);
608  mytext = mysptr; /* sauvegarde le jeton */
609  mysptr++;
610  string:
611  for (; isstgt((int)CURC); mysptr++)
612  fwrite(mysptr, 1, 1, f);
613  switch (chtbl[(int)CURC]) {
614  case EOBT:
615  next_source();
616  goto comment;
617  break;
618  case EOFT:
619  lexerr("start", lex_errtbl[E_STG_EOF], NULL);
620  return (T_EOF);
621  break;
622  case EOLT:
623  lexerr("start", lex_errtbl[E_STG_EOL], NULL);
624  return ('\n');
625  break;
626  case STGT:
627  fwrite(mysptr, 1, 1, f);
628  if (PREVC != '\\') { /* veritable fin */
629  mytext++;
630  mylength = (int)(mysptr - mytext);
631  mysptr++;
632  return (T_STRING);
633  }
634  mysptr++; /* pseudo fin */
635  goto string;
636  break;
637  }
638  break;
639  default:
640  fwrite(mysptr, 1, 1, f);
641  mysptr++;
642  goto lex_loop;
643  break;
644  }
645  return (T_EOF);
646 }
647 
648 #undef BUFSIZE
649 #undef LINESIZE
650 #undef TEXTSIZE
651 
652 #define BUFSIZE (BUFSIZ << 5)
653 #define LINESIZE (BUFSIZ - 1)
654 #define TEXTSIZE (1 + LINESIZE + BUFSIZE + 1)
655 
656 static FILE *fds; /* descripteur du fichier source */
657 static char *source; /* nom du fichier du programme source */
658 static char *botbuf; /* fond du buffer d'entree du fichier */
659 static char *buf; /* base du buffer d'entree du fichier */
660 static char *topbuf; /* sommet du buffer d'entree du fichier */
661 
662 /*
663  * La procedure "unlex" recule la tete de lecture devant le dernier jeton.
664  */
665 void unlex(void) { mysptr = mytext; }
666 
667 /*
668  * La procedure "open_source" alloue et initialise les variables utilisees
669  * pour la gestion des entrees du programme source.
670  * Entree :
671  * fd Fichier du programme source.
672  * sptr Nom du fichier du programme source.
673  */
674 void open_source(FILE *fd, const char *str)
675 {
676  if ((source = (char *)malloc((strlen(str) + 1) * sizeof(char))) == NULL) {
677  static char proc_name[] = "open_source";
678  perror(proc_name);
679  exit(1);
680  }
681  strcpy(source, str);
682  if ((botbuf = (char *)malloc(TEXTSIZE * sizeof(char))) == NULL) {
683  static char proc_name[] = "open_source";
684  perror(proc_name);
685  exit(1);
686  }
687  fds = fd;
688  buf = botbuf + 1 + LINESIZE;
689  topbuf = buf + 1;
690  mylineno = 1;
691  next_source();
692 }
693 
694 /*
695  * La procedure "close_source" libere les variables utilisees pour la gestion
696  * des entrees du programme source.
697  */
698 void close_source(void)
699 {
700  free((char *)source);
701  free((char *)botbuf);
702 }
703 
704 /*
705  * La procedure "next_source" remplit le buffer courant.
706  */
707 static void next_source(void)
708 {
709  size_t size;
710  char *bot = buf;
711  char *top = topbuf;
712 
713  /* recopie la derniere ligne devant "buf" */
714 
715  *bot = EOL; /* evite le debordement de "buf" */
716  while ((*--bot = *--top) != EOL) {
717  };
718  myline = mysptr = bot + 1;
719 
720  size = fread(buf, sizeof(char), BUFSIZE, fds);
721  if (size == 0) {
722  topbuf = buf + 1;
723  *buf = EOF;
724  *topbuf = EOB; /* sentinelle de fin de fichier */
725  mysptr = buf;
726  } else {
727  topbuf = buf + size;
728  *topbuf = EOB; /* sentinelle de fin de buffer */
729 
730  /* recherche de la derniere ligne */
731  top = topbuf;
732  while (*--top != EOL) {
733  };
734  lastline = top;
735  }
736 }
737 
738 /*
739  * ERR_STACK : Pile des messages d'erreur.
740  * La pile est geree par les procedures "poperr", "popuperr" et "pusherr".
741  * Les messages sont affiches par les procedures "count" et "lexerr".
742  */
743 #define ERR_STACK_MAX 32
744 
745 static const char *err_stack[ERR_STACK_MAX];
746 static int size_stack = 0;
747 
748 /*
749  * La procedure "count" calcule la distance en espaces entre
750  * le premier caractere "*mytext" et le caractere de debut de ligne "*myline".
751  */
752 static void count(void)
753 {
754  char *str;
755 
756  mycolumno = 0;
757  for (str = myline; str <= mytext; str++) {
758  (*str == '\t') ? mycolumno += 8 - (mycolumno % 8) : mycolumno++;
759  }
760 }
761 
762 /*
763  * La procedure "lexerr" affiche les messages d'erreur.
764  * 1 elle affiche la ligne d'erreur du fichier source.
765  * 2 elle indique la position de l'erreur dans la ligne.
766  * 3 elle affiche les messages d'erreur contenus dans la pile.
767  * 4 elle affiche les messages d'erreur en parametre.
768  * Entree :
769  * va_list Liste de messages d'erreur terminee par NULL.
770  */
771 
772 // lexerr (va_alist)
773 // va_dcl
774 
775 void lexerr(const char *path, ...)
776 {
777  va_list ap;
778  char *cp;
779  int i;
780 
781  /* Pointe sur le caractere fautif. */
782 
783  count();
784  // write (STDERR, myline, mysptr - myline);
785  fprintf(stderr, "\n%*c\n\"%s\", line %d:\n", mycolumno, '^', source, mylineno);
786 
787  /* Affiche les messages d'erreur de la pile. */
788 
789  for (i = 0; i < size_stack; i++)
790  fprintf(stderr, "%s", err_stack[i]);
791 
792  /* Affiche les messages d'erreur en parametres. */
793 
794  va_start(ap, path);
795  while ((cp = (char *)va_arg(ap, char *)) != NULL)
796  fprintf(stderr, "%s", cp);
797  fprintf(stderr, "\n");
798  va_end(ap);
799 
800  exit(1);
801 }
802 
803 /*
804  * La procedure "poperr" depile le message d'erreur du sommet de pile.
805  */
806 void poperr(void)
807 {
808  if (--size_stack < 0) {
809  static char proc_name[] = "poperr";
810  fprintf(stderr, "%s: error stack underflow\n", proc_name);
811  exit(1);
812  }
813 }
814 
815 /*
816  * La procedure "popup_error" remplace le message d'erreur du sommet de pile.
817  */
818 void popuperr(const char *str)
819 {
820  if (size_stack <= 0) {
821  static const char proc_name[] = "popuerr";
822  fprintf(stderr, "%s: error stack underflow\n", proc_name);
823  exit(1);
824  }
825  err_stack[size_stack - 1] = str;
826 }
827 
828 /*
829  * La procedure "pusherr" empile le message d'erreur.
830  */
831 void pusherr(const char *str)
832 {
833  if (size_stack >= ERR_STACK_MAX) {
834  static const char proc_name[] = "pusherr";
835  fprintf(stderr, "%s: error stack overflow\n", proc_name);
836  exit(1);
837  }
838  err_stack[size_stack++] = str;
839 }
840 
841 #endif