ROS 2 rclcpp + rcl - rolling  rolling-a919a6e5
ROS 2 C++ Client Library with ROS Client Library
lexer_lookahead.c
1 // Copyright 2018 Open Source Robotics Foundation, Inc.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "rcl/error_handling.h"
16 #include "rcl/lexer_lookahead.h"
17 
19 {
20  // Text that is being analyzed for lexemes
21  const char * text;
22  // Where in the text analysis is being performed
23  size_t text_idx;
24 
25  // first character of lexeme
26  size_t start[2];
27  // One past last character of lexeme
28  size_t end[2];
29  // Type of lexeme
30  rcl_lexeme_t type[2];
31 
32  // Allocator to use if an error occurrs
33  rcl_allocator_t allocator;
34 };
35 
38 {
39  // All members are initialized to 0 or NULL by C99 6.7.8/10.
40  static rcl_lexer_lookahead2_t zero_initialized;
41  return zero_initialized;
42 }
43 
46  rcl_lexer_lookahead2_t * buffer,
47  const char * text,
48  rcl_allocator_t allocator)
49 {
50  RCUTILS_CAN_SET_MSG_AND_RETURN_WITH_ERROR_OF(RCL_RET_INVALID_ARGUMENT);
51  RCUTILS_CAN_SET_MSG_AND_RETURN_WITH_ERROR_OF(RCL_RET_BAD_ALLOC);
52 
53  RCL_CHECK_ALLOCATOR_WITH_MSG(&allocator, "invalid allocator", return RCL_RET_INVALID_ARGUMENT);
54  RCL_CHECK_ARGUMENT_FOR_NULL(buffer, RCL_RET_INVALID_ARGUMENT);
55  RCL_CHECK_ARGUMENT_FOR_NULL(text, RCL_RET_INVALID_ARGUMENT);
56  if (NULL != buffer->impl) {
57  RCL_SET_ERROR_MSG("buffer must be zero initialized");
59  }
60 
61  buffer->impl = allocator.allocate(sizeof(rcl_lexer_lookahead2_impl_t), allocator.state);
62  RCL_CHECK_FOR_NULL_WITH_MSG(
63  buffer->impl, "Failed to allocate lookahead impl", return RCL_RET_BAD_ALLOC);
64 
65  buffer->impl->text = text;
66  buffer->impl->text_idx = 0u;
67  buffer->impl->start[0] = 0u;
68  buffer->impl->start[1] = 0u;
69  buffer->impl->end[0] = 0u;
70  buffer->impl->end[1] = 0u;
71  buffer->impl->type[0] = RCL_LEXEME_NONE;
72  buffer->impl->type[1] = RCL_LEXEME_NONE;
73  buffer->impl->allocator = allocator;
74 
75  return RCL_RET_OK;
76 }
77 
80  rcl_lexer_lookahead2_t * buffer)
81 {
82  RCL_CHECK_ARGUMENT_FOR_NULL(buffer, RCL_RET_INVALID_ARGUMENT);
83  RCL_CHECK_FOR_NULL_WITH_MSG(
84  buffer->impl, "buffer finalized twice", return RCL_RET_INVALID_ARGUMENT);
86  &(buffer->impl->allocator), "invalid allocator", return RCL_RET_INVALID_ARGUMENT);
87 
88  buffer->impl->allocator.deallocate(buffer->impl, buffer->impl->allocator.state);
89  buffer->impl = NULL;
90  return RCL_RET_OK;
91 }
92 
95  rcl_lexer_lookahead2_t * buffer,
96  rcl_lexeme_t * next_type)
97 {
98  RCUTILS_CAN_SET_MSG_AND_RETURN_WITH_ERROR_OF(RCL_RET_INVALID_ARGUMENT);
99 
100  RCL_CHECK_ARGUMENT_FOR_NULL(buffer, RCL_RET_INVALID_ARGUMENT);
101  RCL_CHECK_FOR_NULL_WITH_MSG(
102  buffer->impl, "buffer not initialized", return RCL_RET_INVALID_ARGUMENT);
103  RCL_CHECK_ARGUMENT_FOR_NULL(next_type, RCL_RET_INVALID_ARGUMENT);
104 
105  rcl_ret_t ret;
106  size_t length;
107 
108  if (buffer->impl->text_idx >= buffer->impl->end[0]) {
109  // No buffered lexeme; get one
110  ret = rcl_lexer_analyze(
112  &(buffer->impl->type[0]),
113  &length);
114 
115  if (RCL_RET_OK != ret) {
116  return ret;
117  }
118 
119  buffer->impl->start[0] = buffer->impl->text_idx;
120  buffer->impl->end[0] = buffer->impl->start[0] + length;
121  }
122 
123  *next_type = buffer->impl->type[0];
124  return RCL_RET_OK;
125 }
126 
127 rcl_ret_t
129  rcl_lexer_lookahead2_t * buffer,
130  rcl_lexeme_t * next_type1,
131  rcl_lexeme_t * next_type2)
132 {
133  RCUTILS_CAN_SET_MSG_AND_RETURN_WITH_ERROR_OF(RCL_RET_INVALID_ARGUMENT);
134 
135  rcl_ret_t ret;
136  // Peek 1 ahead first (reusing its error checking for buffer and next_type1)
137  ret = rcl_lexer_lookahead2_peek(buffer, next_type1);
138  if (RCL_RET_OK != ret) {
139  return ret;
140  }
141  RCL_CHECK_ARGUMENT_FOR_NULL(next_type2, RCL_RET_INVALID_ARGUMENT);
142 
143  if (RCL_LEXEME_NONE == *next_type1 || RCL_LEXEME_EOF == *next_type1) {
144  // No need to peek further
145  *next_type2 = *next_type1;
146  return ret;
147  }
148 
149  size_t length;
150 
151  if (buffer->impl->text_idx >= buffer->impl->end[1]) {
152  // No buffered lexeme; get one
153  ret = rcl_lexer_analyze(
154  &(buffer->impl->text[buffer->impl->end[0]]),
155  &(buffer->impl->type[1]),
156  &length);
157 
158  if (RCL_RET_OK != ret) {
159  return ret;
160  }
161 
162  buffer->impl->start[1] = buffer->impl->end[0];
163  buffer->impl->end[1] = buffer->impl->start[1] + length;
164  }
165 
166  *next_type2 = buffer->impl->type[1];
167  return RCL_RET_OK;
168 }
169 
170 rcl_ret_t
172  rcl_lexer_lookahead2_t * buffer,
173  const char ** lexeme_text,
174  size_t * lexeme_text_length)
175 {
176  RCUTILS_CAN_SET_MSG_AND_RETURN_WITH_ERROR_OF(RCL_RET_INVALID_ARGUMENT);
177  RCUTILS_CAN_SET_MSG_AND_RETURN_WITH_ERROR_OF(RCL_RET_ERROR);
178 
179  RCL_CHECK_ARGUMENT_FOR_NULL(buffer, RCL_RET_INVALID_ARGUMENT);
180  RCL_CHECK_FOR_NULL_WITH_MSG(
181  buffer->impl, "buffer not initialized", return RCL_RET_INVALID_ARGUMENT);
182  if (
183  (NULL == lexeme_text && NULL != lexeme_text_length) ||
184  (NULL != lexeme_text && NULL == lexeme_text_length))
185  {
186  RCL_SET_ERROR_MSG("text and length must both be set or both be NULL");
188  }
189 
190  if (RCL_LEXEME_EOF == buffer->impl->type[0]) {
191  // Reached EOF, nothing to accept
192  if (NULL != lexeme_text && NULL != lexeme_text_length) {
193  *lexeme_text = rcl_lexer_lookahead2_get_text(buffer);
194  *lexeme_text_length = 0u;
195  }
196  return RCL_RET_OK;
197  }
198 
199  if (buffer->impl->text_idx >= buffer->impl->end[0]) {
200  RCL_SET_ERROR_MSG("no lexeme to accept");
201  return RCL_RET_ERROR;
202  }
203 
204  if (NULL != lexeme_text && NULL != lexeme_text_length) {
205  *lexeme_text = &(buffer->impl->text[buffer->impl->start[0]]);
206  *lexeme_text_length = buffer->impl->end[0] - buffer->impl->start[0];
207  }
208 
209  // Advance lexer position
210  buffer->impl->text_idx = buffer->impl->end[0];
211 
212  // Move second lexeme in buffer to first position
213  buffer->impl->start[0] = buffer->impl->start[1];
214  buffer->impl->end[0] = buffer->impl->end[1];
215  buffer->impl->type[0] = buffer->impl->type[1];
216 
217  return RCL_RET_OK;
218 }
219 
220 rcl_ret_t
222  rcl_lexer_lookahead2_t * buffer,
223  rcl_lexeme_t type,
224  const char ** lexeme_text,
225  size_t * lexeme_text_length)
226 {
227  RCUTILS_CAN_SET_MSG_AND_RETURN_WITH_ERROR_OF(RCL_RET_WRONG_LEXEME);
228 
229  rcl_ret_t ret;
230  rcl_lexeme_t lexeme;
231 
232  ret = rcl_lexer_lookahead2_peek(buffer, &lexeme);
233  if (RCL_RET_OK != ret) {
234  return ret;
235  }
236  if (type != lexeme) {
237  if (RCL_LEXEME_NONE == lexeme || RCL_LEXEME_EOF == lexeme) {
238  RCL_SET_ERROR_MSG_WITH_FORMAT_STRING(
239  "Expected lexeme type (%d) not found, search ended at index %zu",
240  type, buffer->impl->text_idx);
241  return RCL_RET_WRONG_LEXEME;
242  }
243  RCL_SET_ERROR_MSG_WITH_FORMAT_STRING(
244  "Expected lexeme type %d, got %d at index %zu", type, lexeme,
245  buffer->impl->text_idx);
246  return RCL_RET_WRONG_LEXEME;
247  }
248  return rcl_lexer_lookahead2_accept(buffer, lexeme_text, lexeme_text_length);
249 }
250 
251 const char *
253  const rcl_lexer_lookahead2_t * buffer)
254 {
255  return &(buffer->impl->text[buffer->impl->text_idx]);
256 }
#define RCL_CHECK_ALLOCATOR_WITH_MSG(allocator, msg, fail_statement)
Check that the given allocator is initialized, or fail with a message.
Definition: allocator.h:56
rcutils_allocator_t rcl_allocator_t
Encapsulation of an allocator.
Definition: allocator.h:31
@ RCL_LEXEME_NONE
Indicates no valid lexeme was found (end of input not reached)
Definition: lexer.h:36
@ RCL_LEXEME_EOF
Indicates end of input has been reached.
Definition: lexer.h:38
enum rcl_lexeme_e rcl_lexeme_t
Type of lexeme found by lexical analysis.
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_lexer_analyze(const char *text, rcl_lexeme_t *lexeme, size_t *length)
Do lexical analysis on a string.
Definition: lexer.c:598
RCL_PUBLIC RCL_WARN_UNUSED rcl_lexer_lookahead2_t rcl_get_zero_initialized_lexer_lookahead2(void)
Get a zero initialized rcl_lexer_lookahead2_t instance.
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_lexer_lookahead2_fini(rcl_lexer_lookahead2_t *buffer)
Finalize an instance of an rcl_lexer_lookahead2_t structure.
RCL_PUBLIC RCL_WARN_UNUSED const char * rcl_lexer_lookahead2_get_text(const rcl_lexer_lookahead2_t *buffer)
Get the text at the point where it is currently being analyzed.
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_lexer_lookahead2_peek2(rcl_lexer_lookahead2_t *buffer, rcl_lexeme_t *next_type1, rcl_lexeme_t *next_type2)
Look ahead at the next two lexemes in the string.
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_lexer_lookahead2_accept(rcl_lexer_lookahead2_t *buffer, const char **lexeme_text, size_t *lexeme_text_length)
Accept a lexeme and advance analysis.
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_lexer_lookahead2_expect(rcl_lexer_lookahead2_t *buffer, rcl_lexeme_t type, const char **lexeme_text, size_t *lexeme_text_length)
Require the next lexeme to be a certain type and advance analysis.
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_lexer_lookahead2_peek(rcl_lexer_lookahead2_t *buffer, rcl_lexeme_t *next_type)
Look ahead at the next lexeme in the string.
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_lexer_lookahead2_init(rcl_lexer_lookahead2_t *buffer, const char *text, rcl_allocator_t allocator)
Initialize an rcl_lexer_lookahead2_t instance.
Track lexical analysis and allow looking ahead 2 lexemes.
rcl_lexer_lookahead2_impl_t * impl
Pointer to the lexer look ahead2 implementation.
#define RCL_RET_WRONG_LEXEME
Expected one type of lexeme but got another.
Definition: types.h:109
#define RCL_RET_OK
Success return code.
Definition: types.h:27
#define RCL_RET_BAD_ALLOC
Failed to allocate memory return code.
Definition: types.h:33
#define RCL_RET_INVALID_ARGUMENT
Invalid argument return code.
Definition: types.h:35
#define RCL_RET_ERROR
Unspecified error return code.
Definition: types.h:29
rmw_ret_t rcl_ret_t
The type that holds an rcl return code.
Definition: types.h:24