1
/* Copyright (c) 1994, Joseph Arceneaux. All rights reserved
3
* Copyright (c) 1992, Free Software Foundation, Inc. All rights reserved.
5
* Copyright (c) 1985 Sun Microsystems, Inc. Copyright (c) 1980 The Regents
6
* of the University of California. Copyright (c) 1976 Board of Trustees of
7
* the University of Illinois. All rights reserved.
9
* Redistribution and use in source and binary forms are permitted
11
* the above copyright notice and this paragraph are duplicated in all such
12
* forms and that any documentation, advertising materials, and other
13
* materials related to such distribution and use acknowledge that the
14
* software was developed by the University of California, Berkeley, the
15
* University of Illinois, Urbana, and Sun Microsystems, Inc. The name of
16
* either University or Sun Microsystems may not be used to endorse or
17
* promote products derived from this software without specific prior written
18
* permission. THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
19
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES
20
* OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
24
/* Here we have the token scanner for indent. It scans off one token and
25
* puts it in the global variable "token". It returns a code, indicating the
26
* type of token scanned. */
30
#if defined (HAVE_UNISTD_H)
37
RCSTAG_CC ("$Id: lexi.c,v 1.32 2001/11/26 21:50:49 david Exp $");
39
/* Stuff that needs to be shared with the rest of indent. Documented in
53
/* Pointer to a vector of keywords specified by the user. */
54
static struct templ *user_specials = 0;
56
/* Allocated size of user_specials. */
57
static unsigned int user_specials_max;
59
/* Index in user_specials of the first unused entry. */
60
static unsigned int user_specials_idx;
62
char chartype[] = { /* this is used to facilitate the decision of
63
what type (alphanumeric, operator) each
65
#ifndef CHARSET_EBCDIC
67
0, 0, 0, 0, 0, 0, 0, 0,
68
0, 0, 0, 0, 0, 0, 0, 0,
69
0, 0, 0, 0, 0, 0, 0, 0,
70
0, 0, 0, 0, 0, 0, 0, 0,
71
0, 3, 0, 0, 1, 3, 3, 0,
72
0, 0, 3, 3, 0, 3, 0, 3,
73
1, 1, 1, 1, 1, 1, 1, 1,
74
1, 1, 0, 0, 3, 3, 3, 3,
75
0, 1, 1, 1, 1, 1, 1, 1,
76
1, 1, 1, 1, 1, 1, 1, 1,
77
1, 1, 1, 1, 1, 1, 1, 1,
78
1, 1, 1, 0, 0, 0, 3, 1,
79
0, 1, 1, 1, 1, 1, 1, 1,
80
1, 1, 1, 1, 1, 1, 1, 1,
81
1, 1, 1, 1, 1, 1, 1, 1,
82
1, 1, 1, 0, 3, 0, 3, 0,
83
0, 0, 0, 0, 0, 0, 0, 0,
84
0, 0, 0, 0, 0, 0, 0, 0,
85
0, 0, 0, 0, 0, 0, 0, 0,
86
0, 0, 0, 0, 0, 0, 0, 0,
87
0, 0, 0, 0, 0, 0, 0, 0,
88
0, 0, 0, 0, 0, 0, 0, 0,
89
0, 0, 0, 0, 0, 0, 0, 0,
90
0, 0, 0, 0, 0, 0, 0, 0,
91
0, 0, 0, 0, 0, 0, 0, 0,
92
0, 0, 0, 0, 0, 0, 0, 0,
93
0, 0, 0, 0, 0, 0, 0, 0,
94
0, 0, 0, 0, 0, 0, 0, 0,
95
0, 0, 0, 0, 0, 0, 0, 0,
96
0, 0, 0, 0, 0, 0, 0, 0,
97
0, 0, 0, 0, 0, 0, 0, 0,
98
0, 0, 0, 0, 0, 0, 0, 0,
100
#else /* CHARSET_EBCDIC */
103
* The following table was generated by the program given at the end
106
0, 0, 0, 0, 0, 0, 0, 0, /*|........| */
107
0, 0, 0, 0, 0, 0, 0, 0, /*|........| */
108
0, 0, 0, 0, 0, 0, 0, 0, /*|........| */
109
0, 0, 0, 0, 0, 0, 0, 0, /*|........| */
110
0, 0, 0, 0, 0, 0, 0, 0, /*|........| */
111
0, 0, 0, 0, 0, 0, 0, 0, /*|........| */
112
0, 0, 0, 0, 0, 0, 0, 0, /*|........| */
113
0, 0, 0, 0, 0, 0, 0, 0, /*|........| */
114
0, 0, 0, 0, 0, 0, 0, 0, /*| .......| */
115
0, 0, 0, 0, 3, 0, 3, 3, /*|..`.<(+|| */
116
3, 0, 0, 0, 0, 0, 0, 0, /*|&.......| */
117
0, 0, 3, 1, 3, 0, 0, 0, /*|..!$*);.| */
118
3, 3, 0, 0, 0, 0, 0, 0, /*|-/......| */
119
0, 0, 3, 0, 3, 1, 3, 3, /*|..^,%_>?| */
120
0, 0, 0, 0, 0, 0, 0, 0, /*|........| */
121
0, 0, 0, 0, 0, 0, 3, 0, /*|..:#@'="| */
122
0, 1, 1, 1, 1, 1, 1, 1, /*|.abcdefg| */
123
1, 1, 0, 0, 0, 0, 0, 0, /*|hi......| */
124
0, 1, 1, 1, 1, 1, 1, 1, /*|.jklmnop| */
125
1, 1, 0, 0, 0, 0, 0, 0, /*|qr......| */
126
0, 0, 1, 1, 1, 1, 1, 1, /*|..stuvwx| */
127
1, 1, 0, 0, 0, 0, 0, 0, /*|yz......| */
128
0, 0, 0, 0, 0, 0, 0, 0, /*|........| */
129
0, 0, 0, 0, 0, 0, 0, 0, /*|...[\]..| */
130
0, 1, 1, 1, 1, 1, 1, 1, /*|.ABCDEFG| */
131
1, 1, 0, 0, 0, 0, 0, 0, /*|HI......| */
132
0, 1, 1, 1, 1, 1, 1, 1, /*|.JKLMNOP| */
133
1, 1, 0, 0, 0, 0, 0, 0, /*|QR......| */
134
0, 0, 1, 1, 1, 1, 1, 1, /*|..STUVWX| */
135
1, 1, 0, 0, 0, 0, 0, 0, /*|YZ......| */
136
1, 1, 1, 1, 1, 1, 1, 1, /*|01234567| */
137
1, 1, 0, 0, 0, 0, 0, 3, /*|89.{.}.~| */
138
#endif /* CHARSET_EBCDIC */
142
* The table above was generated by the following program from
143
* the ASCII version of the chartype[] array above, where the
144
* unsigned char os_toascii[] array can be found in the source
145
* for the Apache Web Server version 1.3.x, in the directories...
146
* src/os/bs2000/ebcdic.c for the SIEMENS BS2000 mainframes,
147
* src/os/tpf/ebcdic.c for the IBM TPF server line.
148
* The following table was created for BS2000 EBCDIC character set,
149
* but the few non-zero places should be compatible with IBM's EBCDIC.
158
for (i = 0; i < 256; i += GAP)
161
for (j = 0; j < GAP; ++j)
163
printf ("%d, ", chartype[os_toascii[i + j]]);
168
for (j = 0; j < GAP; ++j)
170
printf ("%c", isprint (i + j) ? (i + j) : '.');
179
/* Include code generated by gperf */
184
struct templ *is_reserved (register const char *str, register unsigned int len);
188
/* Include code generated by gperf for C++ keyword set */
189
#undef MIN_HASH_VALUE /* remove old defs */
190
#undef MAX_HASH_VALUE
191
#undef TOTAL_KEYWORDS
192
#undef MIN_WORD_LENGTH
193
#undef MAX_WORD_LENGTH
199
struct templ *is_reserved_cc (register const char *str, register unsigned int len);
201
#include "gperf-cc.c"
203
enum codes lexi (void)
205
int unary_delim; /* this is set to 1 if the current token
206
forces a following operator to be unary */
207
static enum codes last_code; /* the last token type returned */
208
static int l_struct; /* set to 1 if the last token was 'struct' */
209
static int l_enum; /* set to 1 if the last token was `enum' */
210
enum codes code; /* internal code to be returned */
211
char qchar; /* the delimiter character for a string */
213
static int count; /* debugging counter */
218
/* tell world that this token started in column 1 iff the last
219
thing scanned was nl */
220
parser_state_tos->col_1 = parser_state_tos->last_nl;
221
parser_state_tos->last_saw_nl = parser_state_tos->last_nl;
222
parser_state_tos->last_nl = false;
224
if (buf_ptr >= buf_end)
229
if (*buf_ptr == ' ' || *buf_ptr == TAB)
231
parser_state_tos->col_1 = false;
232
while (*buf_ptr == ' ' || *buf_ptr == TAB)
234
if (++buf_ptr >= buf_end)
241
/* INCREDIBLY IMPORTANT WARNING!!!
243
* Note that subsequent calls to `fill_buffer ()' may switch `buf_ptr'
244
* to a different buffer. Thus when `token_end' gets set later, it
245
* may be pointing into a different buffer than `token'. */
249
/* Scan an alphanumeric token */
251
if ((!((buf_ptr[0] == 'L') &&
252
((buf_ptr[1] == '"') || (buf_ptr[1] == '\''))) &&
253
(chartype[0xff & (int) *buf_ptr] == alphanum)) ||
254
((buf_ptr[0] == '.') && isdigit (buf_ptr[1])))
256
/* we have a character or number */
259
if (isdigit (*buf_ptr) ||
260
((buf_ptr[0] == '.') && isdigit (buf_ptr[1])))
262
int seendot = 0, seenexp = 0;
264
if ((*buf_ptr == '0') && ((buf_ptr[1] == 'x') || (buf_ptr[1] == 'X')))
267
while (isxdigit (*buf_ptr))
289
if (!isdigit (*buf_ptr) && *buf_ptr != '.')
291
if ((*buf_ptr != 'E' && *buf_ptr != 'e') || seenexp)
301
if (*buf_ptr == '+' || *buf_ptr == '-')
309
if (*buf_ptr == 'F' || *buf_ptr == 'f' || *buf_ptr == 'i' || *buf_ptr == 'j')
315
while (*buf_ptr == 'U' || *buf_ptr == 'u' || *buf_ptr == 'L' || *buf_ptr == 'l')
322
while (chartype[0xff & (int) *buf_ptr] == alphanum)
326
if (buf_ptr >= buf_end)
334
if (token_end - token == 13 && !strncmp (token, "__attribute__", 13))
337
parser_state_tos->last_u_d = true;
341
while (*buf_ptr == ' ' || *buf_ptr == TAB)
343
if (++buf_ptr >= buf_end)
349
/* Handle operator declarations. */
351
if (token_end - token == 8 && !strncmp (token, "operator", 8))
353
while (chartype[0xff & (int) *buf_ptr] == opchar)
357
if (buf_ptr >= buf_end)
365
while (*buf_ptr == ' ' || *buf_ptr == TAB)
367
if (++buf_ptr >= buf_end)
372
parser_state_tos->its_a_keyword = false;
373
parser_state_tos->sizeof_keyword = false;
375
/* if last token was 'struct', then this token should be treated
381
parser_state_tos->last_u_d = true;
383
if (parser_state_tos->last_token == cpp_operator)
390
/* Operator after indentifier is binary */
392
parser_state_tos->last_u_d = false;
395
/* Check whether the token is a reserved word. Use perfect hashing... */
399
p = is_reserved_cc (token, token_end - token);
403
p = is_reserved (token, token_end - token);
406
if (!p && user_specials != 0)
408
for (p = &user_specials[0]; p < &user_specials[0] + user_specials_idx; p++)
413
/* This string compare is a little nonstandard because token
414
* ends at the character before token_end and p->rwd is
415
* null-terminated. */
419
/* If we have come to the end of both the keyword in
420
* user_specials and the keyword in token they are equal. */
422
if (q >= token_end && !*r)
427
/* If we have come to the end of just one, they are not
430
if (q >= token_end || !*r)
435
/* If the characters in corresponding characters are not
436
* equal, the strings are not equal. */
445
/* Didn't find anything in user_specials. */
451
{ /* we have a keyword */
456
parser_state_tos->its_a_keyword = true;
457
parser_state_tos->last_u_d = true;
458
parser_state_tos->last_rw = p->rwcode;
459
parser_state_tos->last_rw_depth = parser_state_tos->paren_depth;
463
case rw_operator: /* C++ operator overloading. */
464
value = cpp_operator;
465
parser_state_tos->in_parameter_declaration = 1;
467
case rw_switch: /* it is a switch */
470
case rw_case: /* a case or default */
474
l_enum = true; /* reset on '(' ')' '{' '}' or ';' */
476
case rw_struct_like: /* a "struct" */
477
if (parser_state_tos->p_l_follow && !(parser_state_tos->noncast_mask & 1 << parser_state_tos->p_l_follow))
478
/* inside parens: cast */
480
parser_state_tos->cast_mask |= 1 << parser_state_tos->p_l_follow;
486
/* Next time around, we will want to know that we have had a
488
case rw_decl: /* one of the declaration keywords */
489
if (parser_state_tos->p_l_follow && !(parser_state_tos->noncast_mask & 1 << parser_state_tos->p_l_follow))
490
/* inside parens: cast */
492
parser_state_tos->cast_mask |= 1 << parser_state_tos->p_l_follow;
500
case rw_sp_paren: /* if, while, for */
502
if (*token == 'i' && parser_state_tos->last_token == sp_else)
504
parser_state_tos->i_l_follow -= ind_size;
509
case rw_sp_nparen: /* do */
513
case rw_sp_else: /* else */
518
parser_state_tos->sizeof_keyword = true;
524
default: /* all others are treated like any other
527
} /* end of switch */
529
if (parser_state_tos->last_token == cpp_operator)
535
} /* end of if (found_it) */
536
else if ((*buf_ptr == '(') && (parser_state_tos->tos <= 1) &&
537
(parser_state_tos->ind_level == 0) &&
538
(parser_state_tos->paren_depth == 0))
540
/* We have found something which might be the name in a function
546
/* If the return type of this function definition was not defined
547
* with a -T commandline option, then the output of indent would
548
* alternate on subsequent calls. In order to avoid that we try
549
* to detect that case here and make a minimal change to cause
550
* the correct behaviour.
553
if (parser_state_tos->last_token == ident && parser_state_tos->last_saw_nl)
555
parser_state_tos->in_decl = 1;
558
/* Skip to the matching ')'. */
560
for (tp = buf_ptr + 1; paren_count > 0 && tp < in_prog + in_prog_size; tp++)
572
/* Can't occur in parameter list; this way we don't search the
573
* whole file in the case of unbalanced parens. */
581
if (paren_count == 0)
583
parser_state_tos->procname = token;
584
parser_state_tos->procname_end = token_end;
586
while (isspace (*tp))
591
if ((*tp == '_') && (in_prog + in_prog_size - tp >= 13) &&
592
!strncmp (tp, "__attribute__", 13))
594
/* Found an __attribute__ after a function declaration */
595
goto not_proc; /* Must be a declaration */
598
/* If the next char is ';' or ',' or '(' we have a function
599
* declaration, not a definition.
601
* I've added '=' to this list to keep from breaking
602
* a non-valid C macro from libc. -jla */
604
if (*tp != ';' && *tp != ',' && *tp != '(' && *tp != '=')
606
parser_state_tos->in_parameter_declaration = 1;
612
else if ((*buf_ptr == ':') && (*(buf_ptr + 1) == ':') &&
613
(parser_state_tos->tos <= 1) &&
614
(parser_state_tos->ind_level == 0) &&
615
(parser_state_tos->paren_depth == 0))
617
parser_state_tos->classname = token;
618
parser_state_tos->classname_end = token_end;
621
/* The following hack attempts to guess whether or not the
622
* current token is in fact a declaration keyword -- one that
623
* has been typedef'd */
625
else if ( ( ((*buf_ptr == '*') && (buf_ptr[1] != '=')) ||
626
isalpha (*buf_ptr) || (*buf_ptr == '_')) &&
627
!parser_state_tos->p_l_follow && !parser_state_tos->block_init &&
628
( (parser_state_tos->last_token == rparen) ||
629
(parser_state_tos->last_token == semicolon) ||
630
(parser_state_tos->last_token == rbrace) ||
631
(parser_state_tos->last_token == decl) ||
632
(parser_state_tos->last_token == lbrace) ||
633
(parser_state_tos->last_token == start_token)))
635
parser_state_tos->its_a_keyword = true;
636
parser_state_tos->last_u_d = true;
639
if (parser_state_tos->last_token == cpp_operator)
647
if (last_code == decl)
649
/* if this is a declared variable, then
650
following sign is unary */
651
parser_state_tos->last_u_d = true; /* will make "int a -1" work */
656
if (parser_state_tos->last_token == cpp_operator)
661
return (ident); /* the ident is not in the list */
662
} /* end of procesing for alpanum character */
664
/* Scan a non-alphanumeric token */
666
/* If it is not a one character token, token_end will get changed later. */
668
token_end = buf_ptr + 1;
670
/* THIS MAY KILL YOU!!!
672
* Note that it may be possible for this to kill us--if `fill_buffer'
673
* at any time switches `buf_ptr' to the other input buffer, `token'
674
* and `token_end' will point to different storage areas!!! */
676
if (++buf_ptr >= buf_end)
681
/* If it is a backslash new-line, just eat the backslash */
683
if ((*token == '\\') && (buf_ptr[0] == EOL))
687
if (++buf_ptr >= buf_end)
700
parser_state_tos->matching_brace_on_same_line = -1;
701
unary_delim = parser_state_tos->last_u_d;
702
parser_state_tos->last_nl = true;
706
/* Handle wide strings and chars. */
708
if (buf_ptr[0] != '"' && buf_ptr[0] != '\'')
719
case '\'': /* start of quoted character */
720
case '"': /* start of string */
724
/* Find out how big the literal is so we can set token_end. */
726
/* Invariant: before loop test buf_ptr points to the next
727
* character that we have not yet checked. */
729
while ((*buf_ptr != qchar) && (*buf_ptr != 0)) /* && *buf_ptr != EOL) */
736
if (*buf_ptr == '\\')
740
if (buf_ptr >= buf_end)
758
if (buf_ptr >= buf_end)
764
if (*buf_ptr == EOL || *buf_ptr == 0)
766
WARNING ((qchar == '\'' ? _("Unterminated character constant") :
767
_("Unterminated string constant")), 0, 0);
771
/* Advance over end quote char. */
774
if (buf_ptr >= buf_end)
791
if (parser_state_tos->in_or_st)
792
parser_state_tos->in_or_st++;
803
if (parser_state_tos->in_or_st > 1)
804
parser_state_tos->in_or_st--;
809
unary_delim = parser_state_tos->last_u_d;
812
/* Make spaces between '#' and the directive be part of
813
the token if user specified "-lps" */
814
if (leave_preproc_space)
816
while (*buf_ptr == ' ' && buf_ptr < buf_end)
831
/* Deal with C++ class::method */
843
if (squest && *e_com != ' ')
845
if (e_code == s_code)
847
parser_state_tos->want_blank = false;
852
parser_state_tos->want_blank = true;
864
if (parser_state_tos->matching_brace_on_same_line < 0)
866
parser_state_tos->matching_brace_on_same_line = 1;
870
parser_state_tos->matching_brace_on_same_line++;
875
/* Keep all variables in the same column:
881
* Use a special code for `block_init' however, because we still
882
* want to do the line breaks when `braces_on_struct_decl_line'
885
parser_state_tos->block_init = 2;
886
parser_state_tos->block_init_level = 0;
895
parser_state_tos->matching_brace_on_same_line--;
901
case 014: /* a form feed */
902
unary_delim = parser_state_tos->last_u_d;
903
parser_state_tos->last_nl = true; /* remember this so we can set
904
'parser_state_tos->col_1' right */
914
if (parser_state_tos->in_decl && *buf_ptr == '.' && buf_ptr[1] == '.')
916
/* check for '...' in a declaration */
917
if ((buf_ptr += 2) >= buf_end)
930
if (*buf_ptr == '*') /* object .* pointer-to-member */
938
case '+': /* check for -, +, --, ++ */
939
code = (parser_state_tos->last_u_d ? unary_op : binary_op);
942
if (*buf_ptr == token[0])
944
/* check for doubled character */
946
/* buffer overflow will be checked at end of loop */
947
if (last_code == ident || last_code == rparen)
949
code = (parser_state_tos->last_u_d ? unary_op : postop);
950
/* check for following ++ or -- */
954
else if (*buf_ptr == '=')
956
/* check for operator += */
959
else if (*buf_ptr == '>')
961
/* check for operator -> */
964
/* check for operator ->* */
973
break; /* buffer overflow will be checked at end of
977
if (parser_state_tos->in_or_st && parser_state_tos->last_token != cpp_operator)
979
parser_state_tos->block_init = 1;
980
parser_state_tos->block_init_level = 0;
983
if (*buf_ptr == '=') /* == */
987
else if ((*buf_ptr == '-') ||
992
/* Something like x=-1, which can mean x -= 1 ("old style" in K&R1)
993
* or x = -1 (ANSI). Note that this is only an ambiguity if the
994
* character can also be a unary operator. If not, just produce
995
* output code that produces a syntax error (the theory being that
996
* people want to detect and eliminate old style assignments but
997
* they don't want indent to silently change the meaning of their
1000
WARNING (_("old style assignment ambiguity in \"=%c\". Assuming \"= %c\"\n"),
1001
(unsigned long) *((unsigned char *) buf_ptr), (unsigned long) *((unsigned char *) buf_ptr));
1006
token_end = buf_ptr;
1008
/* can drop thru!!! */
1013
/* ops like <, <<, <=, !=, <<=, etc */
1014
/* This will of course scan sequences like "<=>", "!=>", "<<>", etc. as
1015
* one token, but I don't think that will cause any harm. */
1016
/* in C++ mode also scan <?[=], >?[=] GNU C++ operators
1017
* maybe some flag to them ? */
1019
while (*buf_ptr == '>' || *buf_ptr == '<' || *buf_ptr == '=' || (c_plus_plus && *buf_ptr == '?'))
1021
if (++buf_ptr >= buf_end)
1026
if (*buf_ptr == '=')
1028
if (++buf_ptr >= buf_end)
1035
code = (parser_state_tos->last_u_d ? unary_op : binary_op);
1037
token_end = buf_ptr;
1041
if (token[0] == '/' && (*buf_ptr == '*' || *buf_ptr == '/'))
1043
/* A C or C++ comment */
1045
if (*buf_ptr == '*')
1051
code = cplus_comment;
1054
if (++buf_ptr >= buf_end)
1059
if (code == comment)
1061
/* Threat comments of type / *UPPERCASE* / not as comments */
1064
while (isupper (*p++))
1066
/* There is always at least one
1067
* newline in the buffer; so no
1068
* need to check for buf_end. */
1071
if (p < buf_end && p[-1] == '*' && *p == '/')
1075
parser_state_tos->want_blank = true;
1079
unary_delim = parser_state_tos->last_u_d;
1081
else if (parser_state_tos->last_token == cpp_operator)
1083
/* For C++ overloaded operators. */
1085
last_code = overloaded;
1089
while (*(buf_ptr - 1) == *buf_ptr || *buf_ptr == '=')
1091
/* handle ||, &&, etc, and also things as in int *****i */
1092
if (++buf_ptr >= buf_end)
1097
code = (parser_state_tos->last_u_d ? unary_op : binary_op);
1101
token_end = buf_ptr;
1103
} /* end of switch */
1105
if (code != newline)
1111
if (buf_ptr >= buf_end)
1116
parser_state_tos->last_u_d = unary_delim;
1118
if (parser_state_tos->last_token == cpp_operator)
1126
/* Add the given keyword to the keyword table, using val as
1127
* the keyword type */
1136
/* Check to see whether key is a reserved word or not. */
1137
if ( (c_plus_plus && is_reserved_cc (key, strlen (key)) != 0) ||
1138
(!c_plus_plus && is_reserved (key, strlen (key)) != 0))
1143
if (user_specials == 0)
1145
user_specials = (struct templ *) xmalloc (5 * sizeof (struct templ));
1146
user_specials_max = 5;
1147
user_specials_idx = 0;
1149
else if (user_specials_idx == user_specials_max)
1151
user_specials_max += 5;
1152
user_specials = (struct templ *) xrealloc ((char *) user_specials, user_specials_max * sizeof (struct templ));
1155
p = &user_specials[user_specials_idx++];