3 * $Id: parser.y,v 1.14 2007/11/11 22:35:51 khansen Exp $
5 * Revision 1.14 2007/11/11 22:35:51 khansen
8 * Revision 1.13 2007/08/19 11:19:47 khansen
9 * --case-insensitive option
11 * Revision 1.12 2007/08/12 18:59:00 khansen
12 * ability to generate pure 6502 binary
14 * Revision 1.11 2007/08/11 01:25:50 khansen
15 * includepaths support (-I option)
17 * Revision 1.10 2007/07/22 13:34:38 khansen
18 * convert tabs to whitespaces
20 * Revision 1.9 2005/01/05 02:28:40 kenth
21 * anonymous union parsing
23 * Revision 1.8 2004/12/29 21:45:26 kenth
27 * Revision 1.7 2004/12/19 19:59:14 kenth
30 * Revision 1.6 2004/12/16 13:22:27 kenth
33 * Revision 1.5 2004/12/14 01:50:42 kenth
36 * Revision 1.4 2004/12/11 02:12:41 kenth
39 * Revision 1.3 2004/12/09 11:17:15 kenth
40 * added: warning_statement, error_statement
42 * Revision 1.2 2004/12/06 05:06:21 kenth
45 * Revision 1.1 2004/06/30 07:57:03 kenth
57 void yyerror(const char *); /* In lexer */
58 int yylex(void); /* In lexer */
59 int yypushandrestart
(const char *, int); /* In lexer */
60 void __yy_memcpy
(char *, char *, int);
61 extern
char *yytext
; /* In lexer */
62 extern
YYLTYPE yylloc; /* In lexer */
63 char *scan_include
(int); /* In lexer */
64 extern astnode
*root_node
; /* Root of the generated parse tree */
65 void handle_incsrc
(astnode
*); /* See below */
66 void handle_incbin
(astnode
*); /* See below */
80 %token
<integer
> INTEGER_LITERAL
81 %token
<string> STRING_LITERAL
82 %token
<string> FILE_PATH
83 %token
<ident
> IDENTIFIER
84 %token
<ident
> LOCAL_ID
85 %token
<ident
> FORWARD_BRANCH
86 %token
<ident
> BACKWARD_BRANCH
88 %token
<label
> LOCAL_LABEL
89 %token
<mnemonic
> MNEMONIC
91 %type
<node
> identifier identifier_opt local_id assembly_unit statement labelable_statement statement_list if_statement elif_statement elif_statement_list elif_statement_list_opt ifdef_statement ifndef_statement macro_decl_statement macro_statement instruction_statement data_statement storage_statement null_statement incsrc_statement incbin_statement equ_statement assign_statement public_statement extrn_statement dataseg_statement codeseg_statement charmap_statement struc_decl_statement union_decl_statement enum_decl_statement record_decl_statement instruction expression extended_expression expression_opt arithmetic_expression comparison_expression literal label label_decl identifier_list expression_list file_specifier param_list_opt arg_list_opt else_part_opt scope_access struc_access struc_initializer field_initializer_list field_initializer_list_opt field_initializer datatype storage named_data_statement unnamed_data_statement named_storage_statement unnamed_storage_statement proc_statement rept_statement label_statement message_statement warning_statement error_statement while_statement define_statement align_statement org_statement symbol_type enum_item_list enum_item record_field_list record_field sizeof_arg label_addr_part_opt label_type_part_opt from_part_opt indexed_identifier
93 %token _LABEL_ BYTE CHAR WORD DWORD DSB DSW DSD DATASEG CODESEG IF IFDEF IFNDEF ELSE ELIF ENDIF INCSRC INCBIN MACRO REPT WHILE ENDM ALIGN EQU DEFINE END PUBLIC EXTRN CHARMAP STRUC UNION ENDS RECORD ENUM ENDE PROC ENDP SIZEOF MASK TAG MESSAGE WARNING ERROR ZEROPAGE ORG
112 %left LE_OP GE_OP
'>' '<'
123 statement_list end_opt
{ root_node
= astnode_create_list
($1); }
132 labelable_statement
{ $$
= $1; }
133 | statement_list labelable_statement
{
134 if
($1 != NULL
) { $$
= $1; astnode_add_sibling
($$
, $2); }
140 label_decl statement
{ $$
= $1; astnode_add_sibling
($$
, $2); }
141 | statement
{ $$
= $1; }
145 if_statement
{ $$
= $1; }
146 | ifdef_statement
{ $$
= $1; }
147 | ifndef_statement
{ $$
= $1; }
148 | macro_decl_statement
{ $$
= $1; }
149 | macro_statement
{ $$
= $1; }
150 | incsrc_statement
{ $$
= $1; }
151 | incbin_statement
{ $$
= $1; }
152 | equ_statement
{ $$
= $1; }
153 | assign_statement
{ $$
= $1; }
154 | public_statement
{ $$
= $1; }
155 | extrn_statement
{ $$
= $1; }
156 | instruction_statement
{ $$
= $1; }
157 | data_statement
{ $$
= $1; }
158 | storage_statement
{ $$
= $1; }
159 | dataseg_statement
{ $$
= $1; }
160 | codeseg_statement
{ $$
= $1; }
161 | charmap_statement
{ $$
= $1; }
162 | struc_decl_statement
{ $$
= $1; }
163 | union_decl_statement
{ $$
= $1; }
164 | enum_decl_statement
{ $$
= $1; }
165 | record_decl_statement
{ $$
= $1; }
166 | proc_statement
{ $$
= $1; }
167 | rept_statement
{ $$
= $1; }
168 | while_statement
{ $$
= $1; }
169 | label_statement
{ $$
= $1; }
170 | message_statement
{ $$
= $1; }
171 | warning_statement
{ $$
= $1; }
172 | error_statement
{ $$
= $1; }
173 | define_statement
{ $$
= $1; }
174 | align_statement
{ $$
= $1; }
175 | org_statement
{ $$
= $1; }
176 | null_statement
{ $$
= $1; }
177 |
error line_tail
{ $$
= NULL
; }
181 ORG expression line_tail
{ $$
= astnode_create_org
($2, @$
); }
185 ALIGN identifier_list expression line_tail
{ $$
= astnode_create_align
($2, $3, @$
); }
189 WARNING expression line_tail
{ $$
= astnode_create_warning
($2, @$
); }
193 ERROR expression line_tail
{ $$
= astnode_create_error
($2, @$
); }
197 MESSAGE expression line_tail
{ $$
= astnode_create_message
($2, @$
); }
201 _LABEL_ identifier label_addr_part_opt label_type_part_opt line_tail
{ $$
= astnode_create_label
($2->label
, $3, $4, @$
); }
205 '=' expression
{ $$
= $2; }
210 ':' symbol_type
{ $$
= $2; }
215 WHILE expression line_tail statement_list ENDM line_tail
{ $$
= astnode_create_while
($2, $4, @$
); }
219 REPT expression line_tail statement_list ENDM line_tail
{ $$
= astnode_create_rept
($2, $4, @$
); }
223 PROC identifier line_tail statement_list ENDP line_tail
{ $$
= astnode_create_proc
($2, $4, @$
); }
226 struc_decl_statement:
227 STRUC identifier line_tail statement_list ENDS line_tail
{ $$
= astnode_create_struc_decl
($2, $4, @$
); }
230 union_decl_statement:
231 UNION identifier_opt line_tail statement_list ENDS line_tail
{ $$
= astnode_create_union_decl
($2, $4, @$
); }
235 ENUM identifier line_tail enum_item_list ENDE line_tail
{ $$
= astnode_create_enum_decl
($2, $4, @$
); }
239 enum_item
{ $$
= $1; }
240 | enum_item_list enum_item
{ $$
= $1; astnode_add_sibling
($$
, $2); }
244 assign_statement
{ $$
= $1; }
245 | identifier line_tail
{ $$
= $1; }
248 record_decl_statement:
249 RECORD identifier record_field_list line_tail
{ $$
= astnode_create_record_decl
($2, $3, @$
); }
253 record_field
{ $$
= $1; }
254 | record_field_list
',' record_field
{ $$
= $1; astnode_add_sibling
($$
, $3); }
258 identifier
':' expression
{ $$
= astnode_create_bitfield_decl
($1, $3, @$
); }
262 CHARMAP file_specifier line_tail
{ $$
= astnode_create_charmap
($2, @$
); }
266 DATASEG line_tail
{ $$
= astnode_create_dataseg
(0, @$
); }
267 | DATASEG ZEROPAGE line_tail
{ $$
= astnode_create_dataseg
(ZEROPAGE_FLAG
, @$
); }
270 CODESEG line_tail
{ $$
= astnode_create_codeseg
(@$
); }
274 line_tail
{ $$
= NULL
; }
290 instruction_statement:
291 instruction line_tail
{ $$
= $1; }
295 MNEMONIC
{ $$
= astnode_create_instruction
($1, IMPLIED_MODE
, NULL
, @$
); }
296 | MNEMONIC
'A' { $$
= astnode_create_instruction
($1, ACCUMULATOR_MODE
, NULL
, @$
); }
297 | MNEMONIC
'#' expression
{ $$
= astnode_create_instruction
($1, IMMEDIATE_MODE
, $3, @$
); }
298 | MNEMONIC expression
{ $$
= astnode_create_instruction
($1, ABSOLUTE_MODE
, $2, @$
); }
299 | MNEMONIC expression
',' 'X' { $$
= astnode_create_instruction
($1, ABSOLUTE_X_MODE
, $2, @$
); }
300 | MNEMONIC expression
',' 'Y' { $$
= astnode_create_instruction
($1, ABSOLUTE_Y_MODE
, $2, @$
); }
301 | MNEMONIC
'[' expression
',' 'X' ']' { $$
= astnode_create_instruction
($1, PREINDEXED_INDIRECT_MODE
, $3, @$
); }
302 | MNEMONIC
'[' expression
']' ',' 'Y' { $$
= astnode_create_instruction
($1, POSTINDEXED_INDIRECT_MODE
, $3, @$
); }
303 | MNEMONIC
'[' expression
']' { $$
= astnode_create_instruction
($1, INDIRECT_MODE
, $3, @$
); }
307 indexed_identifier
{ $$
= $1; }
308 | SIZEOF sizeof_arg
{ $$
= astnode_create_sizeof
($2, @$
); }
309 | scope_access
{ $$
= $1; }
310 | struc_access
{ $$
= $1; }
311 | local_id
{ $$
= $1; }
312 | literal
{ $$
= $1; }
313 |
'$' { $$
= astnode_create_pc
(@$
); }
314 | arithmetic_expression
{ $$
= $1; }
315 | comparison_expression
{ $$
= $1; }
316 |
'(' expression
')' { $$
= $2; }
317 |
'+' { $$
= astnode_create_forward_branch
("+", @$
); }
318 |
'-' { $$
= astnode_create_backward_branch
("-", @$
); }
319 | FORWARD_BRANCH
{ $$
= astnode_create_forward_branch
($1, @$
); }
320 | BACKWARD_BRANCH
{ $$
= astnode_create_backward_branch
($1, @$
); }
321 | MASK scope_access
{ $$
= astnode_create_mask
($2, @$
); }
325 identifier
{ $$
= $1; }
326 | identifier
'[' expression
']' { $$
= astnode_create_index
($1, $3, @$
); }
327 | identifier
'(' expression
')' { $$
= astnode_create_index
($1, $3, @$
); }
331 expression
{ $$
= $1; }
332 | struc_initializer
{ $$
= $1; }
336 identifier
{ $$
= $1; }
337 | datatype
{ $$
= $1; }
341 expression
{ $$
= $1; }
346 identifier SCOPE_OP identifier
{ $$
= astnode_create_scope
($1, $3, @$
); }
350 indexed_identifier
'.' struc_access
{ $$
= astnode_create_dot
($1, $3, @$
); }
351 | indexed_identifier
'.' indexed_identifier
{ $$
= astnode_create_dot
($1, $3, @$
); }
355 '{' field_initializer_list_opt
'}' { $$
= astnode_create_struc
($2, @$
); }
358 field_initializer_list_opt:
359 field_initializer_list
{ $$
= $1; }
363 field_initializer_list:
364 field_initializer
{ $$
= $1; }
365 | field_initializer_list
',' field_initializer
{ $$
= $1; astnode_add_sibling
($$
, $3); }
369 extended_expression
{ $$
= $1; }
370 |
{ $$
= astnode_create_null
(@$
); }
374 LOCAL_ID
{ $$
= astnode_create_local_id
($1, @$
); }
377 arithmetic_expression:
378 expression
'+' expression
{ $$
= astnode_create_arithmetic
(PLUS_OPERATOR
, $1, $3, @$
); }
379 | expression
'-' expression
{ $$
= astnode_create_arithmetic
(MINUS_OPERATOR
, $1, $3, @$
); }
380 | expression
'*' expression
{ $$
= astnode_create_arithmetic
(MUL_OPERATOR
, $1, $3, @$
); }
381 | expression
'/' expression
{ $$
= astnode_create_arithmetic
(DIV_OPERATOR
, $1, $3, @$
); }
382 | expression
'%' expression
{ $$
= astnode_create_arithmetic
(MOD_OPERATOR
, $1, $3, @$
); }
383 | expression
'&' expression
{ $$
= astnode_create_arithmetic
(AND_OPERATOR
, $1, $3, @$
); }
384 | expression
'|' expression
{ $$
= astnode_create_arithmetic
(OR_OPERATOR
, $1, $3, @$
); }
385 | expression
'^' expression
{ $$
= astnode_create_arithmetic
(XOR_OPERATOR
, $1, $3, @$
); }
386 | expression SHL_OP expression
{ $$
= astnode_create_arithmetic
(SHL_OPERATOR
, $1, $3, @$
); }
387 | expression SHR_OP expression
{ $$
= astnode_create_arithmetic
(SHR_OPERATOR
, $1, $3, @$
); }
388 |
'~' expression
{ $$
= astnode_create_arithmetic
(NEG_OPERATOR
, $2, NULL
, @$
); }
389 |
'!' expression
{ $$
= astnode_create_arithmetic
(NOT_OPERATOR
, $2, NULL
, @$
); }
390 |
'^' identifier
{ $$
= astnode_create_arithmetic
(BANK_OPERATOR
, $2, NULL
, @$
); }
391 |
'<' expression %prec LO_OP
{ $$
= astnode_create_arithmetic
(LO_OPERATOR
, $2, NULL
, @$
); }
392 |
'>' expression %prec HI_OP
{ $$
= astnode_create_arithmetic
(HI_OPERATOR
, $2, NULL
, @$
); }
393 |
'-' expression %prec UMINUS
{ $$
= astnode_create_arithmetic
(UMINUS_OPERATOR
, $2, NULL
, @$
); }
396 comparison_expression:
397 expression EQ_OP expression
{ $$
= astnode_create_arithmetic
(EQ_OPERATOR
, $1, $3, @$
); }
398 | expression NE_OP expression
{ $$
= astnode_create_arithmetic
(NE_OPERATOR
, $1, $3, @$
); }
399 | expression
'>' expression
{ $$
= astnode_create_arithmetic
(GT_OPERATOR
, $1, $3, @$
); }
400 | expression
'<' expression
{ $$
= astnode_create_arithmetic
(LT_OPERATOR
, $1, $3, @$
); }
401 | expression GE_OP expression
{ $$
= astnode_create_arithmetic
(GE_OPERATOR
, $1, $3, @$
); }
402 | expression LE_OP expression
{ $$
= astnode_create_arithmetic
(LE_OPERATOR
, $1, $3, @$
); }
406 LABEL
{ $$
= astnode_create_label
($1, NULL
, NULL
, @$
); }
407 | LOCAL_LABEL
{ $$
= astnode_create_local_label
($1, @$
); }
408 |
'+' { $$
= astnode_create_forward_branch_decl
("+", @$
); }
409 |
'-' { $$
= astnode_create_backward_branch_decl
("-", @$
); }
410 | FORWARD_BRANCH
{ $$
= astnode_create_forward_branch_decl
($1, @$
); }
411 | BACKWARD_BRANCH
{ $$
= astnode_create_backward_branch_decl
($1, @$
); }
415 IDENTIFIER
{ $$
= astnode_create_identifier
($1, @$
); }
419 identifier
{ $$
= $1; }
420 |
{ $$
= astnode_create_null
(@$
); }
424 INTEGER_LITERAL
{ $$
= astnode_create_integer
($1, @$
); }
425 | STRING_LITERAL
{ $$
= astnode_create_string
($1, @$
); }
429 IF expression line_tail statement_list elif_statement_list_opt else_part_opt ENDIF line_tail
{ $$
= astnode_create_if
($2, $4, $5, $6, @$
); }
432 elif_statement_list_opt:
433 elif_statement_list
{ $$
= $1; }
438 elif_statement
{ $$
= $1; }
439 | elif_statement_list elif_statement
{ $$
= $1; astnode_add_sibling
($$
, $2); }
443 ELIF expression line_tail statement_list
{ $$
= astnode_create_case
($2, $4, @$
); }
447 ELSE line_tail statement_list
{ $$
= $3; }
452 IFDEF identifier line_tail statement_list else_part_opt ENDIF line_tail
{ $$
= astnode_create_ifdef
($2, $4, $5, @$
); }
456 IFNDEF identifier line_tail statement_list else_part_opt ENDIF line_tail
{ $$
= astnode_create_ifndef
($2, $4, $5, @$
); }
460 named_data_statement line_tail
{ $$
= $1; }
461 | unnamed_data_statement line_tail
{ $$
= $1; }
464 named_data_statement:
465 identifier unnamed_data_statement
{ $$
= astnode_create_var_decl
(0, $1, $2, @$
); }
466 | ZEROPAGE identifier unnamed_data_statement
{ $$
= astnode_create_var_decl
(ZEROPAGE_FLAG
, $2, $3, @$
); }
467 | PUBLIC identifier unnamed_data_statement
{ $$
= astnode_create_var_decl
(PUBLIC_FLAG
, $2, $3, @$
); }
468 | ZEROPAGE PUBLIC identifier unnamed_data_statement
{ $$
= astnode_create_var_decl
(ZEROPAGE_FLAG | PUBLIC_FLAG
, $3, $4, @$
); }
469 | PUBLIC ZEROPAGE identifier unnamed_data_statement
{ $$
= astnode_create_var_decl
(PUBLIC_FLAG | ZEROPAGE_FLAG
, $3, $4, @$
); }
472 unnamed_data_statement:
473 datatype expression_list
{ $$
= astnode_create_data
($1, $2, @$
); }
474 | datatype
{ $$
= astnode_create_storage
($1, NULL
, @$
); }
475 | datatype
'[' expression
']' { $$
= astnode_create_storage
($1, $3, @$
); }
479 BYTE
{ $$
= astnode_create_datatype
(BYTE_DATATYPE
, NULL
, @$
); }
480 | CHAR
{ $$
= astnode_create_datatype
(CHAR_DATATYPE
, NULL
, @$
); }
481 | WORD
{ $$
= astnode_create_datatype
(WORD_DATATYPE
, NULL
, @$
); }
482 | DWORD
{ $$
= astnode_create_datatype
(DWORD_DATATYPE
, NULL
, @$
); }
483 | TAG identifier
{ $$
= astnode_create_datatype
(USER_DATATYPE
, $2, @$
); }
484 |
'.' identifier
{ $$
= astnode_create_datatype
(USER_DATATYPE
, $2, @$
); }
488 extended_expression
{ $$
= $1; }
489 | expression_list
',' extended_expression
{ $$
= $1; astnode_add_sibling
($$
, $3); }
493 INCSRC file_specifier line_tail
{ $$
= astnode_create_incsrc
($2, @$
); handle_incsrc
($$
); }
497 INCBIN file_specifier line_tail
{ $$
= astnode_create_incbin
($2, @$
); handle_incbin
($$
); }
501 STRING_LITERAL
{ $$
= astnode_create_string
($1, @$
); }
502 |
'<' { $$
= astnode_create_file_path
(scan_include
('>'), @$
); }
505 macro_decl_statement:
506 MACRO identifier param_list_opt line_tail statement_list ENDM line_tail
{ $$
= astnode_create_macro_decl
($2, $3, $5, @$
); }
510 identifier_list
{ $$
= $1; }
515 identifier arg_list_opt line_tail
{ $$
= astnode_create_macro
($1, $2, @$
); }
519 expression_list
{ $$
= $1; }
524 identifier
{ $$
= $1; }
525 | identifier_list
',' identifier
{ $$
= $1; astnode_add_sibling
($$
, $3); }
529 identifier EQU extended_expression line_tail
{ $$
= astnode_create_equ
($1, $3, @$
); }
533 identifier
'=' extended_expression line_tail
{ $$
= astnode_create_assign
($1, $3, @$
); }
537 DEFINE identifier line_tail
{ $$
= astnode_create_equ
($2, astnode_create_integer
(0, @$
), @$
); }
538 | DEFINE identifier extended_expression line_tail
{ $$
= astnode_create_equ
($2, $3, @$
); }
542 PUBLIC identifier_list line_tail
{ $$
= astnode_create_public
($2, @$
); }
546 EXTRN identifier_list
':' symbol_type from_part_opt line_tail
{ $$
= astnode_create_extrn
($2, $4, $5, @$
); }
550 '@' identifier
{ $$
= $2; }
555 datatype
{ $$
= $1; }
556 | identifier
{ $$
= astnode_create_datatype
(USER_DATATYPE
, $1, @$
); }
557 | PROC
{ $$
= astnode_create_integer
(PROC_SYMBOL
, @$
); }
558 | _LABEL_
{ $$
= astnode_create_integer
(LABEL_SYMBOL
, @$
); }
562 named_storage_statement
{ $$
= $1; }
563 | unnamed_storage_statement
{ $$
= $1; }
566 named_storage_statement:
567 identifier unnamed_storage_statement
{ $$
= astnode_create_var_decl
(0, $1, $2, @$
); }
568 | ZEROPAGE identifier unnamed_storage_statement
{ $$
= astnode_create_var_decl
(ZEROPAGE_FLAG
, $2, $3, @$
); }
569 | PUBLIC identifier unnamed_storage_statement
{ $$
= astnode_create_var_decl
(PUBLIC_FLAG
, $2, $3, @$
); }
570 | ZEROPAGE PUBLIC identifier unnamed_storage_statement
{ $$
= astnode_create_var_decl
(ZEROPAGE_FLAG | PUBLIC_FLAG
, $3, $4, @$
); }
571 | PUBLIC ZEROPAGE identifier unnamed_storage_statement
{ $$
= astnode_create_var_decl
(PUBLIC_FLAG | ZEROPAGE_FLAG
, $3, $4, @$
); }
574 unnamed_storage_statement:
575 storage expression_opt line_tail
{ $$
= astnode_create_storage
($1, $2, @$
); }
579 DSB
{ $$
= astnode_create_datatype
(BYTE_DATATYPE
, NULL
, @$
); }
580 | DSW
{ $$
= astnode_create_datatype
(WORD_DATATYPE
, NULL
, @$
); }
581 | DSD
{ $$
= astnode_create_datatype
(DWORD_DATATYPE
, NULL
, @$
); }
585 * Takes care of switching to a new scanner input stream when a "incsrc" statement
586 * has been encountered.
587 * The current stream is pushed on a stack, and will be popped when EOF is reached
589 * @param n A node of type INCSRC_NODE
591 void handle_incsrc
(astnode
*n
)
594 /* Get the node which describes the file to include */
595 astnode
*file
= astnode_get_child
(n
, 0);
596 int quoted_form
= (astnode_get_type
(file
) == STRING_NODE
) ?
1 : 0;
597 switch
(yypushandrestart
(file
->string, quoted_form
)) {
602 /* Failed to open file */
603 sprintf
(errs
, "could not open '%s' for reading", file
->string);
608 yyerror("Maximum include nesting level reached");
613 // TODO: This shouldn't be done here but rather in astproc module.
615 FILE *open_included_file
(const char *, int, char **);
618 * Takes care of including the binary contents of the file specified by a parsed
619 * "incbin" statement.
620 * Calls yyerror() if the file can't be included for some reason.
621 * @param n A node of type INCBIN_NODE
623 void handle_incbin
(astnode
*n
)
629 /* Get the node which describes the file to include */
630 astnode
*file
= astnode_get_child
(n
, 0);
631 const char *filename
= file
->string;
632 int quoted_form
= (astnode_get_type
(file
) == STRING_NODE
) ?
1 : 0;
634 fp
= open_included_file
(filename
, quoted_form
, NULL
);
637 fseek
(fp
, 0, SEEK_END
);
641 /* Allocate buffer to hold file contents */
642 data
= (unsigned char *)malloc
(size
);
643 /* Read file contents into buffer */
644 fread
(data
, 1, size
, fp
);
645 /* Insert binary node */
646 astnode_add_sibling
(n
, astnode_create_binary
(data
, size
, n
->loc
) );
651 /* Couldn't open file */
652 sprintf
(errs
, "could not open '%s' for reading", file
->string);