ROS 2 rclcpp + rcl - humble  humble
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  static rcl_lexer_lookahead2_t zero_initialized = {
40  .impl = NULL,
41  };
42  return zero_initialized;
43 }
44 
47  rcl_lexer_lookahead2_t * buffer,
48  const char * text,
49  rcl_allocator_t allocator)
50 {
51  RCUTILS_CAN_SET_MSG_AND_RETURN_WITH_ERROR_OF(RCL_RET_INVALID_ARGUMENT);
52  RCUTILS_CAN_SET_MSG_AND_RETURN_WITH_ERROR_OF(RCL_RET_BAD_ALLOC);
53 
54  RCL_CHECK_ALLOCATOR_WITH_MSG(&allocator, "invalid allocator", return RCL_RET_INVALID_ARGUMENT);
55  RCL_CHECK_ARGUMENT_FOR_NULL(buffer, RCL_RET_INVALID_ARGUMENT);
56  RCL_CHECK_ARGUMENT_FOR_NULL(text, RCL_RET_INVALID_ARGUMENT);
57  if (NULL != buffer->impl) {
58  RCL_SET_ERROR_MSG("buffer must be zero initialized");
60  }
61 
62  buffer->impl = allocator.allocate(sizeof(rcl_lexer_lookahead2_impl_t), allocator.state);
63  RCL_CHECK_FOR_NULL_WITH_MSG(
64  buffer->impl, "Failed to allocate lookahead impl", return RCL_RET_BAD_ALLOC);
65 
66  buffer->impl->text = text;
67  buffer->impl->text_idx = 0u;
68  buffer->impl->start[0] = 0u;
69  buffer->impl->start[1] = 0u;
70  buffer->impl->end[0] = 0u;
71  buffer->impl->end[1] = 0u;
72  buffer->impl->type[0] = RCL_LEXEME_NONE;
73  buffer->impl->type[1] = RCL_LEXEME_NONE;
74  buffer->impl->allocator = allocator;
75 
76  return RCL_RET_OK;
77 }
78 
81  rcl_lexer_lookahead2_t * buffer)
82 {
83  RCL_CHECK_ARGUMENT_FOR_NULL(buffer, RCL_RET_INVALID_ARGUMENT);
84  RCL_CHECK_FOR_NULL_WITH_MSG(
85  buffer->impl, "buffer finalized twice", return RCL_RET_INVALID_ARGUMENT);
87  &(buffer->impl->allocator), "invalid allocator", return RCL_RET_INVALID_ARGUMENT);
88 
89  buffer->impl->allocator.deallocate(buffer->impl, buffer->impl->allocator.state);
90  buffer->impl = NULL;
91  return RCL_RET_OK;
92 }
93 
96  rcl_lexer_lookahead2_t * buffer,
97  rcl_lexeme_t * next_type)
98 {
99  RCUTILS_CAN_SET_MSG_AND_RETURN_WITH_ERROR_OF(RCL_RET_INVALID_ARGUMENT);
100 
101  RCL_CHECK_ARGUMENT_FOR_NULL(buffer, RCL_RET_INVALID_ARGUMENT);
102  RCL_CHECK_FOR_NULL_WITH_MSG(
103  buffer->impl, "buffer not initialized", return RCL_RET_INVALID_ARGUMENT);
104  RCL_CHECK_ARGUMENT_FOR_NULL(next_type, RCL_RET_INVALID_ARGUMENT);
105 
106  rcl_ret_t ret;
107  size_t length;
108 
109  if (buffer->impl->text_idx >= buffer->impl->end[0]) {
110  // No buffered lexeme; get one
111  ret = rcl_lexer_analyze(
113  &(buffer->impl->type[0]),
114  &length);
115 
116  if (RCL_RET_OK != ret) {
117  return ret;
118  }
119 
120  buffer->impl->start[0] = buffer->impl->text_idx;
121  buffer->impl->end[0] = buffer->impl->start[0] + length;
122  }
123 
124  *next_type = buffer->impl->type[0];
125  return RCL_RET_OK;
126 }
127 
128 rcl_ret_t
130  rcl_lexer_lookahead2_t * buffer,
131  rcl_lexeme_t * next_type1,
132  rcl_lexeme_t * next_type2)
133 {
134  RCUTILS_CAN_SET_MSG_AND_RETURN_WITH_ERROR_OF(RCL_RET_INVALID_ARGUMENT);
135 
136  rcl_ret_t ret;
137  // Peek 1 ahead first (reusing its error checking for buffer and next_type1)
138  ret = rcl_lexer_lookahead2_peek(buffer, next_type1);
139  if (RCL_RET_OK != ret) {
140  return ret;
141  }
142  RCL_CHECK_ARGUMENT_FOR_NULL(next_type2, RCL_RET_INVALID_ARGUMENT);
143 
144  if (RCL_LEXEME_NONE == *next_type1 || RCL_LEXEME_EOF == *next_type1) {
145  // No need to peek further
146  *next_type2 = *next_type1;
147  return ret;
148  }
149 
150  size_t length;
151 
152  if (buffer->impl->text_idx >= buffer->impl->end[1]) {
153  // No buffered lexeme; get one
154  ret = rcl_lexer_analyze(
155  &(buffer->impl->text[buffer->impl->end[0]]),
156  &(buffer->impl->type[1]),
157  &length);
158 
159  if (RCL_RET_OK != ret) {
160  return ret;
161  }
162 
163  buffer->impl->start[1] = buffer->impl->end[0];
164  buffer->impl->end[1] = buffer->impl->start[1] + length;
165  }
166 
167  *next_type2 = buffer->impl->type[1];
168  return RCL_RET_OK;
169 }
170 
171 rcl_ret_t
173  rcl_lexer_lookahead2_t * buffer,
174  const char ** lexeme_text,
175  size_t * lexeme_text_length)
176 {
177  RCUTILS_CAN_SET_MSG_AND_RETURN_WITH_ERROR_OF(RCL_RET_INVALID_ARGUMENT);
178  RCUTILS_CAN_SET_MSG_AND_RETURN_WITH_ERROR_OF(RCL_RET_ERROR);
179 
180  RCL_CHECK_ARGUMENT_FOR_NULL(buffer, RCL_RET_INVALID_ARGUMENT);
181  RCL_CHECK_FOR_NULL_WITH_MSG(
182  buffer->impl, "buffer not initialized", return RCL_RET_INVALID_ARGUMENT);
183  if (
184  (NULL == lexeme_text && NULL != lexeme_text_length) ||
185  (NULL != lexeme_text && NULL == lexeme_text_length))
186  {
187  RCL_SET_ERROR_MSG("text and length must both be set or both be NULL");
189  }
190 
191  if (RCL_LEXEME_EOF == buffer->impl->type[0]) {
192  // Reached EOF, nothing to accept
193  if (NULL != lexeme_text && NULL != lexeme_text_length) {
194  *lexeme_text = rcl_lexer_lookahead2_get_text(buffer);
195  *lexeme_text_length = 0u;
196  }
197  return RCL_RET_OK;
198  }
199 
200  if (buffer->impl->text_idx >= buffer->impl->end[0]) {
201  RCL_SET_ERROR_MSG("no lexeme to accept");
202  return RCL_RET_ERROR;
203  }
204 
205  if (NULL != lexeme_text && NULL != lexeme_text_length) {
206  *lexeme_text = &(buffer->impl->text[buffer->impl->start[0]]);
207  *lexeme_text_length = buffer->impl->end[0] - buffer->impl->start[0];
208  }
209 
210  // Advance lexer position
211  buffer->impl->text_idx = buffer->impl->end[0];
212 
213  // Move second lexeme in buffer to first position
214  buffer->impl->start[0] = buffer->impl->start[1];
215  buffer->impl->end[0] = buffer->impl->end[1];
216  buffer->impl->type[0] = buffer->impl->type[1];
217 
218  return RCL_RET_OK;
219 }
220 
221 rcl_ret_t
223  rcl_lexer_lookahead2_t * buffer,
224  rcl_lexeme_t type,
225  const char ** lexeme_text,
226  size_t * lexeme_text_length)
227 {
228  RCUTILS_CAN_SET_MSG_AND_RETURN_WITH_ERROR_OF(RCL_RET_WRONG_LEXEME);
229 
230  rcl_ret_t ret;
231  rcl_lexeme_t lexeme;
232 
233  ret = rcl_lexer_lookahead2_peek(buffer, &lexeme);
234  if (RCL_RET_OK != ret) {
235  return ret;
236  }
237  if (type != lexeme) {
238  if (RCL_LEXEME_NONE == lexeme || RCL_LEXEME_EOF == lexeme) {
239  RCL_SET_ERROR_MSG_WITH_FORMAT_STRING(
240  "Expected lexeme type (%d) not found, search ended at index %zu",
241  type, buffer->impl->text_idx);
242  return RCL_RET_WRONG_LEXEME;
243  }
244  RCL_SET_ERROR_MSG_WITH_FORMAT_STRING(
245  "Expected lexeme type %d, got %d at index %zu", type, lexeme,
246  buffer->impl->text_idx);
247  return RCL_RET_WRONG_LEXEME;
248  }
249  return rcl_lexer_lookahead2_accept(buffer, lexeme_text, lexeme_text_length);
250 }
251 
252 const char *
254  const rcl_lexer_lookahead2_t * buffer)
255 {
256  return &(buffer->impl->text[buffer->impl->text_idx]);
257 }
#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()
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:106
#define RCL_RET_OK
Success return code.
Definition: types.h:26
#define RCL_RET_BAD_ALLOC
Failed to allocate memory return code.
Definition: types.h:32
#define RCL_RET_INVALID_ARGUMENT
Invalid argument return code.
Definition: types.h:34
#define RCL_RET_ERROR
Unspecified error return code.
Definition: types.h:28
rmw_ret_t rcl_ret_t
The type that holds an rcl return code.
Definition: types.h:23