Visual Servoing Platform  version 3.6.1 under development (2024-11-15)
vpKeyword.cpp
1 /****************************************************************************
2  *
3  * ViSP, open source Visual Servoing Platform software.
4  * Copyright (C) 2005 - 2023 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 https://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 "keyword.c" contient les procedures de gestion
33  * des mots cles retournes par l'analyseur lexical "lex".
34  *
35  * Authors:
36  * Jean-Luc CORRE
37  *
38 *****************************************************************************/
39 
40 #include <visp3/core/vpConfig.h>
41 #include <visp3/core/vpException.h>
42 
43 #include "vpKeyword.h"
44 #include "vpMy.h"
45 #include "vpToken.h"
46 
47 #include <stdio.h>
48 #include <stdlib.h>
49 #include <string.h>
50 #ifndef DOXYGEN_SHOULD_SKIP_THIS
51 BEGIN_VISP_NAMESPACE
52 static void open_hash(void);
53 static void close_hash(void);
54 static int hashpjw(const char *str);
55 static void insert_keyword(const char *str, Index token);
56 
57 #ifdef debug
58 static void delete_keyword(void);
59 static char *get_keyword(void);
60 #endif /* debug */
61 
62 #define PRIME 211
63 #define NEXT(x) (x) = (x)->next
64 
65 typedef struct bucket
66 {
67  struct bucket *next; /* element suivant */
68  char *ident; /* identifateur */
69  Byte length; /* longueur de "ident" */
70  Index token; /* code du jeton */
71 } Bucket;
72 
73 static Bucket **hash_tbl; /* table de "hash-coding" */
74 
75 /*
76  * La procedure "open_keyword" alloue et initialise les variables utilisees
77  * par les procedures de gestion des mots cles.
78  * Entree :
79  * kwp Tableau des mots cles termine par NULL.
80  */
81 void open_keyword(Keyword *kwp)
82 {
83  open_hash();
84  for (; kwp->ident != NULL; kwp++) /* recopie les mots cles */
85  insert_keyword(kwp->ident, kwp->token);
86 }
87 
88 /*
89  * La procedure "close_keyword" libere les variables utilisees
90  * par les procedures de gestion des mots cles.
91  */
92 void close_keyword(void) { close_hash(); }
93 
94 /*
95  * La procedure "open_hash" alloue et initialise la table de codage.
96  */
97 static void open_hash(void)
98 {
99  Bucket **head, **bend;
100 
101  if ((hash_tbl = (Bucket **)malloc(sizeof(Bucket *) * PRIME)) == NULL) {
102  static char proc_name[] = "open_hash";
103  perror(proc_name);
104  throw vpException(vpException::fatalError, "Error in open_hash");
105  }
106  head = hash_tbl;
107  bend = head + PRIME;
108  for (; head < bend; *head++ = NULL) {
109  };
110 }
111 
112 /*
113  * La procedure "close_hash" libere la table de codage et ses elements.
114  */
115 static void close_hash(void)
116 {
117  Bucket **head = hash_tbl;
118  Bucket **bend = head + PRIME;
119  Bucket *bp; /* element courant */
120  Bucket *next; /* element suivant */
121 
122  for (; head < bend; head++) { /* libere les listes */
123  for (bp = *head; bp != NULL; bp = next) {
124  next = bp->next;
125  free((char *)bp);
126  }
127  }
128  free((char *)hash_tbl); /* libere la table */
129 }
130 
131 /*
132  * La procedure "hashpjw" calcule un indice code a partir de la chaine
133  * de caracteres "str".
134  * Pour plus de renseignements, voir :
135  * "Compilers. Principles, Techniques, and Tools",
136  * A.V. AHO, R. SETHI, J.D. ULLMAN,
137  * ADDISON-WESLEY PUBLISHING COMPANY, pp 436.
138  * Entree :
139  * str Chaine de caracteres a coder.
140  * Sortie :
141  * Le code de la chaine.
142  */
143 static int hashpjw(const char *str)
144 {
145  unsigned h = 0; /* "hash value" */
146 
147  for (; *str != '\0'; str++) {
148  unsigned g;
149  h = (h << 4) + (unsigned)(*str);
150  if ((g = h & ~0xfffffff) != 0) {
151  h ^= g >> 24;
152  h ^= g;
153  }
154  }
155  return ((int)(h % PRIME));
156 }
157 
158 /*
159  * La procedure "insert_keyword" insere en tete d'un point d'entree
160  * de la table de "hachage" le mot cle ayant pour identificateur
161  * la chaine de caracteres "str" et pour valeur "token".
162  * Entree :
163  * str Chaine de caracteres du mot cle.
164  * token Valeur du jeton associe au mot cle.
165  */
166 static void insert_keyword(const char *str, Index token)
167 {
168  Bucket **head = hash_tbl + hashpjw(str);
169  Bucket *bp;
170  Byte length;
171 
172  length = (Byte)(strlen(str)); // Warning! Overflow possible!
173  if ((bp = (Bucket *)malloc(sizeof(Bucket) + length + 1)) == NULL) {
174  static const char proc_name[] = "insert_keyword";
175  perror(proc_name);
176  throw vpException(vpException::fatalError, "Error in insert_keyword");
177  }
178  bp->length = length;
179  bp->token = token;
180  bp->ident = (char *)(bp + 1);
181  strcpy(bp->ident, str);
182 
183  bp->next = *head; /* insere "b" en tete de "head" */
184  *head = bp;
185 }
186 
187 /*
188  * La pocedure "get_symbol" verifie que la chaine pointee par "ident"
189  * de longeur "length" est un mot cle.
190  * Entree :
191  * ident Chaine de l'identificateur.
192  * length Nombre de caracteres de la chaine.
193  * Note :
194  * La chaine "ident" n'est pas terminee par '\0'.
195  * Sortie :
196  * Valeur du jeton associe si c'est un mot cle, 0 sinon.
197  */
198 Index get_symbol(char *ident, int length)
199 {
200  Bucket *bp;
201  const char *kwd;
202  char *idn = ident;
203  int len = length;
204 
205  { /* calcule le code de hachage (voir "hashpjw") */
206  unsigned h = 0; /* "hash value" */
207 
208  for (; len != 0; idn++, len--) {
209  unsigned g;
210  h = (h << 4) + (unsigned)(*idn);
211  if ((g = h & ~0xfffffff) != 0) {
212  h ^= g >> 24;
213  h ^= g;
214  }
215  }
216  bp = hash_tbl[h % PRIME];
217  }
218 
219  /* recherche le mot cle */
220 
221  for (; bp != NULL; NEXT(bp)) {
222  if (length == bp->length) {
223  idn = ident;
224  len = length;
225  kwd = bp->ident;
226  for (; *idn == *kwd; idn++, kwd++) {
227  --len;
228  if (len == 0)
229  return (bp->token);
230  }
231  }
232  }
233  return (0); /* identificateur */
234 }
235 END_VISP_NAMESPACE
236 #endif
error that can be emitted by ViSP classes.
Definition: vpException.h:60
@ fatalError
Fatal error.
Definition: vpException.h:72