1# Executing Actions.                               -*- Autotest -*-
2
3# Copyright (C) 2002, 2004-2005, 2007, 2009-2015, 2018-2021 Free
4# Software Foundation, Inc.
5
6# This program is free software: you can redistribute it and/or modify
7# it under the terms of the GNU General Public License as published by
8# the Free Software Foundation, either version 3 of the License, or
9# (at your option) any later version.
10#
11# This program is distributed in the hope that it will be useful,
12# but WITHOUT ANY WARRANTY; without even the implied warranty of
13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14# GNU General Public License for more details.
15#
16# You should have received a copy of the GNU General Public License
17# along with this program.  If not, see <https://www.gnu.org/licenses/>.
18
19AT_BANNER([[Sync Lines.]])
20
21
22# _AT_SYNCLINES_COMPILE(FILE)
23# ---------------------------
24# Compile FILE expecting an error, and save in the file stdout the
25# normalized output.  Ignore the exit status, since some compilers
26# (e.g. c89 on IRIX 6.5) trigger warnings on '#error', instead of
27# errors.
28m4_define([_AT_SYNCLINES_COMPILE],
29[AT_CHECK([$CC $CFLAGS $CPPFLAGS -c $1], [ignore], [], [stderr])
30
31# Transform the file 'stderr' into something like this:
32#
33#   input.y:4: #error "4"
34#
35# In case GCC displays column information, strip it down.
36#
37#   input.y:4:2: #error "4"    or
38#   input.y:4.2: #error "4"    or
39#   input.y:4:2: error: #error "4"
40# =>
41#   input.y:4: #error "4"
42#
43# It may also issue more context information:
44#
45#   input.y: In function 'yyparse':
46#   input.y:8: #error "8"
47# =>
48#   input.y:4: #error "8"
49#
50# The message may include a caret-error (indented by GCC 4.8,
51# not by clang 3.2):
52#
53#   input.y:1:2: error: #error "1"
54#    #error "1"
55#     ^
56#
57# Possibly distcc adds its bits.
58#
59#   distcc[33187] ERROR: compile (null) on localhost failed
60#   syncline.c:1:2: error: #error "1"
61#   distcc[33185] ERROR: compile syncline.c on localhost failed
62#
63# or even
64#
65#   distcc[35882] (dcc_connect_by_name) ERROR: failed to look up host "chrisimac": Unknown host
66#   distcc[35882] Warning: failed to distribute input.c to chrisimac/4, running locally instead
67#
68# The compiler might end by the number of messages issued (Clang 3.2):
69#
70#    syncline.c:1:2: error: "1"
71#    #error "1"
72#     ^
73#    1 error generated.
74#
75# When c++ is used to compiler C, we might have more messages (Clang 3.2):
76#
77#    clang: warning: treating 'c' input as 'c++' when in C++ mode, this behavior is deprecated
78#
79#
80# xlc reports things like:
81#
82#    "input.yy", line 80.21: 1540-0218 (S) The call does not match any parameter list for "operator<<".
83#    "/usr/vacpp/include/iosfwd", line 32.6: 1506-205 (S) #error This file to be used only with IBM VisualAge C++ v4 and later compilers
84#
85# Newer GCCs go further and if the function is declared static, complain
86# that it's not used.
87#
88# GCC 7 also underlines the error.
89#
90#    syncline.c:4:2: error: #error "4"
91#     #error "4"
92#      ^~~~~
93#
94# GCC 9 displays a left-hand margin with the line number:
95#
96#    syncline.c: In function 'foo':
97#    syncline.c:4:2: error: #error "4"
98#        4 | #error "4"
99#          |  ^~~~~
100AT_CHECK([["$PERL" -p -0777 - stderr <<\EOF || exit 77
101  # Remove left-hand margin.
102  s/^[\d ]{6}\| //gm;
103
104  # 1. Remove useless lines.
105
106  # distcc clutter.
107  s/^distcc\[\d+\] .*\n//gm;
108  # c vs. c++.
109  s/^clang: warning: treating 'c' input as 'c\+\+'.*\n//gm;
110  # Function context.
111  s/^[^:]*: In function '[^']+':\n//gm;
112  # Caret error (with possible '~' to underline).
113  s/^ *#error.*\n *\^~*\n//gm;
114  # Number of errors.
115  s/^1 error generated\.\n//gm;
116
117  # 2. Normalize the lines we kept.
118
119  # xlc messages.  Remove also error identifier (e.g., "1540-0218 (S)").
120  s/^"(.*?)", line ([\w.]*): \d+-\d+ \(.\) /$][1:$][2: /gm;
121  # Remove column.
122  s/^([^:]+:\d+)[.:][^:]+:(.+)$/$][1:$][2/gm;
123  # Map all combinations of "error: " and "#error: " to "#error ".
124  s/^([^:]+:\d+):( |#error|error|:)+/$][1: #error /gm;
125EOF
126]],
127  0, [stdout])
128])
129
130
131
132# AT_SYNCLINES_COMPILE(FILE)
133# --------------------------
134# Compile FILE expecting an error, and save in the file 'stdout' the
135# normalized output.  If we can't get a trustable location
136# from the compiler, just skip the test.
137#
138# It seems impossible to find a generic scheme to check the location
139# of an error.  Even requiring GCC is not sufficient, since for instance
140# the version modified by Apple:
141#
142# | Reading specs from /usr/libexec/gcc/darwin/ppc/2.95.2/specs
143# | Apple Computer, Inc. version gcc-934.3, based on gcc version 2.95.2
144# | 19991024 (release) configure:2124: $? = 0
145#
146# instead of:
147#
148# | input.y:2: #error "2"
149#
150# it reports:
151#
152# | input.y:2: "2"
153# | cpp-precomp: warning: errors during smart preprocessing, retrying in basic mode
154m4_define([AT_SYNCLINES_COMPILE],
155[# Check if we can trust location translation.
156AT_DATA([syncline.c],
157[[void foo (void);
158void foo (void)
159{
160#error "4"
161}
162]])
163
164_AT_SYNCLINES_COMPILE([syncline.c])
165AT_REQUIRE([[test "`cat stdout`" = 'syncline.c:4: @%:@error "4"']])
166
167# Then work for real.
168_AT_SYNCLINES_COMPILE([$1])
169])
170
171
172# AT_TEST(TITLE, INPUT, ERROR-MSG)
173# --------------------------------
174# Check that compiling the parser produced from INPUT cause GCC
175# to issue ERROR-MSG.
176m4_pushdef([AT_TEST],
177[AT_SETUP([$1])
178AT_BISON_OPTION_PUSHDEFS
179
180AT_DATA([[input.y]], [$2])
181AT_BISON_CHECK([-o input.c input.y])
182AT_SYNCLINES_COMPILE([input.c])
183AT_CHECK([cat stdout], 0, [$3])
184AT_BISON_OPTION_POPDEFS
185AT_CLEANUP
186])
187
188
189## ------------------- ##
190## Prologue syncline.  ##
191## ------------------- ##
192
193
194AT_TEST([Prologue syncline],
195[[%{
196#error "2"
197%}
198%code {
199  ]AT_YYERROR_DECLARE_EXTERN[
200  ]AT_YYLEX_DECLARE_EXTERN[
201}
202%%
203exp: '0';
204%%
205]],
206[input.y:2: #error "2"
207])
208
209
210## ----------------- ##
211## %union syncline.  ##
212## ----------------- ##
213
214AT_TEST([%union syncline],
215[[%union {
216#error "2"
217  char dummy;
218}
219%code {
220  ]AT_YYERROR_DECLARE_EXTERN[
221  ]AT_YYLEX_DECLARE_EXTERN[
222}
223%%
224exp: '0';
225%%
226]],
227[input.y:2: #error "2"
228])
229
230
231## ---------------------- ##
232## %union name syncline.  ##
233## ---------------------- ##
234
235# Check that invalid union names are properly reported in the
236# source file.
237AT_SETUP([%union name syncline])
238AT_BISON_OPTION_PUSHDEFS
239AT_DATA([[input.y]],
240[[%union break
241{
242  char dummy;
243}
244%code {
245  ]AT_YYERROR_DECLARE_EXTERN[
246  ]AT_YYLEX_DECLARE_EXTERN[
247%}
248%%
249exp: '0';
250%%
251]])
252
253AT_BISON_CHECK([-o input.c input.y])
254AT_SYNCLINES_COMPILE([input.c])
255AT_CHECK([[grep '^input.y:1' stdout]], 0, [ignore])
256AT_BISON_OPTION_POPDEFS
257AT_CLEANUP
258
259
260## ----------------------- ##
261## Postprologue syncline.  ##
262## ----------------------- ##
263
264AT_TEST([Postprologue syncline],
265[[%code {
266  ]AT_YYERROR_DECLARE_EXTERN[
267  ]AT_YYLEX_DECLARE_EXTERN[
268}
269%{
270  /* Preprologue.  */
271%}
272%union
273{
274  int ival;
275}
276%{
277#error "13"
278%}
279%%
280exp: '0';
281%%
282]],
283[input.y:13: #error "13"
284])
285
286
287## ----------------- ##
288## Action syncline.  ##
289## ----------------- ##
290
291AT_TEST([Action syncline],
292[[%code {
293  ]AT_YYERROR_DECLARE_EXTERN[
294  ]AT_YYLEX_DECLARE_EXTERN[
295}
296%%
297exp:
298{
299#error "8"
300};
301]],
302[input.y:8: #error "8"
303])
304
305
306## ------------------- ##
307## Epilogue syncline.  ##
308## ------------------- ##
309
310AT_TEST([Epilogue syncline],
311[[%code {
312  ]AT_YYERROR_DECLARE_EXTERN[
313  ]AT_YYLEX_DECLARE_EXTERN[
314}
315%%
316exp: '0';
317%%
318#error "8"
319]],
320[input.y:8: #error "8"
321])
322
323## -------------------- ##
324## %code top syncline.  ##
325## -------------------- ##
326
327AT_TEST([%code top syncline],
328[[%code top {
329#error "2"
330}
331%code {
332  ]AT_YYERROR_DECLARE_EXTERN[
333  ]AT_YYLEX_DECLARE_EXTERN[
334}
335%%
336exp: '0';
337%%
338]],
339[input.y:2: #error "2"
340])
341
342## ---------------------- ##
343## %destructor syncline.  ##
344## ---------------------- ##
345
346AT_TEST([%destructor syncline],
347[[%destructor {
348#error "2"
349} <ival>
350%{
351]AT_YYERROR_DECLARE_EXTERN[
352]AT_YYLEX_DECLARE_EXTERN[
353%}
354%union {
355  int ival;
356}
357%type <ival> exp
358%%
359exp: '0' { $$ = 0; };
360%%
361]],
362[input.y:2: #error "2"
363])
364
365
366## ------------------- ##
367## %printer syncline.  ##
368## ------------------- ##
369
370AT_TEST([%printer syncline],
371[[%printer {
372#error "2"
373} <ival>
374%debug
375%code {
376  ]AT_YYERROR_DECLARE_EXTERN[
377  ]AT_YYLEX_DECLARE_EXTERN[
378}
379%union {
380  int ival;
381}
382%type <ival> exp
383%%
384exp: '0' { $$ = 0; };
385%%
386]],
387[input.y:2: #error "2"
388])
389
390m4_popdef([AT_TEST])
391
392
393
394## ------------------ ##
395## syncline escapes.  ##
396## ------------------ ##
397
398# AT_TEST([SKELETON])
399# -------------------
400m4_pushdef([AT_TEST],
401[AT_SETUP([syncline escapes: $1])
402
403AT_BISON_OPTION_PUSHDEFS([%skeleton "$1"])
404
405# ICC is unable to handle these file names: it fails to pass them
406# properly to the linker, and is unable to save a file named this way.
407# Don't try with such compilers.
408AT_DATA([\"\\\"\".AT_LANG_EXT],
409[[int main (void) { return 0; }
410]])
411
412AT_REQUIRE([AT_CXX_IF([$CXX $CXXFLAGS], [$CC $CFLAGS]) $CPPFLAGS \"\\\"\".]AT_LANG_EXT[ -o \"\\\"\"],
413                 [0], [ignore], [ignore])
414
415AT_DATA_GRAMMAR([\"\\\"\".y],
416[[%skeleton "$1"
417%code {
418  ]AT_YYERROR_DECLARE[
419  ]AT_YYLEX_DECLARE[
420}
421%destructor {} <>
422%printer {} <>
423%%
424exp: '0'
425%%
426]AT_YYERROR_DEFINE[
427]AT_YYLEX_DEFINE[
428]AT_MAIN_DEFINE[
429]])
430
431# Maybe we tried to create a file name that the file system does not
432# support.
433AT_SKIP_IF([[test ! -f \"\\\"\".y]])
434AT_FULL_COMPILE([\"\\\"\"])
435AT_BISON_OPTION_POPDEFS
436
437AT_CLEANUP
438])
439
440m4_map_args([AT_TEST], [yacc.c], [glr.c], [lalr1.cc], [glr.cc])
441
442m4_popdef([AT_TEST])
443
444
445
446## ----------- ##
447## %no-lines.  ##
448## ----------- ##
449
450# AT_TEST([SKELETON])
451# -------------------
452m4_pushdef([AT_TEST],
453[AT_SETUP([%no-lines: $1])
454
455AT_BISON_OPTION_PUSHDEFS([%skeleton "$1" %defines])
456AT_DATA_GRAMMAR([input.y],
457[[%skeleton "$1" %defines
458%{
459]AT_YYERROR_DECLARE_EXTERN[
460]AT_YYLEX_DECLARE_EXTERN[
461%}
462%union {
463  int ival;
464}
465%%
466exp: '0'
467]])
468
469# Generate without.* without the #line.  Don't use -o without.c which
470# would change the content (e.g., CPP guard depend on the output file
471# name).
472AT_BISON_CHECK([--no-lines -o input.AT_LANG_EXT -d input.y])
473AT_CHECK([mv input.]AT_LANG_EXT[ without.]AT_LANG_EXT[])
474AT_CHECK([mv input.]AT_LANG_HDR[ without.]AT_LANG_HDR[])
475# There is no #line at all.
476AT_CHECK([grep '#line' *.]AT_LANG_EXT[ *.]AT_LANG_HDR[], 1)
477
478# Generate with.* without the #line.
479AT_BISON_CHECK([-o input.AT_LANG_EXT -d input.y])
480AT_CHECK([mv input.]AT_LANG_EXT[ with.]AT_LANG_EXT[])
481AT_CHECK([mv input.]AT_LANG_HDR[ with.]AT_LANG_HDR[])
482
483# The implementation file with --no-line is exactly the
484# original one with #lines removed.
485AT_CHECK([grep -v '#line' with.]AT_LANG_EXT[ >expout])
486AT_CHECK([cat without.AT_LANG_EXT], 0, [expout])
487
488# Likewise for the header.
489AT_CHECK([grep -v '#line' with.]AT_LANG_HDR[ >expout])
490AT_CHECK([cat without.AT_LANG_HDR], 0, [expout])
491
492AT_BISON_OPTION_POPDEFS
493
494AT_CLEANUP
495])
496
497m4_map_args([AT_TEST], [yacc.c], [glr.c], [lalr1.cc], [glr.cc])
498
499m4_popdef([AT_TEST])
500
501
502
503## ---------------- ##
504## Output columns.  ##
505## ---------------- ##
506
507AT_SETUP([Output columns])
508
509# This test is fragile: its point is to check the compiler's error
510# message, but it seems too hard to do portability (even between
511# version of GCC).  So instead, let's just check the generated code
512# itself.
513
514AT_BISON_OPTION_PUSHDEFS
515AT_DATA([input.y],
516[[%{
517]AT_YYERROR_DECLARE_EXTERN[
518]AT_YYLEX_DECLARE_EXTERN[
519%}
520%define api.value.type union
521%type <int> '0' exp
522%destructor { /* --BEGIN */
523              destructor
524              /* --END   */ } <*>
525%printer { /* --BEGIN */
526           printer
527           /* --END   */ } <*>
528
529
530
531%left '+'
532%%
533exp: exp '+' exp {  /* --BEGIN */
534                    $$ = $1 + $3;
535                    @$ = @1 + @3;
536                    /* --END */ }
537   | '0'
538]])
539
540AT_BISON_CHECK([-o input.c input.y])
541AT_CHECK([[sed -ne '/--BEGIN/,/--END/{' \
542    -e '/input.c/s/ [0-9]* / LINE /;' \
543    -e 'p;}' \
544    input.c]], 0,
545[[         { /* --BEGIN */
546           printer
547           /* --END   */ }
548         { /* --BEGIN */
549           printer
550           /* --END   */ }
551            { /* --BEGIN */
552              destructor
553              /* --END   */ }
554            { /* --BEGIN */
555              destructor
556              /* --END   */ }
557                 {  /* --BEGIN */
558                    (yyval.exp) = (yyvsp[-2].exp) + (yyvsp[0].exp);
559                    (yyloc) = (yylsp[-2]) + (yylsp[0]);
560                    /* --END */ }
561]])
562
563AT_BISON_OPTION_POPDEFS
564AT_CLEANUP
565