diff options
author | Denys Vlasenko <vda.linux@googlemail.com> | 2011-09-11 00:30:56 +0200 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2011-09-11 00:30:56 +0200 |
commit | 7b46d11582047d0dd21b547ff4a913defe646d40 (patch) | |
tree | f4f6787860df6536bd1e22deba6ddec41a0e3fa1 | |
parent | d48fdde3704f453014404fca321e08238dc4acc4 (diff) | |
download | busybox-w32-7b46d11582047d0dd21b547ff4a913defe646d40.tar.gz busybox-w32-7b46d11582047d0dd21b547ff4a913defe646d40.tar.bz2 busybox-w32-7b46d11582047d0dd21b547ff4a913defe646d40.zip |
awk: fix a SEGV
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r-- | editors/awk.c | 71 | ||||
-rwxr-xr-x | testsuite/awk.tests | 3 |
2 files changed, 65 insertions, 9 deletions
diff --git a/editors/awk.c b/editors/awk.c index 8117cab54..71abca215 100644 --- a/editors/awk.c +++ b/editors/awk.c | |||
@@ -25,6 +25,7 @@ | |||
25 | * to perform debug printfs to stderr: */ | 25 | * to perform debug printfs to stderr: */ |
26 | #define debug_printf_walker(...) do {} while (0) | 26 | #define debug_printf_walker(...) do {} while (0) |
27 | #define debug_printf_eval(...) do {} while (0) | 27 | #define debug_printf_eval(...) do {} while (0) |
28 | #define debug_printf_parse(...) do {} while (0) | ||
28 | 29 | ||
29 | #ifndef debug_printf_walker | 30 | #ifndef debug_printf_walker |
30 | # define debug_printf_walker(...) (fprintf(stderr, __VA_ARGS__)) | 31 | # define debug_printf_walker(...) (fprintf(stderr, __VA_ARGS__)) |
@@ -32,6 +33,9 @@ | |||
32 | #ifndef debug_printf_eval | 33 | #ifndef debug_printf_eval |
33 | # define debug_printf_eval(...) (fprintf(stderr, __VA_ARGS__)) | 34 | # define debug_printf_eval(...) (fprintf(stderr, __VA_ARGS__)) |
34 | #endif | 35 | #endif |
36 | #ifndef debug_printf_parse | ||
37 | # define debug_printf_parse(...) (fprintf(stderr, __VA_ARGS__)) | ||
38 | #endif | ||
35 | 39 | ||
36 | 40 | ||
37 | 41 | ||
@@ -435,13 +439,13 @@ struct globals { | |||
435 | smallint nextrec; | 439 | smallint nextrec; |
436 | smallint nextfile; | 440 | smallint nextfile; |
437 | smallint is_f0_split; | 441 | smallint is_f0_split; |
442 | smallint t_rollback; | ||
438 | }; | 443 | }; |
439 | struct globals2 { | 444 | struct globals2 { |
440 | uint32_t t_info; /* often used */ | 445 | uint32_t t_info; /* often used */ |
441 | uint32_t t_tclass; | 446 | uint32_t t_tclass; |
442 | char *t_string; | 447 | char *t_string; |
443 | int t_lineno; | 448 | int t_lineno; |
444 | int t_rollback; | ||
445 | 449 | ||
446 | var *intvar[NUM_INTERNAL_VARS]; /* often used */ | 450 | var *intvar[NUM_INTERNAL_VARS]; /* often used */ |
447 | 451 | ||
@@ -499,11 +503,11 @@ struct globals2 { | |||
499 | #define nextrec (G1.nextrec ) | 503 | #define nextrec (G1.nextrec ) |
500 | #define nextfile (G1.nextfile ) | 504 | #define nextfile (G1.nextfile ) |
501 | #define is_f0_split (G1.is_f0_split ) | 505 | #define is_f0_split (G1.is_f0_split ) |
506 | #define t_rollback (G1.t_rollback ) | ||
502 | #define t_info (G.t_info ) | 507 | #define t_info (G.t_info ) |
503 | #define t_tclass (G.t_tclass ) | 508 | #define t_tclass (G.t_tclass ) |
504 | #define t_string (G.t_string ) | 509 | #define t_string (G.t_string ) |
505 | #define t_lineno (G.t_lineno ) | 510 | #define t_lineno (G.t_lineno ) |
506 | #define t_rollback (G.t_rollback ) | ||
507 | #define intvar (G.intvar ) | 511 | #define intvar (G.intvar ) |
508 | #define fsplitter (G.fsplitter ) | 512 | #define fsplitter (G.fsplitter ) |
509 | #define rsplitter (G.rsplitter ) | 513 | #define rsplitter (G.rsplitter ) |
@@ -1011,6 +1015,7 @@ static uint32_t next_token(uint32_t expected) | |||
1011 | 1015 | ||
1012 | if (*p == '\0') { | 1016 | if (*p == '\0') { |
1013 | tc = TC_EOF; | 1017 | tc = TC_EOF; |
1018 | debug_printf_parse("%s: token found: TC_EOF\n", __func__); | ||
1014 | 1019 | ||
1015 | } else if (*p == '\"') { | 1020 | } else if (*p == '\"') { |
1016 | /* it's a string */ | 1021 | /* it's a string */ |
@@ -1026,6 +1031,7 @@ static uint32_t next_token(uint32_t expected) | |||
1026 | p++; | 1031 | p++; |
1027 | *s = '\0'; | 1032 | *s = '\0'; |
1028 | tc = TC_STRING; | 1033 | tc = TC_STRING; |
1034 | debug_printf_parse("%s: token found:'%s' TC_STRING\n", __func__, t_string); | ||
1029 | 1035 | ||
1030 | } else if ((expected & TC_REGEXP) && *p == '/') { | 1036 | } else if ((expected & TC_REGEXP) && *p == '/') { |
1031 | /* it's regexp */ | 1037 | /* it's regexp */ |
@@ -1048,6 +1054,7 @@ static uint32_t next_token(uint32_t expected) | |||
1048 | p++; | 1054 | p++; |
1049 | *s = '\0'; | 1055 | *s = '\0'; |
1050 | tc = TC_REGEXP; | 1056 | tc = TC_REGEXP; |
1057 | debug_printf_parse("%s: token found:'%s' TC_REGEXP\n", __func__, t_string); | ||
1051 | 1058 | ||
1052 | } else if (*p == '.' || isdigit(*p)) { | 1059 | } else if (*p == '.' || isdigit(*p)) { |
1053 | /* it's a number */ | 1060 | /* it's a number */ |
@@ -1057,6 +1064,7 @@ static uint32_t next_token(uint32_t expected) | |||
1057 | if (*p == '.') | 1064 | if (*p == '.') |
1058 | syntax_error(EMSG_UNEXP_TOKEN); | 1065 | syntax_error(EMSG_UNEXP_TOKEN); |
1059 | tc = TC_NUMBER; | 1066 | tc = TC_NUMBER; |
1067 | debug_printf_parse("%s: token found:%f TC_NUMBER\n", __func__, t_double); | ||
1060 | 1068 | ||
1061 | } else { | 1069 | } else { |
1062 | /* search for something known */ | 1070 | /* search for something known */ |
@@ -1079,6 +1087,7 @@ static uint32_t next_token(uint32_t expected) | |||
1079 | ) { | 1087 | ) { |
1080 | /* then this is what we are looking for */ | 1088 | /* then this is what we are looking for */ |
1081 | t_info = *ti; | 1089 | t_info = *ti; |
1090 | debug_printf_parse("%s: token found:'%.*s' t_info:%x\n", __func__, l, p, t_info); | ||
1082 | p += l; | 1091 | p += l; |
1083 | goto token_found; | 1092 | goto token_found; |
1084 | } | 1093 | } |
@@ -1102,14 +1111,17 @@ static uint32_t next_token(uint32_t expected) | |||
1102 | p = skip_spaces(p); | 1111 | p = skip_spaces(p); |
1103 | if (*p == '(') { | 1112 | if (*p == '(') { |
1104 | tc = TC_FUNCTION; | 1113 | tc = TC_FUNCTION; |
1114 | debug_printf_parse("%s: token found:'%s' TC_FUNCTION\n", __func__, t_string); | ||
1105 | } else { | 1115 | } else { |
1106 | if (*p == '[') { | 1116 | if (*p == '[') { |
1107 | p++; | 1117 | p++; |
1108 | tc = TC_ARRAY; | 1118 | tc = TC_ARRAY; |
1109 | } | 1119 | debug_printf_parse("%s: token found:'%s' TC_ARRAY\n", __func__, t_string); |
1120 | } else | ||
1121 | debug_printf_parse("%s: token found:'%s' TC_VARIABLE\n", __func__, t_string); | ||
1110 | } | 1122 | } |
1111 | token_found: ; | ||
1112 | } | 1123 | } |
1124 | token_found: | ||
1113 | g_pos = p; | 1125 | g_pos = p; |
1114 | 1126 | ||
1115 | /* skipping newlines in some cases */ | 1127 | /* skipping newlines in some cases */ |
@@ -1181,6 +1193,8 @@ static node *parse_expr(uint32_t iexp) | |||
1181 | uint32_t tc, xtc; | 1193 | uint32_t tc, xtc; |
1182 | var *v; | 1194 | var *v; |
1183 | 1195 | ||
1196 | debug_printf_parse("%s(%x)\n", __func__, iexp); | ||
1197 | |||
1184 | sn.info = PRIMASK; | 1198 | sn.info = PRIMASK; |
1185 | sn.r.n = glptr = NULL; | 1199 | sn.r.n = glptr = NULL; |
1186 | xtc = TC_OPERAND | TC_UOPPRE | TC_REGEXP | iexp; | 1200 | xtc = TC_OPERAND | TC_UOPPRE | TC_REGEXP | iexp; |
@@ -1189,12 +1203,14 @@ static node *parse_expr(uint32_t iexp) | |||
1189 | 1203 | ||
1190 | if (glptr && (t_info == (OC_COMPARE | VV | P(39) | 2))) { | 1204 | if (glptr && (t_info == (OC_COMPARE | VV | P(39) | 2))) { |
1191 | /* input redirection (<) attached to glptr node */ | 1205 | /* input redirection (<) attached to glptr node */ |
1206 | debug_printf_parse("%s: input redir\n", __func__); | ||
1192 | cn = glptr->l.n = new_node(OC_CONCAT | SS | P(37)); | 1207 | cn = glptr->l.n = new_node(OC_CONCAT | SS | P(37)); |
1193 | cn->a.n = glptr; | 1208 | cn->a.n = glptr; |
1194 | xtc = TC_OPERAND | TC_UOPPRE; | 1209 | xtc = TC_OPERAND | TC_UOPPRE; |
1195 | glptr = NULL; | 1210 | glptr = NULL; |
1196 | 1211 | ||
1197 | } else if (tc & (TC_BINOP | TC_UOPPOST)) { | 1212 | } else if (tc & (TC_BINOP | TC_UOPPOST)) { |
1213 | debug_printf_parse("%s: TC_BINOP | TC_UOPPOST\n", __func__); | ||
1198 | /* for binary and postfix-unary operators, jump back over | 1214 | /* for binary and postfix-unary operators, jump back over |
1199 | * previous operators with higher priority */ | 1215 | * previous operators with higher priority */ |
1200 | vn = cn; | 1216 | vn = cn; |
@@ -1224,6 +1240,7 @@ static node *parse_expr(uint32_t iexp) | |||
1224 | vn->a.n = cn; | 1240 | vn->a.n = cn; |
1225 | 1241 | ||
1226 | } else { | 1242 | } else { |
1243 | debug_printf_parse("%s: other\n", __func__); | ||
1227 | /* for operands and prefix-unary operators, attach them | 1244 | /* for operands and prefix-unary operators, attach them |
1228 | * to last node */ | 1245 | * to last node */ |
1229 | vn = cn; | 1246 | vn = cn; |
@@ -1231,12 +1248,14 @@ static node *parse_expr(uint32_t iexp) | |||
1231 | cn->a.n = vn; | 1248 | cn->a.n = vn; |
1232 | xtc = TC_OPERAND | TC_UOPPRE | TC_REGEXP; | 1249 | xtc = TC_OPERAND | TC_UOPPRE | TC_REGEXP; |
1233 | if (tc & (TC_OPERAND | TC_REGEXP)) { | 1250 | if (tc & (TC_OPERAND | TC_REGEXP)) { |
1251 | debug_printf_parse("%s: TC_OPERAND | TC_REGEXP\n", __func__); | ||
1234 | xtc = TC_UOPPRE | TC_UOPPOST | TC_BINOP | TC_OPERAND | iexp; | 1252 | xtc = TC_UOPPRE | TC_UOPPOST | TC_BINOP | TC_OPERAND | iexp; |
1235 | /* one should be very careful with switch on tclass - | 1253 | /* one should be very careful with switch on tclass - |
1236 | * only simple tclasses should be used! */ | 1254 | * only simple tclasses should be used! */ |
1237 | switch (tc) { | 1255 | switch (tc) { |
1238 | case TC_VARIABLE: | 1256 | case TC_VARIABLE: |
1239 | case TC_ARRAY: | 1257 | case TC_ARRAY: |
1258 | debug_printf_parse("%s: TC_VARIABLE | TC_ARRAY\n", __func__); | ||
1240 | cn->info = OC_VAR; | 1259 | cn->info = OC_VAR; |
1241 | v = hash_search(ahash, t_string); | 1260 | v = hash_search(ahash, t_string); |
1242 | if (v != NULL) { | 1261 | if (v != NULL) { |
@@ -1253,6 +1272,7 @@ static node *parse_expr(uint32_t iexp) | |||
1253 | 1272 | ||
1254 | case TC_NUMBER: | 1273 | case TC_NUMBER: |
1255 | case TC_STRING: | 1274 | case TC_STRING: |
1275 | debug_printf_parse("%s: TC_NUMBER | TC_STRING\n", __func__); | ||
1256 | cn->info = OC_VAR; | 1276 | cn->info = OC_VAR; |
1257 | v = cn->l.v = xzalloc(sizeof(var)); | 1277 | v = cn->l.v = xzalloc(sizeof(var)); |
1258 | if (tc & TC_NUMBER) | 1278 | if (tc & TC_NUMBER) |
@@ -1262,32 +1282,41 @@ static node *parse_expr(uint32_t iexp) | |||
1262 | break; | 1282 | break; |
1263 | 1283 | ||
1264 | case TC_REGEXP: | 1284 | case TC_REGEXP: |
1285 | debug_printf_parse("%s: TC_REGEXP\n", __func__); | ||
1265 | mk_re_node(t_string, cn, xzalloc(sizeof(regex_t)*2)); | 1286 | mk_re_node(t_string, cn, xzalloc(sizeof(regex_t)*2)); |
1266 | break; | 1287 | break; |
1267 | 1288 | ||
1268 | case TC_FUNCTION: | 1289 | case TC_FUNCTION: |
1290 | debug_printf_parse("%s: TC_FUNCTION\n", __func__); | ||
1269 | cn->info = OC_FUNC; | 1291 | cn->info = OC_FUNC; |
1270 | cn->r.f = newfunc(t_string); | 1292 | cn->r.f = newfunc(t_string); |
1271 | cn->l.n = condition(); | 1293 | cn->l.n = condition(); |
1272 | break; | 1294 | break; |
1273 | 1295 | ||
1274 | case TC_SEQSTART: | 1296 | case TC_SEQSTART: |
1297 | debug_printf_parse("%s: TC_SEQSTART\n", __func__); | ||
1275 | cn = vn->r.n = parse_expr(TC_SEQTERM); | 1298 | cn = vn->r.n = parse_expr(TC_SEQTERM); |
1299 | if (!cn) | ||
1300 | syntax_error("Empty sequence"); | ||
1276 | cn->a.n = vn; | 1301 | cn->a.n = vn; |
1277 | break; | 1302 | break; |
1278 | 1303 | ||
1279 | case TC_GETLINE: | 1304 | case TC_GETLINE: |
1305 | debug_printf_parse("%s: TC_GETLINE\n", __func__); | ||
1280 | glptr = cn; | 1306 | glptr = cn; |
1281 | xtc = TC_OPERAND | TC_UOPPRE | TC_BINOP | iexp; | 1307 | xtc = TC_OPERAND | TC_UOPPRE | TC_BINOP | iexp; |
1282 | break; | 1308 | break; |
1283 | 1309 | ||
1284 | case TC_BUILTIN: | 1310 | case TC_BUILTIN: |
1311 | debug_printf_parse("%s: TC_BUILTIN\n", __func__); | ||
1285 | cn->l.n = condition(); | 1312 | cn->l.n = condition(); |
1286 | break; | 1313 | break; |
1287 | } | 1314 | } |
1288 | } | 1315 | } |
1289 | } | 1316 | } |
1290 | } | 1317 | } |
1318 | |||
1319 | debug_printf_parse("%s() returns %p\n", __func__, sn.r.n); | ||
1291 | return sn.r.n; | 1320 | return sn.r.n; |
1292 | } | 1321 | } |
1293 | 1322 | ||
@@ -1356,18 +1385,25 @@ static void chain_group(void) | |||
1356 | } while (c & TC_NEWLINE); | 1385 | } while (c & TC_NEWLINE); |
1357 | 1386 | ||
1358 | if (c & TC_GRPSTART) { | 1387 | if (c & TC_GRPSTART) { |
1388 | debug_printf_parse("%s: TC_GRPSTART\n", __func__); | ||
1359 | while (next_token(TC_GRPSEQ | TC_GRPTERM) != TC_GRPTERM) { | 1389 | while (next_token(TC_GRPSEQ | TC_GRPTERM) != TC_GRPTERM) { |
1390 | debug_printf_parse("%s: !TC_GRPTERM\n", __func__); | ||
1360 | if (t_tclass & TC_NEWLINE) | 1391 | if (t_tclass & TC_NEWLINE) |
1361 | continue; | 1392 | continue; |
1362 | rollback_token(); | 1393 | rollback_token(); |
1363 | chain_group(); | 1394 | chain_group(); |
1364 | } | 1395 | } |
1396 | debug_printf_parse("%s: TC_GRPTERM\n", __func__); | ||
1365 | } else if (c & (TC_OPSEQ | TC_OPTERM)) { | 1397 | } else if (c & (TC_OPSEQ | TC_OPTERM)) { |
1398 | debug_printf_parse("%s: TC_OPSEQ | TC_OPTERM\n", __func__); | ||
1366 | rollback_token(); | 1399 | rollback_token(); |
1367 | chain_expr(OC_EXEC | Vx); | 1400 | chain_expr(OC_EXEC | Vx); |
1368 | } else { /* TC_STATEMNT */ | 1401 | } else { |
1402 | /* TC_STATEMNT */ | ||
1403 | debug_printf_parse("%s: TC_STATEMNT(?)\n", __func__); | ||
1369 | switch (t_info & OPCLSMASK) { | 1404 | switch (t_info & OPCLSMASK) { |
1370 | case ST_IF: | 1405 | case ST_IF: |
1406 | debug_printf_parse("%s: ST_IF\n", __func__); | ||
1371 | n = chain_node(OC_BR | Vx); | 1407 | n = chain_node(OC_BR | Vx); |
1372 | n->l.n = condition(); | 1408 | n->l.n = condition(); |
1373 | chain_group(); | 1409 | chain_group(); |
@@ -1382,12 +1418,14 @@ static void chain_group(void) | |||
1382 | break; | 1418 | break; |
1383 | 1419 | ||
1384 | case ST_WHILE: | 1420 | case ST_WHILE: |
1421 | debug_printf_parse("%s: ST_WHILE\n", __func__); | ||
1385 | n2 = condition(); | 1422 | n2 = condition(); |
1386 | n = chain_loop(NULL); | 1423 | n = chain_loop(NULL); |
1387 | n->l.n = n2; | 1424 | n->l.n = n2; |
1388 | break; | 1425 | break; |
1389 | 1426 | ||
1390 | case ST_DO: | 1427 | case ST_DO: |
1428 | debug_printf_parse("%s: ST_DO\n", __func__); | ||
1391 | n2 = chain_node(OC_EXEC); | 1429 | n2 = chain_node(OC_EXEC); |
1392 | n = chain_loop(NULL); | 1430 | n = chain_loop(NULL); |
1393 | n2->a.n = n->a.n; | 1431 | n2->a.n = n->a.n; |
@@ -1396,6 +1434,7 @@ static void chain_group(void) | |||
1396 | break; | 1434 | break; |
1397 | 1435 | ||
1398 | case ST_FOR: | 1436 | case ST_FOR: |
1437 | debug_printf_parse("%s: ST_FOR\n", __func__); | ||
1399 | next_token(TC_SEQSTART); | 1438 | next_token(TC_SEQSTART); |
1400 | n2 = parse_expr(TC_SEMICOL | TC_SEQTERM); | 1439 | n2 = parse_expr(TC_SEMICOL | TC_SEQTERM); |
1401 | if (t_tclass & TC_SEQTERM) { /* for-in */ | 1440 | if (t_tclass & TC_SEQTERM) { /* for-in */ |
@@ -1421,6 +1460,7 @@ static void chain_group(void) | |||
1421 | 1460 | ||
1422 | case OC_PRINT: | 1461 | case OC_PRINT: |
1423 | case OC_PRINTF: | 1462 | case OC_PRINTF: |
1463 | debug_printf_parse("%s: OC_PRINT[F]\n", __func__); | ||
1424 | n = chain_node(t_info); | 1464 | n = chain_node(t_info); |
1425 | n->l.n = parse_expr(TC_OPTERM | TC_OUTRDR | TC_GRPTERM); | 1465 | n->l.n = parse_expr(TC_OPTERM | TC_OUTRDR | TC_GRPTERM); |
1426 | if (t_tclass & TC_OUTRDR) { | 1466 | if (t_tclass & TC_OUTRDR) { |
@@ -1432,17 +1472,20 @@ static void chain_group(void) | |||
1432 | break; | 1472 | break; |
1433 | 1473 | ||
1434 | case OC_BREAK: | 1474 | case OC_BREAK: |
1475 | debug_printf_parse("%s: OC_BREAK\n", __func__); | ||
1435 | n = chain_node(OC_EXEC); | 1476 | n = chain_node(OC_EXEC); |
1436 | n->a.n = break_ptr; | 1477 | n->a.n = break_ptr; |
1437 | break; | 1478 | break; |
1438 | 1479 | ||
1439 | case OC_CONTINUE: | 1480 | case OC_CONTINUE: |
1481 | debug_printf_parse("%s: OC_CONTINUE\n", __func__); | ||
1440 | n = chain_node(OC_EXEC); | 1482 | n = chain_node(OC_EXEC); |
1441 | n->a.n = continue_ptr; | 1483 | n->a.n = continue_ptr; |
1442 | break; | 1484 | break; |
1443 | 1485 | ||
1444 | /* delete, next, nextfile, return, exit */ | 1486 | /* delete, next, nextfile, return, exit */ |
1445 | default: | 1487 | default: |
1488 | debug_printf_parse("%s: default\n", __func__); | ||
1446 | chain_expr(t_info); | 1489 | chain_expr(t_info); |
1447 | } | 1490 | } |
1448 | } | 1491 | } |
@@ -1460,19 +1503,24 @@ static void parse_program(char *p) | |||
1460 | while ((tclass = next_token(TC_EOF | TC_OPSEQ | TC_GRPSTART | | 1503 | while ((tclass = next_token(TC_EOF | TC_OPSEQ | TC_GRPSTART | |
1461 | TC_OPTERM | TC_BEGIN | TC_END | TC_FUNCDECL)) != TC_EOF) { | 1504 | TC_OPTERM | TC_BEGIN | TC_END | TC_FUNCDECL)) != TC_EOF) { |
1462 | 1505 | ||
1463 | if (tclass & TC_OPTERM) | 1506 | if (tclass & TC_OPTERM) { |
1507 | debug_printf_parse("%s: TC_OPTERM\n", __func__); | ||
1464 | continue; | 1508 | continue; |
1509 | } | ||
1465 | 1510 | ||
1466 | seq = &mainseq; | 1511 | seq = &mainseq; |
1467 | if (tclass & TC_BEGIN) { | 1512 | if (tclass & TC_BEGIN) { |
1513 | debug_printf_parse("%s: TC_BEGIN\n", __func__); | ||
1468 | seq = &beginseq; | 1514 | seq = &beginseq; |
1469 | chain_group(); | 1515 | chain_group(); |
1470 | 1516 | ||
1471 | } else if (tclass & TC_END) { | 1517 | } else if (tclass & TC_END) { |
1518 | debug_printf_parse("%s: TC_END\n", __func__); | ||
1472 | seq = &endseq; | 1519 | seq = &endseq; |
1473 | chain_group(); | 1520 | chain_group(); |
1474 | 1521 | ||
1475 | } else if (tclass & TC_FUNCDECL) { | 1522 | } else if (tclass & TC_FUNCDECL) { |
1523 | debug_printf_parse("%s: TC_FUNCDECL\n", __func__); | ||
1476 | next_token(TC_FUNCTION); | 1524 | next_token(TC_FUNCTION); |
1477 | g_pos++; | 1525 | g_pos++; |
1478 | f = newfunc(t_string); | 1526 | f = newfunc(t_string); |
@@ -1490,22 +1538,27 @@ static void parse_program(char *p) | |||
1490 | clear_array(ahash); | 1538 | clear_array(ahash); |
1491 | 1539 | ||
1492 | } else if (tclass & TC_OPSEQ) { | 1540 | } else if (tclass & TC_OPSEQ) { |
1541 | debug_printf_parse("%s: TC_OPSEQ\n", __func__); | ||
1493 | rollback_token(); | 1542 | rollback_token(); |
1494 | cn = chain_node(OC_TEST); | 1543 | cn = chain_node(OC_TEST); |
1495 | cn->l.n = parse_expr(TC_OPTERM | TC_EOF | TC_GRPSTART); | 1544 | cn->l.n = parse_expr(TC_OPTERM | TC_EOF | TC_GRPSTART); |
1496 | if (t_tclass & TC_GRPSTART) { | 1545 | if (t_tclass & TC_GRPSTART) { |
1546 | debug_printf_parse("%s: TC_GRPSTART\n", __func__); | ||
1497 | rollback_token(); | 1547 | rollback_token(); |
1498 | chain_group(); | 1548 | chain_group(); |
1499 | } else { | 1549 | } else { |
1550 | debug_printf_parse("%s: !TC_GRPSTART\n", __func__); | ||
1500 | chain_node(OC_PRINT); | 1551 | chain_node(OC_PRINT); |
1501 | } | 1552 | } |
1502 | cn->r.n = mainseq.last; | 1553 | cn->r.n = mainseq.last; |
1503 | 1554 | ||
1504 | } else /* if (tclass & TC_GRPSTART) */ { | 1555 | } else /* if (tclass & TC_GRPSTART) */ { |
1556 | debug_printf_parse("%s: TC_GRPSTART(?)\n", __func__); | ||
1505 | rollback_token(); | 1557 | rollback_token(); |
1506 | chain_group(); | 1558 | chain_group(); |
1507 | } | 1559 | } |
1508 | } | 1560 | } |
1561 | debug_printf_parse("%s: TC_EOF\n", __func__); | ||
1509 | } | 1562 | } |
1510 | 1563 | ||
1511 | 1564 | ||
@@ -3000,7 +3053,7 @@ int awk_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | |||
3000 | int awk_main(int argc, char **argv) | 3053 | int awk_main(int argc, char **argv) |
3001 | { | 3054 | { |
3002 | unsigned opt; | 3055 | unsigned opt; |
3003 | char *opt_F, *opt_W; | 3056 | char *opt_F; |
3004 | llist_t *list_v = NULL; | 3057 | llist_t *list_v = NULL; |
3005 | llist_t *list_f = NULL; | 3058 | llist_t *list_f = NULL; |
3006 | int i, j; | 3059 | int i, j; |
@@ -3062,7 +3115,7 @@ int awk_main(int argc, char **argv) | |||
3062 | } | 3115 | } |
3063 | } | 3116 | } |
3064 | opt_complementary = "v::f::"; /* -v and -f can occur multiple times */ | 3117 | opt_complementary = "v::f::"; /* -v and -f can occur multiple times */ |
3065 | opt = getopt32(argv, "F:v:f:W:", &opt_F, &list_v, &list_f, &opt_W); | 3118 | opt = getopt32(argv, "F:v:f:W:", &opt_F, &list_v, &list_f, NULL); |
3066 | argv += optind; | 3119 | argv += optind; |
3067 | argc -= optind; | 3120 | argc -= optind; |
3068 | if (opt & 0x1) | 3121 | if (opt & 0x1) |
@@ -3096,7 +3149,7 @@ int awk_main(int argc, char **argv) | |||
3096 | parse_program(*argv++); | 3149 | parse_program(*argv++); |
3097 | } | 3150 | } |
3098 | if (opt & 0x8) // -W | 3151 | if (opt & 0x8) // -W |
3099 | bb_error_msg("warning: unrecognized option '-W %s' ignored", opt_W); | 3152 | bb_error_msg("warning: option -W is ignored"); |
3100 | 3153 | ||
3101 | /* fill in ARGV array */ | 3154 | /* fill in ARGV array */ |
3102 | setvar_i(intvar[ARGC], argc); | 3155 | setvar_i(intvar[ARGC], argc); |
diff --git a/testsuite/awk.tests b/testsuite/awk.tests index 0afe9b9e7..5a323047d 100755 --- a/testsuite/awk.tests +++ b/testsuite/awk.tests | |||
@@ -202,4 +202,7 @@ end d | |||
202 | " \ | 202 | " \ |
203 | "" "" | 203 | "" "" |
204 | 204 | ||
205 | testing "awk handles empty ()" \ | ||
206 | "awk 'BEGIN {print()}' 2>&1" "awk: cmd. line:1: Empty sequence\n" "" "" | ||
207 | |||
205 | exit $FAILCOUNT | 208 | exit $FAILCOUNT |