ROS 2 rclcpp + rcl - rolling  rolling-e7363f10
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 <stddef.h>
16 
17 #include "rcl/allocator.h"
18 #include "rcl/error_handling.h"
19 #include "rcl/lexer_lookahead.h"
20 #include "rcl/types.h"
21 
23 {
24  // Text that is being analyzed for lexemes
25  const char * text;
26  // Where in the text analysis is being performed
27  size_t text_idx;
28 
29  // first character of lexeme
30  size_t start[2];
31  // One past last character of lexeme
32  size_t end[2];
33  // Type of lexeme
34  rcl_lexeme_t type[2];
35 
36  // Allocator to use if an error occurs
37  rcl_allocator_t allocator;
38 };
39 
42 {
43  // All members are initialized to 0 or NULL by C99 6.7.8/10.
44  static rcl_lexer_lookahead2_t zero_initialized;
45  return zero_initialized;
46 }
47 
50  rcl_lexer_lookahead2_t * buffer,
51  const char * text,
52  rcl_allocator_t allocator)
53 {
54  RCUTILS_CAN_SET_MSG_AND_RETURN_WITH_ERROR_OF(RCL_RET_INVALID_ARGUMENT);
55  RCUTILS_CAN_SET_MSG_AND_RETURN_WITH_ERROR_OF(RCL_RET_BAD_ALLOC);
56 
57  RCL_CHECK_ALLOCATOR_WITH_MSG(&allocator, "invalid allocator", return RCL_RET_INVALID_ARGUMENT);
58  RCL_CHECK_ARGUMENT_FOR_NULL(buffer, RCL_RET_INVALID_ARGUMENT);
59  RCL_CHECK_ARGUMENT_FOR_NULL(text, RCL_RET_INVALID_ARGUMENT);
60  if (NULL != buffer->impl) {
61  RCL_SET_ERROR_MSG("buffer must be zero initialized");
63  }
64 
65  buffer->impl = allocator.allocate(sizeof(rcl_lexer_lookahead2_impl_t), allocator.state);
66  RCL_CHECK_FOR_NULL_WITH_MSG(
67  buffer->impl, "Failed to allocate lookahead impl", return RCL_RET_BAD_ALLOC);
68 
69  buffer->impl->text = text;
70  buffer->impl->text_idx = 0u;
71  buffer->impl->start[0] = 0u;
72  buffer->impl->start[1] = 0u;
73  buffer->impl->end[0] = 0u;
74  buffer->impl->end[1] = 0u;
75  buffer->impl->type[0] = RCL_LEXEME_NONE;
76  buffer->impl->type[1] = RCL_LEXEME_NONE;
77  buffer->impl->allocator = allocator;
78 
79  return RCL_RET_OK;
80 }
81 
84  rcl_lexer_lookahead2_t * buffer)
85 {
86  RCL_CHECK_ARGUMENT_FOR_NULL(buffer, RCL_RET_INVALID_ARGUMENT);
87  RCL_CHECK_FOR_NULL_WITH_MSG(
88  buffer->impl, "buffer finalized twice", return RCL_RET_INVALID_ARGUMENT);
90  &(buffer->impl->allocator), "invalid allocator", return RCL_RET_INVALID_ARGUMENT);
91 
92  buffer->impl->allocator.deallocate(buffer->impl, buffer->impl->allocator.state);
93  buffer->impl = NULL;
94  return RCL_RET_OK;
95 }
96 
99  rcl_lexer_lookahead2_t * buffer,
100  rcl_lexeme_t * next_type)
101 {
102  RCUTILS_CAN_SET_MSG_AND_RETURN_WITH_ERROR_OF(RCL_RET_INVALID_ARGUMENT);
103 
104  RCL_CHECK_ARGUMENT_FOR_NULL(buffer, RCL_RET_INVALID_ARGUMENT);
105  RCL_CHECK_FOR_NULL_WITH_MSG(
106  buffer->impl, "buffer not initialized", return RCL_RET_INVALID_ARGUMENT);
107  RCL_CHECK_ARGUMENT_FOR_NULL(next_type, RCL_RET_INVALID_ARGUMENT);
108 
109  rcl_ret_t ret;
110  size_t length;
111 
112  if (buffer->impl->text_idx >= buffer->impl->end[0]) {
113  // No buffered lexeme; get one
114  ret = rcl_lexer_analyze(
116  &(buffer->impl->type[0]),
117  &length);
118 
119  if (RCL_RET_OK != ret) {
120  return ret;
121  }
122 
123  buffer->impl->start[0] = buffer->impl->text_idx;
124  buffer->impl->end[0] = buffer->impl->start[0] + length;
125  }
126 
127  *next_type = buffer->impl->type[0];
128  return RCL_RET_OK;
129 }
130 
131 rcl_ret_t
133  rcl_lexer_lookahead2_t * buffer,
134  rcl_lexeme_t * next_type1,
135  rcl_lexeme_t * next_type2)
136 {
137  RCUTILS_CAN_SET_MSG_AND_RETURN_WITH_ERROR_OF(RCL_RET_INVALID_ARGUMENT);
138 
139  rcl_ret_t ret;
140  // Peek 1 ahead first (reusing its error checking for buffer and next_type1)
141  ret = rcl_lexer_lookahead2_peek(buffer, next_type1);
142  if (RCL_RET_OK != ret) {
143  return ret;
144  }
145  RCL_CHECK_ARGUMENT_FOR_NULL(next_type2, RCL_RET_INVALID_ARGUMENT);
146 
147  if (RCL_LEXEME_NONE == *next_type1 || RCL_LEXEME_EOF == *next_type1) {
148  // No need to peek further
149  *next_type2 = *next_type1;
150  return ret;
151  }
152 
153  size_t length;
154 
155  if (buffer->impl->text_idx >= buffer->impl->end[1]) {
156  // No buffered lexeme; get one
157  ret = rcl_lexer_analyze(
158  &(buffer->impl->text[buffer->impl->end[0]]),
159  &(buffer->impl->type[1]),
160  &length);
161 
162  if (RCL_RET_OK != ret) {
163  return ret;
164  }
165 
166  buffer->impl->start[1] = buffer->impl->end[0];
167  buffer->impl->end[1] = buffer->impl->start[1] + length;
168  }
169 
170  *next_type2 = buffer->impl->type[1];
171  return RCL_RET_OK;
172 }
173 
174 rcl_ret_t
176  rcl_lexer_lookahead2_t * buffer,
177  const char ** lexeme_text,
178  size_t * lexeme_text_length)
179 {
180  RCUTILS_CAN_SET_MSG_AND_RETURN_WITH_ERROR_OF(RCL_RET_INVALID_ARGUMENT);
181  RCUTILS_CAN_SET_MSG_AND_RETURN_WITH_ERROR_OF(RCL_RET_ERROR);
182 
183  RCL_CHECK_ARGUMENT_FOR_NULL(buffer, RCL_RET_INVALID_ARGUMENT);
184  RCL_CHECK_FOR_NULL_WITH_MSG(
185  buffer->impl, "buffer not initialized", return RCL_RET_INVALID_ARGUMENT);
186  if (
187  (NULL == lexeme_text && NULL != lexeme_text_length) ||
188  (NULL != lexeme_text && NULL == lexeme_text_length))
189  {
190  RCL_SET_ERROR_MSG("text and length must both be set or both be NULL");
192  }
193 
194  if (RCL_LEXEME_EOF == buffer->impl->type[0]) {
195  // Reached EOF, nothing to accept
196  if (NULL != lexeme_text && NULL != lexeme_text_length) {
197  *lexeme_text = rcl_lexer_lookahead2_get_text(buffer);
198  *lexeme_text_length = 0u;
199  }
200  return RCL_RET_OK;
201  }
202 
203  if (buffer->impl->text_idx >= buffer->impl->end[0]) {
204  RCL_SET_ERROR_MSG("no lexeme to accept");
205  return RCL_RET_ERROR;
206  }
207 
208  if (NULL != lexeme_text && NULL != lexeme_text_length) {
209  *lexeme_text = &(buffer->impl->text[buffer->impl->start[0]]);
210  *lexeme_text_length = buffer->impl->end[0] - buffer->impl->start[0];
211  }
212 
213  // Advance lexer position
214  buffer->impl->text_idx = buffer->impl->end[0];
215 
216  // Move second lexeme in buffer to first position
217  buffer->impl->start[0] = buffer->impl->start[1];
218  buffer->impl->end[0] = buffer->impl->end[1];
219  buffer->impl->type[0] = buffer->impl->type[1];
220 
221  return RCL_RET_OK;
222 }
223 
224 rcl_ret_t
226  rcl_lexer_lookahead2_t * buffer,
227  rcl_lexeme_t type,
228  const char ** lexeme_text,
229  size_t * lexeme_text_length)
230 {
231  RCUTILS_CAN_SET_MSG_AND_RETURN_WITH_ERROR_OF(RCL_RET_WRONG_LEXEME);
232 
233  rcl_ret_t ret;
234  rcl_lexeme_t lexeme;
235 
236  ret = rcl_lexer_lookahead2_peek(buffer, &lexeme);
237  if (RCL_RET_OK != ret) {
238  return ret;
239  }
240  if (type != lexeme) {
241  if (RCL_LEXEME_NONE == lexeme || RCL_LEXEME_EOF == lexeme) {
242  RCL_SET_ERROR_MSG_WITH_FORMAT_STRING(
243  "Expected lexeme type (%d) not found, search ended at index %zu",
244  type, buffer->impl->text_idx);
245  return RCL_RET_WRONG_LEXEME;
246  }
247  RCL_SET_ERROR_MSG_WITH_FORMAT_STRING(
248  "Expected lexeme type %d, got %d at index %zu", type, lexeme,
249  buffer->impl->text_idx);
250  return RCL_RET_WRONG_LEXEME;
251  }
252  return rcl_lexer_lookahead2_accept(buffer, lexeme_text, lexeme_text_length);
253 }
254 
255 const char *
257  const rcl_lexer_lookahead2_t * buffer)
258 {
259  return &(buffer->impl->text[buffer->impl->text_idx]);
260 }
#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:35
@ RCL_LEXEME_EOF
Indicates end of input has been reached.
Definition: lexer.h:37
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:601
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:110
#define RCL_RET_OK
Success return code.
Definition: types.h:28
#define RCL_RET_BAD_ALLOC
Failed to allocate memory return code.
Definition: types.h:34
#define RCL_RET_INVALID_ARGUMENT
Invalid argument return code.
Definition: types.h:36
#define RCL_RET_ERROR
Unspecified error return code.
Definition: types.h:30
rmw_ret_t rcl_ret_t
The type that holds an rcl return code.
Definition: types.h:25