#!/usr/bin/perl

# Tangled output generated by inweb: do not edit
$INWEB_BUILD = "inweb 4/090319"
;
$NO_MODE = 0
;
$ANALYSE_MODE = 1
;
$TANGLE_MODE = 2
;
$WEAVE_MODE = 3
;
$CREATE_MODE = 4 # a special mode for creating a new web, not acting on an existing one
;
$SWARM_OFF = 0
;
$SWARM_INDEX = 1 # Make index(es) as if swarming, but don't actually swarm
;
$SWARM_CHAPTERS = 2 # Swarm the chapters
;
$SWARM_SECTIONS = 3 # That, and also all of the individual sections
;
$NO_LCAT = 0 # none set as yet
;
$COMMENT_BODY_LCAT = 1
;
$MACRO_DEFINITION_LCAT = 2
;
$BAR_LCAT = 3
;
$INDEX_ENTRY_LCAT = 4
;
$PURPOSE_LCAT = 5
;
$INTERFACE_LCAT = 6
;
$GRAMMAR_LCAT = 7
;
$DEFINITIONS_LCAT = 8
;
$PARAGRAPH_START_LCAT = 9
;
$BEGIN_VERBATIM_LCAT = 10
;
$TEXT_EXTRACT_LCAT = 11
;
$BEGIN_DEFINITION_LCAT = 12
;
$GRAMMAR_BODY_LCAT = 13
;
$INTERFACE_BODY_LCAT = 14
;
$CODE_BODY_LCAT = 15
;
$CONT_DEFINITION_LCAT = 19
;
$SOURCE_DISPLAY_LCAT = 16
;
$TOGGLE_WEAVING_LCAT = 17
;
$COMMAND_LCAT = 18
;
$PAGEBREAK_CMD = 1
;
$BNF_GRAMMAR_CMD = 2
;
$THEMATIC_INDEX_CMD = 3
;
$FIGURE_CMD = 4
;
$INDEX_UNDER_CMD = 5
;
$debug_identifier_detection = 0
;
$TRACE_CI_EXECUTION = 0 # For debugging
;
$DEBUG_MARKING = 0
;
$C_LANGUAGE = 1              # C or C++
;
$C_FOR_INFORM_LANGUAGE = 2   # Ditto, but with NI extensions
;
$PERL_LANGUAGE = 3           # Perl
;
$I6_LANGUAGE = 4             # Inform 6
;
$I7_LANGUAGE = 5             # Inform 7 extension
;
$PLAIN_LANGUAGE = 6          # Plain text
;
$NO_LANGUAGE = 100           # Nothing to tangle, by fiat
;
#line 47 "Chapter 1/Program Control.w"
use integer;

#line 59 "Chapter 1/Program Control.w"
$web_is_chaptered = 1;

#line 73 "Chapter 1/Program Control.w"
$web_mode = $NO_MODE; # a value used to mean ``not set yet''

#line 83 "Chapter 1/Program Control.w"
$sigil_of_target = "0"; # By default, the entire web is the target

#line 94 "Chapter 1/Program Control.w"
$swarm_mode = $SWARM_OFF;

#line 99 "Chapter 1/Program Control.w"
$tangle_to = ""; # This is set either by the command line or from the Contents

#line 14 "Chapter 1/Command Line and Errors.w"
$analyse_structure_setting = ""; # |-analyse-structure|: name of typedef struct to show usage of
$catalogue_switch = 0; # |-catalogue|: print catalogue of sections
$functions_switch = 0; # |-functions|: print catalogue of functions within sections
$convert_graphs_switch = 0; # |-convert-graphs|: run |-make-graphs| output through 'dot'
$make_graphs_switch = 0; # |-make-graphs|: compile code to generate graphs
$open_pdf_switch = -1; # |-open-pdf|: open any woven PDF in the OS once it is made
$scan_switch = 0; # |-scan|: simply show the syntactic scan of the source
$tangle_setting = ""; # |-tangle X|: the pathname X, if supplied
$verbose_about_input_switch = 0; # |-verbose-about-input|: print names of files read to stdout
$voids_switch = 0; # |-voids|: print void pointer usage
$web_setting = ""; # set by |-web|: project folder relative to cwd
$create_setting = ""; # set by |-create|: name of a new project to create
$only_setting = ""; # set by |-only|: restrict a swarm to this chapter
$complete_PDF_leafname = "Complete.pdf"; # overridden when |-only| is used

#line 35 "Chapter 1/Command Line and Errors.w"
$path_to_inweb_setting = "";

#line 40 "Chapter 1/Command Line and Errors.w"
$pdftex_configuration = 'pdftex';
$dot_utility_configuration = 'dot';

#line 46 "Chapter 1/Command Line and Errors.w"
$no_inweb_errors = 0;

#line 26 "Chapter 2/Reading Sections.w"
$no_lines = 0; # Total lines in literate source, excluding contents
$no_sections = 0; # Again, excluding contents: it will eventually be at least 1
$no_chapters = 0; # Similarly, this will be at least 1
$no_tangle_targets = 0; # And again

#line 65 "Chapter 2/The Parser.w"
$no_paragraphs = 0;

#line 146 "Chapter 2/Identifiers.w"
$current_struct = "";

#line 21 "Chapter 3/Programming Languages.w"
$web_language = $C_LANGUAGE; # The default
$tangled_extension = ".c";

#line 102 "Chapter 1/Program Control.w"

#line 109 "Chapter 1/Program Control.w"
	print "$INWEB_BUILD (Inform Tools Suite)\n";
	make_command_line_settings();
	if (($web_mode == $NO_MODE) || ($web_setting eq "")) 
 { 
#line 130 "Chapter 1/Program Control.w"
	print "A simple literate programming tool intended for medium-sized and large programs.\n";
	print "Usage: inweb webname -action [-options] [target]\n";
	print "  where 'webname' is a folder containing a web (an inweb project),\n";
	print "  The most useful -action commands are:\n";
	print "    -create: make a new web, creating its folder and contents\n";
	print "    -tangle: make the program described in the web\n";
	print "    -weave: make a human-readable booklet of the web\n";
	print "  For options and less commonly used actions, see the inweb manual.\n";
	exit(0);

 } 
#line 111 "Chapter 1/Program Control.w"
;
	read_configuration_file();

	if ($create_setting ne "") 
 { 
#line 266 "Chapter 1/Program Control.w"
	system("mkdir -pv '".$create_setting."'");
	system("mkdir -pv '".$create_setting."/Figures'");
	system("mkdir -pv '".$create_setting."/Materials'");
	system("mkdir -pv '".$create_setting."/Sections'");
	system("mkdir -pv '".$create_setting."/Tangled'");
	system("mkdir -pv '".$create_setting."/Woven'");
	system("cp -nv '".$path_to_inweb_setting."inweb/Materials/Contents.w' '".
		$create_setting."'");
	system("cp -nv '".$path_to_inweb_setting."inweb/Materials/Main.w' '".
		$create_setting."/Sections'");
 } 
#line 115 "Chapter 1/Program Control.w"
	else {
		
 { 
#line 145 "Chapter 1/Program Control.w"
	read_literate_source();
	language_set($bibliographic_data{"Language"});
	if (($web_language == $C_LANGUAGE) || ($web_language == $C_FOR_INFORM_LANGUAGE)) {
		create_base_types_hash();
	}
	parse_literate_source();
	language_set($bibliographic_data{"Language"});
	if (($web_language == $C_LANGUAGE) || ($web_language == $C_FOR_INFORM_LANGUAGE)) {
		parse_C_like_sections();
	}

 } 
#line 116 "Chapter 1/Program Control.w"
;
		
 { 
#line 159 "Chapter 1/Program Control.w"
	print "\"", $bibliographic_data{"Title"}, "\" ";
	if ($shared_structures+$private_structures > 0) {
		print $shared_structures+$private_structures, " structure(s)";
		if ($shared_structures > 0) { print ", $shared_structures shared"; }
		print ": ";
	}
	if ($no_chapters > 0) { print $no_chapters, " chapter(s) : "; }
	print $no_sections, " section(s) : ", $no_paragraphs, " paragraph(s) : ",
	$no_lines, " line(s)\n";

 } 
#line 117 "Chapter 1/Program Control.w"
;

		if ($web_mode == $ANALYSE_MODE) 
 { 
#line 172 "Chapter 1/Program Control.w"
	if ($swarm_mode != $SWARM_OFF) {
		inweb_fatal_error("only specific parts of the web can be analysed");
	}
	if ($catalogue_switch == 1) { catalogue_the_sections($sigil_of_target, 0); }
	if ($functions_switch == 1) { catalogue_the_sections($sigil_of_target, 1); }
	if ($voids_switch == 1) { catalogue_void_pointers($sigil_of_target); }
	if ($make_graphs_switch == 1) { compile_graphs($sigil_of_target); }
	if ($scan_switch == 1) { scan_line_categories($sigil_of_target); }

 } 
#line 119 "Chapter 1/Program Control.w"
;
		if ($web_mode == $TANGLE_MODE) 
 { 
#line 197 "Chapter 1/Program Control.w"
	my $tn = 0;
	if ($sigil_of_target eq "0") {
		
 { 
#line 215 "Chapter 1/Program Control.w"
	$tn = 0;
	if (exists $bibliographic_data{"Short Title"}) {
		$tangle_to = $bibliographic_data{"Short Title"};
	} else {
		$tangle_to = $bibliographic_data{"Title"};
	}
	language_set($bibliographic_data{"Main Language"});
	$tangle_to .= language_file_extension();

 } 
#line 199 "Chapter 1/Program Control.w"
;
	} elsif (exists($sigil_section{$sigil_of_target})) {
		
 { 
#line 227 "Chapter 1/Program Control.w"
	$tn = $section_tangle_target[$sigil_section{$sigil_of_target}];
	if ($tn == 0) { inweb_fatal_error("section cannot be independently tangled"); }
	$tangle_to = $section_leafname[$sigil_section{$sigil_of_target}];

 } 
#line 201 "Chapter 1/Program Control.w"
;
	} else {
		
 { 
#line 234 "Chapter 1/Program Control.w"
	my $cn;
	for ($cn=0; $cn<$no_chapters; $cn++) {
		if ($chapter_tangle_target[$cn] > 0) {
			if ($sigil_of_target eq $chapter_sigil[$cn]) {
				my $brief = $chapter_title[$cn];
				$brief =~ s/^.*?\:\s*//;
				$tangle_to = $brief;
				$tn = $chapter_tangle_target[$cn];
				last;
			}
		}
	}
	if ($tn == 0) {
		inweb_fatal_error("only the entire web, or specific sections, can be tangled");
	}

 } 
#line 203 "Chapter 1/Program Control.w"
;
	}
	if ($tangle_to eq "") { inweb_fatal_error("no tangle destination known"); }
	$tangle_to = $web_setting."Tangled/".$tangle_to;
	if ($tangle_setting ne "") { $tangle_to = $tangle_setting; }
	tangle_source($tn, $tangle_to);
	print "Tangled: $tangle_to\n";

 } 
#line 120 "Chapter 1/Program Control.w"
;
		if ($web_mode == $WEAVE_MODE) 
 { 
#line 253 "Chapter 1/Program Control.w"
	if ($swarm_mode == $SWARM_OFF) {
		my $shall_we_open = $open_pdf_switch;
		if ($shall_we_open == -1) { # i.e., if it wasn't set at the command line
			if ($open_command_configuration ne "") { $shall_we_open = 1; }
			else { $shall_we_open = 0; }
		}
		weave_sigil($sigil_of_target, $shall_we_open);
	} else { weave_swarm(); }

 } 
#line 121 "Chapter 1/Program Control.w"
;
	}

	if ($no_inweb_errors == 0) { exit(0); } else { exit(1); }

#line 49 "Chapter 1/Command Line and Errors.w"

#line 53 "Chapter 1/Command Line and Errors.w"
sub make_command_line_settings {
	my $i;
	my $targets = 0;
	ARGUMENT: for ($i=0; $i<=$#ARGV; $i++) {
		my $opt = $ARGV[$i];
		my $non_switch_follows = 0;
		if (($i < $#ARGV) && (not($ARGV[$i+1] =~ m/^-/))) { $non_switch_follows = 1; }
		if ($opt =~ m/^-/) 
 { 
#line 71 "Chapter 1/Command Line and Errors.w"
	$opt =~ s/^\-\-/\-/; # allow a doubled-dash as equivalent to one
	if ($opt eq "-test-extensions") {
		print "(Test inweb's implementation of Inform's C extensions)\n";
		full_test_double_squares();
		exit(0);
	}
	if ($opt eq "-verbose-about-input") {
		$verbose_about_input_switch = 1; next ARGUMENT;
	}
	if ($opt eq "-at") {
		if ($non_switch_follows == 1) {
			$path_to_inweb_setting = $ARGV[$i+1]; $i++; next ARGUMENT;
		}
		inweb_fatal_error("-at must be followed by the pathname where inweb lives");
	}
	
 { 
#line 95 "Chapter 1/Command Line and Errors.w"
	if ($opt eq "-analyse-structure") {
		if ($non_switch_follows) {
			$analyse_structure_setting = $ARGV[$i+1]; $i++;
			enter_main_mode($ANALYSE_MODE);
			next ARGUMENT;
		}
		inweb_fatal_error("-analyse-structure must be followed by a structure name");
	}
	if ($opt eq "-catalogue") {
		$catalogue_switch = 1; enter_main_mode($ANALYSE_MODE); next ARGUMENT;
	}
	if ($opt eq "-functions") {
		$functions_switch = 1; enter_main_mode($ANALYSE_MODE); next ARGUMENT;
	}
	if ($opt eq "-voids") {
		$voids_switch = 1; enter_main_mode($ANALYSE_MODE); next ARGUMENT;
	}
	if ($opt eq "-make-graphs") {
		$make_graphs_switch = 1; enter_main_mode($ANALYSE_MODE); next ARGUMENT;
	}
	if ($opt eq "-convert-graphs") {
		$make_graphs_switch = 1; $convert_graphs_switch = 1;
		enter_main_mode($ANALYSE_MODE); next ARGUMENT;
	}
	if ($opt eq "-scan") {
		$scan_switch = 1; enter_main_mode($ANALYSE_MODE); next ARGUMENT;
	}

 } 
#line 86 "Chapter 1/Command Line and Errors.w"
;
	
 { 
#line 126 "Chapter 1/Command Line and Errors.w"
	if ($opt eq "-weave") {
		enter_main_mode($WEAVE_MODE); next ARGUMENT;
	}
	if ($opt eq "-open") {
		$open_pdf_switch = 1; enter_main_mode($WEAVE_MODE); next ARGUMENT;
	}
	if ($opt eq "-closed") {
		$open_pdf_switch = 0; enter_main_mode($WEAVE_MODE); next ARGUMENT;
	}
	if ($opt eq "-only") {
		if ($non_switch_follows) {
			$only_setting = $ARGV[$i+1]; $i++;
			enter_main_mode($WEAVE_MODE);
			next ARGUMENT;
		}
		inweb_fatal_error("-only must be followed by a chapter number or appendix letter");
	}

 } 
#line 87 "Chapter 1/Command Line and Errors.w"
;
	
 { 
#line 147 "Chapter 1/Command Line and Errors.w"
	if ($opt eq "-tangle") {
		enter_main_mode($TANGLE_MODE); next ARGUMENT;
	}
	if ($opt eq "-tangle-to") {
		if ($non_switch_follows) {
			$tangle_setting = $ARGV[$i+1]; $i++;
			enter_main_mode($TANGLE_MODE); next ARGUMENT;
		}
		inweb_fatal_error("-tangle-to must be followed by a filename to write");
	}

 } 
#line 88 "Chapter 1/Command Line and Errors.w"
;
	
 { 
#line 162 "Chapter 1/Command Line and Errors.w"
	if ($opt eq "-create") {
		if ($non_switch_follows == 1) {
			$create_setting = $ARGV[$i+1]; $web_setting = $create_setting; $i++;
			enter_main_mode($CREATE_MODE);
			next ARGUMENT;
		}
		inweb_fatal_error("-create must be followed by the pathname of a web");
	}

 } 
#line 89 "Chapter 1/Command Line and Errors.w"
;
	inweb_fatal_error("unknown command line switch: $opt");

 } 
#line 61 "Chapter 1/Command Line and Errors.w"
		else {
			if ($web_setting eq "") { $web_setting = $opt.'/'; }
			else 
 { 
#line 177 "Chapter 1/Command Line and Errors.w"
	$targets++;
	if ($targets > 1) { inweb_fatal_error("at most one target may be given"); }
	$swarm_mode = $NO_SWARM;
	if ($opt eq "index") {
		$swarm_mode = $SWARM_INDEX;
	} elsif ($opt eq "chapters") {
		$swarm_mode = $SWARM_CHAPTERS;
	} elsif ($opt eq "sections") {
		$swarm_mode = $SWARM_SECTIONS;
	} elsif ($opt eq "all") {
		$sigil_of_target = "0";
	} elsif ($opt =~ m/\//) {
		$sigil_of_target = $opt;
	} elsif ($opt =~ m/^\d+$/) {
		$sigil_of_target = $opt;
	} elsif ($opt =~ m/^[A-O]$/) {
		$sigil_of_target = $opt;
	} elsif ($opt =~ m/^P$/) {
		$sigil_of_target = $opt;
	} else {
		inweb_error("target not recognised: $opt");
		print "The legal targets are:\n";
		print "   all: complete web\n";
		print "   P: all preliminaries\n";
		print "   1: Chapter 1 (and so on)\n";
		print "   A: Appendix A (and so on, up to Appendix O)\n";
		print "   3/eg: section with abbreviated name \"3/eg\" (and so on)\n";
		print "   index: HTML page indexing project\n";
		print "   chapters: all individual chapters\n";
		print "   sections: all individual sections\n";
		exit(1);
	}

 } 
#line 63 "Chapter 1/Command Line and Errors.w"
;
		}
	}
}

#line 213 "Chapter 1/Command Line and Errors.w"
sub enter_main_mode {
	my $new_mode = $_[0];
	if ($web_mode == $NO_MODE) { $web_mode = $new_mode; }
	if ($web_mode != $new_mode) {
		inweb_fatal_error("can only do one at a time - weaving, tangling or analysing");
	}
}

#line 227 "Chapter 1/Command Line and Errors.w"
sub read_configuration_file {
	my $cl;
	open(CONFIG, $path_to_inweb_setting.'inweb/Materials/inweb-configuration.txt')
		or die "inweb: can't open configuration file";
	while ($cl = <CONFIG>) {
		$cl =~ m/^\s*(.*?)\s*$/; $cl = $1;
		if ($cl =~ m/^\#/) { next; } # skip comment lines
		if ($cl eq "") { next; } # skip blank lines
		if ($cl =~ m/^(\S+)\s*=\s*(.*?)$/) {
			my $setting = $1;
			my $value = $2;
			
 { 
#line 247 "Chapter 1/Command Line and Errors.w"
	if ($setting eq "pdftex") { $pdftex_configuration = $value; next; }
	if ($setting eq "dot") { $dot_utility_configuration = $value; next; }
	if ($setting eq "open-command") { $open_command_configuration = $value; next; }
	inweb_error("inweb: bad configuration setting ($setting)");

 } 
#line 238 "Chapter 1/Command Line and Errors.w"
;
		}
	}
	close CONFIG;
}

#line 256 "Chapter 1/Command Line and Errors.w"
sub inweb_fatal_error {
	my $message = $_[0];
	print STDERR "inweb: $message\n";
	exit(1);
}

sub inweb_error {
	my $message = $_[0];
	$no_inweb_errors++;
	print STDERR "inweb: $message\n";
}

sub inweb_error_at {
	my $message = $_[0];
	my $file = $_[1];
	my $line = $_[2];
	$no_inweb_errors++;
	print STDERR "inweb: $message\n";
	print STDERR "  (", $file, " line ", $line, ")\n";
}

sub inweb_error_at_program_line {
	my $message = $_[0];
	my $i = $_[1];
	my $sec = $line_sec[$i];
	inweb_error_at($message, $section_pathname_relative_to_web[$sec], $line_source_file_line[$i]);
}
#line 105 "Chapter 2/Reading Sections.w"
sub read_literate_source {
	read_contents_page("Contents.w");
}

#line 114 "Chapter 2/Reading Sections.w"
sub read_contents_page {
	my $pathname_of_contents = $web_setting.$_[0];
	my $cline; # Line read in from the contents file
	my $clc = 0; # Line count within contents section (for use in error messages)

	my $scanning_bibliographic_block = 1; # Top bit, or bottom bit?
	my $scanning_chapter_purpose = 0; # Reading the bit just after the new chapter?

	my $path_to_chapter_being_read = ""; # Where sections in the current chapter live
	my $titling_line_to_insert = ""; # To be inserted automagically

	$bibliographic_data{"Declare Section Usage"} = "On"; # The default
	$bibliographic_data{"Strict Usage Rules"} = "Off"; # The default

	open CP, $pathname_of_contents
		or die "inweb: can't open contents section at: $pathname_of_contents\n";
	while ($cline = <CP>) {
		$cline =~ s/\s+$//; $clc++;
		if ($cline eq "") { $scanning_bibliographic_block = 0; next; }
		if ($scanning_bibliographic_block == 1) 
 { 
#line 149 "Chapter 2/Reading Sections.w"
	if ($cline =~ m/^(.*?)\:\s*(.*?)\s*$/) {
		my $key = $1;
		my $value = $2;
		if ($key eq "License") { $key = "Licence"; } # alias US to UK spelling
		if (($key eq "Title") || ($key eq "Short Title") || ($key eq "Author") ||
			($key eq "Purpose") || ($key eq "Licence") ||
			($key eq "Build Number") || ($key eq "Language") ||
			($key eq "Index Extras") || ($key eq "Index Template") ||
			($key eq "Cover Sheet") || ($key eq "Namespaces") ||
			($key eq "Strict Usage Rules") || ($key eq "Declare Section Usage")) {
			$bibliographic_data{$key} = $value;
			if ((($key eq "Strict Usage Rules") || ($key eq "Declare Section Usage") ||
				($key eq "Namespaces")) &&
				($value ne "On") && ($value ne "Off")) {
				inweb_error_at("This setting must be 'On' or 'Off'", "Contents.w", $clc);
			}
		} else { inweb_error_at("no such bibliographic datum as '$key'", "Contents.w", $clc); }
	} else { inweb_error_at("expected 'Setting: Value' but found '$cline'", "Contents.w", $clc); }
	next;

 } 
#line 133 "Chapter 2/Reading Sections.w"
;
		
 { 
#line 200 "Chapter 2/Reading Sections.w"
	$cline =~ m/^(\s*)(.*?)$/; # A pattern which cannot fail to match
	my $whitespace = $1; local $title = $2;
	if ($whitespace eq "") {
		if ($cline =~ m/^\"(.*)$/) { $scanning_chapter_purpose = 1; $cline = $1; }
		if ($scanning_chapter_purpose == 1) 
 { 
#line 214 "Chapter 2/Reading Sections.w"
	if ($cline =~ m/^(.*)\"\s*$/) { $cline = $1; $scanning_chapter_purpose = 0; }
	if ($chapter_rubric[$no_chapters-1] ne "") {
		$chapter_rubric[$no_chapters-1] .= " ";
	}
	$chapter_rubric[$no_chapters-1] .= $cline;
	next;

 } 
#line 205 "Chapter 2/Reading Sections.w"
		else 
 { 
#line 224 "Chapter 2/Reading Sections.w"
	my $new_chapter_sigil = ""; # e.g., P, 1, 2, 3, A, B, ...
	my $pdf_leafname = "";
	my $ind_target = 0;

	if ($title =~ m/^(.*?)\s*\(\s*Independent\s*(.*?)\s*\)\s*$/)
		
 { 
#line 263 "Chapter 2/Reading Sections.w"
	$title = $1; $lang = $2;
	$current_tangle_target = ++$no_tangle_targets;
	$ind_target = $current_tangle_target;
	$tangle_target_language[$no_tangle_targets] = $bibliographic_data{"Language"};
	if ($lang ne "") { $tangle_target_language[$no_tangle_targets] = $lang; }

 } 
#line 229 "Chapter 2/Reading Sections.w"
;

	if ($title eq "Sections") {
		$new_chapter_sigil = "S"; $path_to_chapter_being_read = "Sections/";
		$titling_line_to_insert = "";
		$pdf_leafname = "Sections.pdf";
		$web_is_chaptered = 0;
	} elsif ($title eq "Preliminaries") {
		$new_chapter_sigil = "P"; $path_to_chapter_being_read = "Preliminaries/";
		$titling_line_to_insert = "";
		$pdf_leafname = "Preliminaries.pdf";
		$web_is_chaptered = 1;
	} elsif ($title =~ m/^Chapter\s+(\d+)\:\s*(.*?)$/) {
		$new_chapter_sigil = $1; $path_to_chapter_being_read = "Chapter $1/";
		$titling_line_to_insert = $title.".";
		$pdf_leafname = "Chapter-$1.pdf";
		$web_is_chaptered = 1;
	} elsif ($title =~ m/^Appendix\s+([A-O])\:\s*(.*?)$/) {
		$new_chapter_sigil = $1; $path_to_chapter_being_read = "Appendix $1/";
		$titling_line_to_insert = $title.".";
		$pdf_leafname = "Appendix-$1.pdf";
		$web_is_chaptered = 1;
	} else {
		inweb_error_at("segment '$title' not understood", "Contents.w", $clc);
		print STDERR "(Must be 'Chapter <number>: Title', 'Appendix <letter A to O>: Title',\n";
		print STDERR "'Preliminaries' or 'Sections')\n";
	}

	
 { 
#line 272 "Chapter 2/Reading Sections.w"
	$chapter_sigil[$no_chapters] = $new_chapter_sigil;
	$chapter_title[$no_chapters] = $title;
	$chapter_rubric[$no_chapters] = "";
	$chapter_tangle_target[$no_chapters] = $ind_target;
	$chapter_woven_pdf_leafname[$no_chapters] = $pdf_leafname;
	if ($ind_target == 0) { $current_tangle_target = 0; }
	$no_chapters++;

 } 
#line 257 "Chapter 2/Reading Sections.w"
;

 } 
#line 205 "Chapter 2/Reading Sections.w"
;
	} else 
 { 
#line 285 "Chapter 2/Reading Sections.w"
	my $source_file_extension = ".w";
	if ($title =~ m/^(.*?)\s*\(\s*Independent\s*(.*?)\s*\)\s*$/) {
		
 { 
#line 311 "Chapter 2/Reading Sections.w"
	$title = $1; $lang = $2;
	$section_tangle_target[$no_sections] = ++$no_tangle_targets;
	$tangle_target_language[$no_tangle_targets] = $bibliographic_data{"Language"};
	if ($lang ne "") {
		$tangle_target_language[$no_tangle_targets] = $lang;
		if ($lang eq "Inform 6") { $source_file_extension = ".i6t"; }
	}

 } 
#line 287 "Chapter 2/Reading Sections.w"
;
	} else {
		$section_tangle_target[$no_sections] = $current_tangle_target;
	}
	$section_chap[$no_sections] = $no_chapters - 1;
	$section_extent[$no_sections] = 0;
	my $path_to_section = $path_to_chapter_being_read.$title.$source_file_extension;
	$path_to_section =~ s/ Template\.i6t$/\.i6t/;
	$section_pathname_relative_to_web[$no_sections] = $path_to_section;
	$section_leafname[$no_sections] = $path_to_section;
	if ($section_leafname[$no_sections] =~ m/\/([^\/]*?)$/) {
		$section_leafname[$no_sections] = $1;
	}
	$section_number_from_leafname{$section_leafname[$no_sections]} = $no_sections;
	read_file($path_to_section, $titling_line_to_insert, $no_sections);
	$no_sections++;

 } 
#line 206 "Chapter 2/Reading Sections.w"
;
	next;

 } 
#line 134 "Chapter 2/Reading Sections.w"
;
	}
	close CP;
	if ($verbose_about_input_switch == 1) {
		print "Read contents section: '", $leafname, "' (", $cline, " lines)\n";
	}

	
 { 
#line 173 "Chapter 2/Reading Sections.w"
	ensure_setting_of("Title"); ensure_setting_of("Author");
	ensure_setting_of("Purpose"); ensure_setting_of("Language");
	$bibliographic_data{"Inweb Build"} = $INWEB_BUILD;
	$bibliographic_data{"Main Language"} = $bibliographic_data{"Language"};

 } 
#line 141 "Chapter 2/Reading Sections.w"
;
	
 { 
#line 193 "Chapter 2/Reading Sections.w"
	$tangle_target_language[0] = $bibliographic_data{"Language"};
	$no_tangle_targets++;

 } 
#line 142 "Chapter 2/Reading Sections.w"
;
}

#line 181 "Chapter 2/Reading Sections.w"
sub ensure_setting_of {
	my $setting = $_[0];
	if (not (exists ($bibliographic_data{$setting}))) {
		inweb_fatal_error("The Contents.w section does not specify '$setting: ...'");
	}
}

#line 324 "Chapter 2/Reading Sections.w"
sub read_file {
	my $path_relative_to_web = $_[0];
	my $titling_line_for_this_chapter = $_[1];
	my $section_number = $_[2];
	my $file_line_count = 0;

	my $pathname = $web_setting.$path_relative_to_web;

	if (($titling_line_for_this_chapter ne "") &&
		($titling_of_current_chapter ne $titling_line_for_this_chapter)) {
		$titling_of_current_chapter = $titling_line_for_this_chapter;
		$nl = '@*** '.$titling_of_current_chapter;
		
 { 
#line 355 "Chapter 2/Reading Sections.w"
	# The text, with a spare copy protected from the parser's meddling:
	$line_text[$no_lines] = $nl;
	$line_text_raw[$no_lines] = $nl;

	# And where it occurs in the web:
	$line_sec[$no_lines] = $section_number;
	$line_source_file_line[$no_lines] = $file_line_count;

	# And keep count:
	$no_lines++;
	$section_extent[$section_number]++; # Not the same as the file line count!

 } 
#line 336 "Chapter 2/Reading Sections.w"
;
	}

	open SECTIONF, $pathname or die "inweb: Unable to open $pathname\n";

	while ($nl = <SECTIONF>) {
		$file_line_count++;
		$nl =~ s/\s+$//; # remove trailing whitespace and the line break
		
 { 
#line 355 "Chapter 2/Reading Sections.w"
	# The text, with a spare copy protected from the parser's meddling:
	$line_text[$no_lines] = $nl;
	$line_text_raw[$no_lines] = $nl;

	# And where it occurs in the web:
	$line_sec[$no_lines] = $section_number;
	$line_source_file_line[$no_lines] = $file_line_count;

	# And keep count:
	$no_lines++;
	$section_extent[$section_number]++; # Not the same as the file line count!

 } 
#line 344 "Chapter 2/Reading Sections.w"
;
	}
	close SECTIONF;
	if ($verbose_about_input_switch == 1) {
		print "Read section: '", $pathname, "' (", $file_line_count, " lines)\n";
	}
}

#line 373 "Chapter 2/Reading Sections.w"
sub line_is_in_heading_position {
	my $i = $_[0];
	if (($line_source_file_line[$i] == 0) ||
		($line_source_file_line[$i] == 1)) { return 1; }
	return 0;
}
#line 40 "Chapter 2/Line Categories.w"
sub scan_line_categories {
	my $sigil = $_[0];
	my $confine_to = -1;
	my $sn;
	my $i;
	for ($sn=0; $sn<$no_sections; $sn++) {
		if ($section_sigil[$sn] eq $sigil) {
			$confine_to = $sn;
		}
	}
	for ($i=0; $i<$no_lines; $i++) {
		if (($confine_to >= 0) && ($confine_to != $line_sec[$i])) { next; }
		print sprintf("%04d  %16s  %s\n",
			$i, category_name($line_category[$i]), $line_text[$i]);
	}
}

#line 60 "Chapter 2/Line Categories.w"
sub category_name {
	my $cat = $_[0];
	if ($cat == $COMMENT_BODY_LCAT) { return "COMMENT_BODY"; }
	elsif ($cat == $MACRO_DEFINITION_LCAT) { return "MACRO_DEFINITION"; }
	elsif ($cat == $BAR_LCAT) { return "BAR"; }
	elsif ($cat == $INDEX_ENTRY_LCAT) { return "INDEX_ENTRY"; }
	elsif ($cat == $PURPOSE_LCAT) { return "PURPOSE"; }
	elsif ($cat == $INTERFACE_LCAT) { return "INTERFACE"; }
	elsif ($cat == $GRAMMAR_LCAT) { return "GRAMMAR"; }
	elsif ($cat == $DEFINITIONS_LCAT) { return "DEFINITIONS"; }
	elsif ($cat == $PARAGRAPH_START_LCAT) { return "PARAGRAPH_START"; }
	elsif ($cat == $BEGIN_VERBATIM_LCAT) { return "BEGIN_CODE"; }
	elsif ($cat == $TEXT_EXTRACT_LCAT) { return "TEXT_EXTRACT"; }
	elsif ($cat == $BEGIN_DEFINITION_LCAT) { return "BEGIN_DEFINITION"; }
	elsif ($cat == $GRAMMAR_BODY_LCAT) { return "GRAMMAR_BODY"; }
	elsif ($cat == $INTERFACE_BODY_LCAT) { return "INTERFACE_BODY"; }
	elsif ($cat == $CODE_BODY_LCAT) { return "CODE_BODY"; }
	elsif ($cat == $SOURCE_DISPLAY_LCAT) { return "SOURCE_DISPLAY"; }
	elsif ($cat == $TOGGLE_WEAVING_LCAT) { return "TOGGLE_WEAVING"; }
	elsif ($cat == $COMMAND_LCAT) { return "COMMAND"; }
	elsif ($cat == $CONT_DEFINITION_LCAT) { return "CONT_DEFINITION"; }
	else { return "? cat $cat"; }
}
#line 106 "Chapter 2/The Parser.w"
sub parse_literate_source {
	
 { 
#line 116 "Chapter 2/The Parser.w"
	my $i;
	for ($i=0; $i<$no_lines; $i++) {
		$line_is_comment[$i] = 0;
		$line_category[$i] = $NO_LCAT;
		$line_paragraph_number[$i] = 0;
		$line_paragraph_ornament[$i] = "";
		$line_starts_paragraph_on_new_page[$i] = 0;
	}

	for ($i=0; $i<$no_sections; $i++) {
		$section_sigil[$i] = "";
		$section_toc[$i] = "";
		$section_purpose[$i] = "";
		$section_no_pars[$i] = 0;
	}

 } 
#line 107 "Chapter 2/The Parser.w"
;
	determine_line_categories(); # Pass 1
	establish_canonical_section_names(); # Pass 2
	
 { 
#line 135 "Chapter 2/The Parser.w"
	my $i;
	$no_paragraphs = 0;
	for ($i=0; $i<$no_lines; $i++) {
		if ($line_category[$i] == $PARAGRAPH_START_LCAT) {
			$no_paragraphs++;
		}
	}

 } 
#line 110 "Chapter 2/The Parser.w"
;
}

#line 148 "Chapter 2/The Parser.w"
sub determine_line_categories {
	$comment_mode = 1;
	$grammar_mode = 0;

	CATEGORISATION: for ($i=0; $i<$no_lines; $i++) {
		$line_is_comment[$i] = $comment_mode;
		$line_category[$i] = $COMMENT_BODY_LCAT; # Until set otherwise down below
		my $l = $line_text[$i];

		if (line_is_in_heading_position($i)) {
			language_set($tangle_target_language[$section_tangle_target[$line_sec[$i]]]);
			
 { 
#line 197 "Chapter 2/The Parser.w"
	if ($l =~ m/^(([A-Za-z0-9_]+::\s*)*)(\S+\/[a-z][a-z0-9]+)\:\s+(.*)\s*$/) {
		$section_namespace[$line_sec[$i]] = $1;
		$section_sigil[$line_sec[$i]] = $3;
		$sigil_section{$1} = $line_sec[$i];
		$l = '@* '.$4;
		$section_namespace[$line_sec[$i]] =~ s/\s*//g;
	} else {
		if (($l =~ m/^Chapter /) || ($l =~ m/^Appendix /)) {
			$l = '@** '.$l;
		}
	}

 } 
#line 159 "Chapter 2/The Parser.w"
;
		}

		if ($l =~ m/^\[\[\s*(.*?)\s*\]\]\s*$/)
			
 { 
#line 213 "Chapter 2/The Parser.w"
	my $comm = $1;
	$line_category[$i] = $COMMAND_LCAT;
	if ($comm =~ m/^(.*?)\s*\:\s*(.*)\s*$/) {
		$comm = $1;
		$line_operand_2[$i] = $2;
	}

	if ($comm eq "Page Break") { $line_operand[$i] = $PAGEBREAK_CMD; }
	elsif ($comm eq "BNF Grammar") { $line_operand[$i] = $BNF_GRAMMAR_CMD; }
	elsif ($comm eq "Thematic Index") { $line_operand[$i] = $THEMATIC_INDEX_CMD; }
	elsif ($comm =~ m/^Index Under (.*)$/) {
		$thematic_indices{$1} .= $line_operand_2[$i]."...".$i."|";
		$line_operand[$i] = $INDEX_UNDER_CMD;
	}
	elsif ($comm eq "Figure") { $line_operand[$i] = $FIGURE_CMD; }
	else { inweb_error("unknown command $l\n"); }
	$line_is_comment[$i] = 1;

 } 
#line 163 "Chapter 2/The Parser.w"
;

		if (language_pagebreak_comment($l)) {
			$line_category[$i] = $COMMAND_LCAT;
			$line_operand[$i] = $PAGEBREAK_CMD;
			next CATEGORISATION;
		}

		if ($l =~ m/^\s*\@\<\s*(.*?)\s*\@\>\s*\=\s*(.*?)$/)
			
 { 
#line 235 "Chapter 2/The Parser.w"
	$line_category[$i] = $MACRO_DEFINITION_LCAT;
	$line_operand[$i] = $1; # The name of the macro
	$line_operand_2[$i] = $2; # Any beginning of its content on the same line
	$comment_mode = 0;
	$line_is_comment[$i] = 0;
	$code_lcat_for_body = $CODE_BODY_LCAT; # Code follows on subsequent lines
	next CATEGORISATION;

 } 
#line 172 "Chapter 2/The Parser.w"
;

		if ($l =~ m/^\@(\S*)(.*?)$/) {
			my $command = $1;
			my $remainder = $2;
			my $succeeded = 0;
			
 { 
#line 258 "Chapter 2/The Parser.w"
	if ($line_category[$i] == $MACRO_DEFINITION_LCAT) { $succeeded = 1; }
	
 { 
#line 275 "Chapter 2/The Parser.w"
	if ($command eq "Purpose:") {
		$line_category[$i] = $PURPOSE_LCAT;
		$line_operand[$i] = $remainder;
		$line_is_comment[$i] = 1;
		$section_purpose[$line_sec[$i]] = $remainder;
		$i2 = $i+1;
		while ($line_text[$i2] =~ m/[a-z]/) {
			$section_purpose[$line_sec[$i]] .= " ".$line_text[$i2];
			$i2++;
		}
		next CATEGORISATION;
	}
	if ($command eq "Interface:") {
		$line_category[$i] = $INTERFACE_LCAT;
		$line_is_comment[$i] = 1;
		$grammar_mode = 0;
		next CATEGORISATION;
	}
	if ($command eq "Grammar:") {
		$line_category[$i] = $GRAMMAR_LCAT;
		$line_is_comment[$i] = 1;
		$grammar_mode = 1;
		next CATEGORISATION;
	}
	if ($command eq "Definitions:") {
		$line_category[$i] = $DEFINITIONS_LCAT;
		$line_is_comment[$i] = 1;
		$grammar_mode = 0;
		next CATEGORISATION;
	}
	if ($command =~ m/\-\-\-\-+/) {
		$line_category[$i] = $BAR_LCAT;
		$line_is_comment[$i] = 1;
		$command = "";
		$grammar_mode = 0;
		next CATEGORISATION;
	}

 } 
#line 259 "Chapter 2/The Parser.w"
;
	
 { 
#line 317 "Chapter 2/The Parser.w"
	if (($command eq "c") || ($command eq "x")) {
		$line_category[$i] = $BEGIN_VERBATIM_LCAT;
		if ($command eq "x") { $code_lcat_for_body = $TEXT_EXTRACT_LCAT; }
		else { $code_lcat_for_body = $CODE_BODY_LCAT; }
		$comment_mode = 0;
		$succeeded = 1;
		$line_text[$i] = "";
	}

 } 
#line 260 "Chapter 2/The Parser.w"
;
	
 { 
#line 330 "Chapter 2/The Parser.w"
	if ($command eq "d") {
		$line_category[$i] = $BEGIN_DEFINITION_LCAT;
		$code_lcat_for_body = $CONT_DEFINITION_LCAT;
		if ($remainder =~ m/^\s*(\S+)\s+(.+?)\s*$/) {
			$line_operand[$i] = $1; # Name of term defined
			$line_operand_2[$i] = $2; # Value
		} else {
			$line_operand[$i] = $remainder; # Name of term defined
			$line_operand_2[$i] = ""; # No value given
		}
		$comment_mode = 0;
		$line_is_comment[$i] = 0;
		$succeeded = 1;
	}

 } 
#line 261 "Chapter 2/The Parser.w"
;
	my $weight = -1;
	if ($command eq "") { $weight = 0; }
	if ($command eq "p") { $weight = 1; }
	if ($command eq "pp") { $weight = 1; $line_starts_paragraph_on_new_page[$i] = 1; }
	if ($command eq "*") { $weight = 2; }
	if ($command eq "**") { $weight = 2; }
	if ($command eq "***") { $weight = 3; }
	if ($command =~ m/\*(\d)/) { $weight = eval($1)-1; }
	if ($weight >= 0) 
 { 
#line 362 "Chapter 2/The Parser.w"
	$grammar_mode = 0;
	$comment_mode = 1;
	$line_is_comment[$i] = 1;
	$line_category[$i] = $PARAGRAPH_START_LCAT;
	$line_operand[$i] = $weight; # Weight
	$line_operand_2[$i] = ""; # Title
	if (($weight > 0) && ($remainder =~ m/\s+(.*?)\.\s*(.*)$/)) {
		$line_operand_2[$i] = $1; # Title up to the full stop
		$line_text[$i] = $2; # And then some regular material
	} else {
		if ($remainder =~ m/\s+(.+?)$/) { $line_text[$i] = $1; }
		else { $line_text[$i] = ""; }
	}
	$succeeded = 1;

 } 
#line 270 "Chapter 2/The Parser.w"
;

 } 
#line 178 "Chapter 2/The Parser.w"
;
			if ($succeeded == 0) {
				inweb_error_at_program_line("don't understand @".$command." at:", $i);
			}
		}

		if ($grammar_mode == 1) 
 { 
#line 425 "Chapter 2/The Parser.w"
	$line_category[$i] = $GRAMMAR_BODY_LCAT;
	$bnf_grammar[$bnf_grammar_lines] = $l;
	$bnf_grammar_source[$bnf_grammar_lines] = $i;
	$bnf_grammar_lines++;
	next CATEGORISATION;

 } 
#line 184 "Chapter 2/The Parser.w"
;
		if ($comment_mode == 1) 
 { 
#line 383 "Chapter 2/The Parser.w"
	if ($line_text[$i] =~ m/^\>\>\s+(.*?)\s*$/) {
		$line_category[$i] = $SOURCE_DISPLAY_LCAT;
		$line_operand[$i] = $1;
	}
	if (($web_language == $C_LANGUAGE) || ($web_language == $C_FOR_INFORM_LANGUAGE)) {
		if (scan_line_for_interface($i)) {
			$line_category[$i] = $INTERFACE_BODY_LCAT;
		}
	}

 } 
#line 185 "Chapter 2/The Parser.w"
;
		if ($comment_mode == 0) 
 { 
#line 398 "Chapter 2/The Parser.w"
	if (($web_language == $C_LANGUAGE) || ($web_language == $C_FOR_INFORM_LANGUAGE)) {
		scan_line_for_interface($i);
	}

	if (($line_category[$i] != $BEGIN_DEFINITION_LCAT) &&
		($line_category[$i] != $COMMAND_LCAT)) {
		$line_category[$i] = $code_lcat_for_body;
	}

	if (($line_category[$i] == $CONT_DEFINITION_LCAT) &&
		($line_text[$i] =~ m/^\s*$/)) {
		$line_category[$i] = $COMMENT_BODY_LCAT;
		$code_lcat_for_body = $COMMENT_BODY_LCAT;
	}

	if (language_and_so_on($line_text[$i])) {
		$line_category[$i] = $TOGGLE_WEAVING_LCAT;
	}

	if ($web_language == $C_FOR_INFORM_LANGUAGE)
		
 { 
#line 436 "Chapter 2/The Parser.w"
	if ($l =~ m/the_debugging_aspects\[\] =/) {
		$bnf_grammar_source[$bnf_grammar_lines] = $i;
		$bnf_grammar[$bnf_grammar_lines++] = "<debugging-aspect>";
		$da_baseline = $i;
	}
	if (($l =~ m/^\s+\{\s+\"(.+?)\"\,\s+\"(.*?)\"\,\s+\"(.*?)\"/)
		&& ($i < $da_baseline+200)) {
		$bnf_grammar[$bnf_grammar_lines] = "    := $1";
		if ($2 ne "") { $bnf_grammar[$bnf_grammar_lines] .= " $2"; }
		if ($3 ne "") { $bnf_grammar[$bnf_grammar_lines] .= " $3"; }
		$bnf_grammar_lines++;
	}

 } 
#line 418 "Chapter 2/The Parser.w"
;

 } 
#line 186 "Chapter 2/The Parser.w"
;
	}
}

#line 455 "Chapter 2/The Parser.w"
sub establish_canonical_section_names {
	my $par_number_counter = 0;
	my $pnum = 0;
	my $ornament = "\\S";
	my $i;

	my $toc = "";
	my $toc_range_start = 0;
	my $toc_name = "";

	
 { 
#line 526 "Chapter 2/The Parser.w"
	$toc = ""; $toc_range_start = 0;

 } 
#line 465 "Chapter 2/The Parser.w"
;
	for ($i=0; $i<$no_lines; $i++) {
		if (($line_category[$i] == $DEFINITIONS_LCAT) ||
			($line_category[$i] == $PURPOSE_LCAT)) {
			$ornament = "\\P";
			$par_number_counter = 0; # Start counting paras from 1
		}
		if ($line_category[$i] == $BAR_LCAT) {
			$ornament = "\\S";
			$par_number_counter = 0; # Start counting paras from 1 again
			
 { 
#line 540 "Chapter 2/The Parser.w"
	$toc = complete_toc_chunk($toc, $toc_range_start, $par_number_counter, $toc_name);
	$toc_range_start = 0;

 } 
#line 475 "Chapter 2/The Parser.w"
;
		}
		if ($line_category[$i] == $PARAGRAPH_START_LCAT) {
			$par_number_counter++;
			if ($line_operand[$i] == 2) { # weight 2, so a section heading
				if ($line_sec[$i] > 0) # i.e., if this isn't the first section
					
 { 
#line 546 "Chapter 2/The Parser.w"
	$toc = complete_toc_chunk($toc, $toc_range_start, $par_number_counter-1, $toc_name);
	set_toc_for_section($line_sec[$i]-1, $toc);

 } 
#line 481 "Chapter 2/The Parser.w"
;
				
 { 
#line 526 "Chapter 2/The Parser.w"
	$toc = ""; $toc_range_start = 0;

 } 
#line 482 "Chapter 2/The Parser.w"
;
			}
			$section_no_pars[$line_sec[$i]]++;
			if ($line_operand[$i] == 1) # weight 1: a named |@p| or |@pp| paragraph
				
 { 
#line 531 "Chapter 2/The Parser.w"
	$toc = complete_toc_chunk($toc, $toc_range_start, $par_number_counter-1, $toc_name);
	$toc_range_start = $par_number_counter; $toc_name = $line_operand_2[$i];
	if ($toc eq "") { $toc = $section_sigil[$line_sec[$i]]."."; }
	else { $toc .= "; "; }
	$toc .= '$'.$ornament.'$'.$par_number_counter;

 } 
#line 486 "Chapter 2/The Parser.w"
;
		}

		$line_paragraph_ornament[$i] = $ornament;
		$line_paragraph_number[$i] = $par_number_counter;
		if ($line_category[$i] == $MACRO_DEFINITION_LCAT)
			
 { 
#line 504 "Chapter 2/The Parser.w"
	my $j = $i;
	my $name = $line_operand[$i];
	$cweb_macros_paragraph_number{$name} = $par_number_counter;
	$cweb_macros_start{$name} = $j+1;
	$cweb_macros_surplus_bit{$name} = $line_operand_2[$j];
	$j++;
	while (($j<$no_lines) && ($line_category[$j] == $CODE_BODY_LCAT)) {
		$line_occurs_in_CWEB_macro_definition[$j] = 1;
		$j++;
	}
	$cweb_macros_end{$name} = $j;

 } 
#line 492 "Chapter 2/The Parser.w"
;

		$line_csn[$i] = $section_sigil[$line_sec[$i]].
			'.$'.$line_paragraph_ornament[$i].'$'.
			$line_paragraph_number[$i];
	}
	
 { 
#line 552 "Chapter 2/The Parser.w"
	$toc = complete_toc_chunk($toc, $toc_range_start, $par_number_counter, $toc_name);
	set_toc_for_section($line_sec[$no_lines-1], $toc);

 } 
#line 498 "Chapter 2/The Parser.w"
;
}

#line 560 "Chapter 2/The Parser.w"
sub complete_toc_chunk {
	my $toc = $_[0];
	my $toc_range_start = $_[1];
	my $pnum = $_[2];
	my $toc_name = $_[3];
	if ($toc_range_start != 0) {
		if ($pnum != $toc_range_start) { $toc .= "-".$pnum; }
		$toc .= "~".$toc_name;
	}
	return $toc;
}

#line 576 "Chapter 2/The Parser.w"
sub set_toc_for_section {
	my $sect_no = $_[0];
	my $toc = $_[1];
	$section_toc[$sect_no] = $toc;
	return; # delete this line for a debugging trace, viz...
	if ($toc eq "") {
		print "Warning: ", $section_sigil[$sect_no], " has no TOC.\n";
	} else {
		print $section_sigil[$sect_no], " has TOC ", $toc, "\n";
	}
}
#line 149 "Chapter 2/Identifiers.w"

#line 162 "Chapter 2/Identifiers.w"
sub create_base_types_hash {
	my $i;
	$base_types{"char"} = 1;
	$base_types{"int"} = 1;
	$base_types{"float"} = 1;
	$base_types{"void"} = 1;
	$base_types{"FILE"} = 1;
	for ($i=0; $i<$no_lines; $i++) {
		if ($line_text[$i] =~ m/^typedef\s+struct\s+(\S+)\s+/) {
			$base_types{$1} = 1;
		}
	}
}

#line 216 "Chapter 2/Identifiers.w"
sub scan_line_for_interface {
	my $i = $_[0];
	my $l = $line_text[$i];
	my $secname = $section_leafname[$line_sec[$i]];
	
 { 
#line 234 "Chapter 2/Identifiers.w"
	if ($l =~ m/^\-\-\s+Owns struct (\S+)\s+/) {
		$section_declared_structure_interface[$line_sec[$i]] .= $l."\n";
		$structure_declared_owner{$1} = $secname;
		return 1;
	}
	if ($l =~ m/^\s+\!\- shared with/) {
		$section_declared_structure_interface[$line_sec[$i]] .= $l."\n";
		return 1;
	}

 } 
#line 220 "Chapter 2/Identifiers.w"
;
	if ($web_language == $C_FOR_INFORM_LANGUAGE)
		
 { 
#line 307 "Chapter 2/Identifiers.w"
	if ($l =~ m/^\-\-\s+Defines \{-callv*\:(.*?)\}\s*$/) {
		$id = $1; $id =~ s/::/__/g;
		$section_I6_template_identifiers[$line_sec[$i]] .= $id.':';
		return 1;
	}
	if ($l =~ m/^\-\-\s+Defines \{-array\:(.*?)\}\s*$/) {
		$id = $1; $id =~ s/::/__/g;
		$section_I6_template_identifiers[$line_sec[$i]] .= $id.'_array:';
		return 1;
	}
	if ($l =~ m/^\-\-\s+Defines \{-routine\:(.*?)\}\s*$/) {
		$id = $1; $id =~ s/::/__/g;
		$section_I6_template_identifiers[$line_sec[$i]] .= $id.'_routine:';
		return 1;
	}

 } 
#line 222 "Chapter 2/Identifiers.w"
;
	
 { 
#line 247 "Chapter 2/Identifiers.w"
	if ($l =~ m/^\-\-\s+Used by Chapter (\d+)\/(.*?)\s*$/) {
		$section_declared_used_by_block[$line_sec[$i]] .= ':'.$1.'-'.$2;
		return 1;
	}
	if ($l =~ m/^\-\-\s+Uses Chapter (\d+)\/(.*?)\s*$/) {
		$section_declared_uses_block[$line_sec[$i]] .= ':'.$1.'-'.$2;
		return 1;
	}
	if ($l =~ m/^\-\-\s+Service\: used widely\s*$/) {
		$section_declared_a_service[$line_sec[$i]] = 1;
		return 1;
	}

 } 
#line 223 "Chapter 2/Identifiers.w"
;
	if ($current_struct ne "")
		
 { 
#line 288 "Chapter 2/Identifiers.w"
	if ($l =~ m/^\s*struct\s+([A-Za-z_][A-Za-z0-9_]*)\s+(\**)(.*?)\s*\;/) {
		# The member is either another structure or a pointer to one
		if ($2 eq "") { # An actual incorporation of another structure
			$structure_incorporates{$current_struct} .= '->'.$1;
		}
		member_detected($current_struct, $1, $2, $3, 1);
	} elsif ($l =~ m/^\s*([A-Za-z_][A-Za-z0-9_]*)\s+()\(\*(.*?)\)\(.*\)\;/) {
		# The member is a function pointer
		member_detected($current_struct, $1, $2, $3, 0);
	} elsif ($l =~ m/^\s*([A-Za-z_][A-Za-z0-9_]*)\s+(\**)(.*?)\s*\;/) {
		# The member has a base type which is not a structure
		member_detected($current_struct, $1, $2, $3, 0);
	}

 } 
#line 225 "Chapter 2/Identifiers.w"
;
	
 { 
#line 266 "Chapter 2/Identifiers.w"
	if ($l =~ m/typedef\s+struct\s+(\S+)/) {
		$candidate = $1;
		if (not ($candidate =~ m/\#\#/)) {
			$structure_declaration_line{$candidate} = $i;
			$current_struct = $candidate;
			$structures{$candidate} = 1;
		}
	}

 } 
#line 226 "Chapter 2/Identifiers.w"
;
	
 { 
#line 278 "Chapter 2/Identifiers.w"
	if (($current_struct ne "") && ($l =~ m/^\}/)) {
		$structure_declaration_end{$current_struct} = $i;
		$current_struct = "";
	}

 } 
#line 227 "Chapter 2/Identifiers.w"
;
	return 0;
}

#line 337 "Chapter 2/Identifiers.w"
sub member_detected {
	my $structure = $_[0];
	my $return_type = $_[1];
	my $return_type_pointer_stars = $_[2];
	my $member_name = $_[3];
	my $vouched_for = $_[4];

	
 { 
#line 362 "Chapter 2/Identifiers.w"
	if ($member_name =~ m/^\s*(.*?)\,\s*(.*?)\s*$/) {
		my $left_chunk = $1;
		my $right_chunk = $2;
		member_detected($structure, $return_type, $return_type_pointer_stars,
			$left_chunk, $vouched_for);
		member_detected($structure, $return_type, $return_type_pointer_stars,
			$right_chunk, $vouched_for);
		return;
	}

 } 
#line 344 "Chapter 2/Identifiers.w"
;

	$member_name =~ s/\[.*$//;

	if (exists($blacklisted_members{$member_name})) { return; }

	if ((exists $base_types{$return_type}) || ($vouched_for == 1)) {
		$member_structures{$member_name} .= $structure.":";
		$member_types{$member_name} .= " ".$return_type.$return_type_pointer_stars;
	} else {
		inweb_error("member '".$member_name."' of structure '".$structure.
			"' has unknown type '".$return_type."'");
	}
}

#line 380 "Chapter 2/Identifiers.w"
sub parse_C_like_sections {
	my $i;
	for ($i=0; $i<$no_sections; $i++) { $section_errors[$no_sections] = ""; }

	
 { 
#line 393 "Chapter 2/Identifiers.w"
	find_function_definitions();
	scan_identifiers_in_source();
	find_actual_section_usage();
	check_interface_declarations_for_uses_and_used_by();

 } 
#line 384 "Chapter 2/Identifiers.w"
;
	
 { 
#line 401 "Chapter 2/Identifiers.w"
	find_structure_ownership();
	establish_structure_usage();
	check_interface_declarations_for_structures();
	if ($web_language == $C_FOR_INFORM_LANGUAGE) { check_uniqueness_of_structure_members(); }

 } 
#line 385 "Chapter 2/Identifiers.w"
;

	report_any_interface_errors_found();
}

#line 410 "Chapter 2/Identifiers.w"
sub find_function_definitions {
	my $i;
	for ($i=0; $i<$no_lines; $i++) {
		if (($line_category[$i] == $CODE_BODY_LCAT)
			|| ($line_category[$i] == $BEGIN_DEFINITION_LCAT)
			|| ($line_category[$i] == $CONT_DEFINITION_LCAT))
			
 { 
#line 426 "Chapter 2/Identifiers.w"
	my $look_for_identifiers = $line_text[$i];
	my $stars_in_comment = "";
	my $type_qualifiers = "";
	if ($look_for_identifiers =~ m/^\s*\/(\*+)\/\s*(.*)$/) {
		$stars_in_comment = $1; $look_for_identifiers = $2;
	}
	if ($look_for_identifiers =~ m/^\s*(signed|unsigned|long)\s+(.*)$/) {
		$type_qualifiers = $1; $look_for_identifiers = $2;
	}
	if ($look_for_identifiers =~
		m/^\s*([A-Za-z_][A-Za-z0-9_]*)\s+(\**)(([A-Za-z_][A-Za-z0-9_]*|\:\:)+)\s*\((.*)$/) {
		my $return_type = $1;
		my $return_type_pointer_stars = $2;
		my $fname = $3;
		my $arguments = $5;
		if ((not(exists $blacklisted_functions{$fname})) &&
			($bibliographic_data{"Namespaces"} eq "On")) {
			if ($stars_in_comment ne "") {
				inweb_error("with Namespaces on, $fname should not be marked /*...*/");
			}
			if (($fname =~ m/::/) && ($stars_in_comment eq "")) {
				$stars_in_comment = "***";
			}
		}
		$fname =~ s/::/__/g;
		if ((exists $base_types{$return_type}) &&
			(not(exists $blacklisted_functions{$fname}))) {
			
 { 
#line 461 "Chapter 2/Identifiers.w"
	if ($return_type_pointer_stars ne "") {
		$return_type .= " ".$return_type_pointer_stars;
	}
	if ($type_qualifiers ne "") {
		$return_type = $type_qualifiers." ".$return_type;
	}

 } 
#line 453 "Chapter 2/Identifiers.w"
;
			
 { 
#line 474 "Chapter 2/Identifiers.w"
	$functions_line{$fname} = $i;
	$functions_return_type{$fname} = $return_type;
	$functions_declared_scope{$fname} = $stars_in_comment;

	my $idash;
	for ($idash = $i+1;
		(($idash<$no_lines) && ($idash-$i<10));
		$idash++) {
		$arguments .= ' '.$line_text[$idash];
	}
	if ($arguments =~ m/^(.*?)\)\s+\{/) {
		$functions_arglist{$fname} = $1;
	} else {
		inweb_error("unable to find spec: $fname (args: '$arguments')");
	}

 } 
#line 454 "Chapter 2/Identifiers.w"
;
		}
	}

 } 
#line 416 "Chapter 2/Identifiers.w"
;
	}
}

#line 496 "Chapter 2/Identifiers.w"
sub scan_identifiers_in_source {
	my $i;
	for ($i=0; $i<$no_lines; $i++) {
		if (($line_category[$i] == $CODE_BODY_LCAT)
			|| ($line_category[$i] == $BEGIN_DEFINITION_LCAT)
			|| ($line_category[$i] == $CONT_DEFINITION_LCAT)) {
			my $current_section_leafname = $section_leafname[$line_sec[$i]];
			my $current_section_number = $line_sec[$i];
			my $look_for_identifiers = $line_text[$i];

			if ($section_sigil[$line_sec[$i]] =~ m/^[A-O]/) { next; }

			
 { 
#line 533 "Chapter 2/Identifiers.w"
	$look_for_identifiers =~ s/\/\*(.*?)\*\///g;

 } 
#line 508 "Chapter 2/Identifiers.w"
;

			if ($web_language == $C_FOR_INFORM_LANGUAGE)
				
 { 
#line 599 "Chapter 2/Identifiers.w"
	if ($look_for_identifiers =~ m/CREATE\((.*?)\)/) {
		if ($1 ne "type_name") {
			if ((exists ($structure_CREATE_in_section{$1})) &&
				($structure_CREATE_in_section{$1} ne $section_leafname[$line_sec[$i]])) {
				add_error_to_section($current_section_number,
					"Use of CREATE($1) in multiple sections");
			}
			$structure_CREATE_in_section{$1} = $section_leafname[$line_sec[$i]];
		}
	}
	while ($look_for_identifiers =~ m/^(.*?)ALLOW_([A-Z]+)\(([A-Za-z_0-9:_]*)\)(.*)$/) {
		$identifier = $3;
		$metalanguage_type = $2;
		$look_for_identifiers = $1.$4;
		$identifier =~ s/::/__/g;
		if (($metalanguage_type eq "CALL") ||
			($metalanguage_type eq "CALLV")) {
			$dot_i6_identifiers{$identifier} = 1;
		}
		if ($metalanguage_type eq "ARRAY") {
			$dot_i6_identifiers{$identifier."_array"} = 1;
		}
		if ($metalanguage_type eq "ROUTINE") {
			$dot_i6_identifiers{$identifier."_routine"} = 1;
		}
	}

 } 
#line 511 "Chapter 2/Identifiers.w"
;

			
 { 
#line 538 "Chapter 2/Identifiers.w"
	while ($look_for_identifiers =~ m/^(.*?)\.([A-Za-z_][A-Za-z0-9_]*)(.*?)$/) {
		$look_for_identifiers = $1.$3;
		note_usage_of_structure_member($2, $i);
	}

 } 
#line 513 "Chapter 2/Identifiers.w"
;
			
 { 
#line 546 "Chapter 2/Identifiers.w"
	while ($look_for_identifiers =~ m/^(.*?)\-\>([A-Za-z_][A-Za-z0-9_]*)(.*?)$/) {
		$look_for_identifiers = $1.$3;
		note_usage_of_structure_member($2, $i);
	}

 } 
#line 514 "Chapter 2/Identifiers.w"
;

			while ($look_for_identifiers =~ m/^.*?([A-Za-z_]([A-Za-z0-9_]|::)*)(.*?)$/) {
				$identifier = $1;
				$look_for_identifiers = $3;
				$identifier =~ s/::/__/g;
				
 { 
#line 556 "Chapter 2/Identifiers.w"
	if (exists $functions_line{$identifier}) {
		if ($debug_identifier_detection == 1) { print STDERR "ID: ", $identifier, "\n"; }
		if ($identifier eq "main") { next; } # which of course isn't called in the web
		my $section_defining_function =
			$section_leafname[$line_sec[$functions_line{$identifier}]];
		$functions_usage_count{$identifier}++;
		$function_usage_hash{$identifier.'+'.$section_chap[$line_sec[$i]]} ++;
		if ($current_section_leafname ne $section_defining_function) {
			$functions_usage_section_list{$identifier} .=
				":".$section_chap[$line_sec[$i]]."-".$current_section_leafname;
			$functions_usage_concisely_described{$identifier} .=
				":".$current_section_number;
			$functions_usage_verbosely_described{$identifier} .=
				language_comment("called by Chapter ".
					$section_chap[$line_sec[$i]]."/".$current_section_leafname.
					" line ".$line_source_file_line[$i]);
		}
		if ($debug_identifier_detection == 1) {
			print STDERR "Added fn to code area $section_chap[$line_sec[$i]]\n";
		}
	}

 } 
#line 520 "Chapter 2/Identifiers.w"
;
			}
		}
	}
}

#line 630 "Chapter 2/Identifiers.w"
sub note_usage_of_structure_member {
	my $member_name = $_[0];
	my $line_number = $_[1];
	my $found_in = "-".$section_leafname[$line_sec[$line_number]].":";
	if ($member_usage_section_list{$member_name} =~ m/$found_in/) { return; }
	$member_usage_section_list{$member_name} .= $found_in;
}

#line 645 "Chapter 2/Identifiers.w"
sub find_actual_section_usage {
	my $sn;
	for ($sn=0; $sn<$no_sections; $sn++) {
		my %usages = ();
		
 { 
#line 736 "Chapter 2/Identifiers.w"
	my $a = $section_I6_template_identifiers[$sn];
	while ($a =~ m/^(.*?)\:(.*)$/) {
		$a = $2;
		if (not(exists $dot_i6_identifiers{$1})) {
			add_error_to_section($sn, "Bad scope: $1 isn't a {-} command as claimed");
		}
		if ($section_leafname[$line_sec[$functions_line{$1}]] ne $section_leafname[$sn]) {
			add_error_to_section($sn, "Bad scope: $1 isn't defined in this section");
		}
	}

 } 
#line 649 "Chapter 2/Identifiers.w"
;
		foreach $f (sort keys %functions_line) {
			if ($section_leafname[$line_sec[$functions_line{$f}]] eq $section_leafname[$sn]) {
				
 { 
#line 672 "Chapter 2/Identifiers.w"
	my $owning_chapter = $section_chap[$line_sec[$functions_line{$f}]];
	my $cp = $functions_usage_section_list{$f};
	$cp =~ s/\:$owning_chapter\-//g;

	my $actual_scope = "";
	if ($functions_usage_section_list{$f} ne "") { $actual_scope = "**"; }
	if ($f eq "main") { $actual_scope = "*****"; }
	elsif (exists $dot_i6_identifiers{$f}) {
		$actual_scope = "****";
		check_section_declares_template_I6($sn, $f);
	} elsif ($cp =~ m/\:\d+\-/) { $actual_scope = "***"; }
	check_function_declared_correct_scope($sn, $f, $actual_scope);

	$cp = $functions_usage_section_list{$f};
	while ($cp =~ m/^(\:\d+\-[^:]*)(.*)$/) {
		$usages{$1}++;
		$cp = $2;
	}

 } 
#line 652 "Chapter 2/Identifiers.w"
;
			}
		}
		if ($section_declared_a_service[$sn] == 1) { %usages = (); }
		
 { 
#line 697 "Chapter 2/Identifiers.w"
	$section_correct_used_by_block[$sn] = "";
	foreach $u (sort keys %usages) {
		$section_correct_used_by_block[$sn] .= $u;
	}
	$section_correct_used_by_block[$sn] .= ":";

 } 
#line 656 "Chapter 2/Identifiers.w"
;
	}

	for ($sn=0; $sn<$no_sections; $sn++)
		
 { 
#line 711 "Chapter 2/Identifiers.w"
	$section_correct_uses_block[$sn] = "";
	my $j;
	for ($j=0; $j<$no_sections; $j++) {
		if ($section_correct_used_by_block[$j] =~ m/\-$section_leafname[$sn]\:/) {
			if ($section_declared_a_service[$j] != 1) {
				$section_correct_uses_block[$sn]
					.= ":".$section_chap[$j]."-".$section_leafname[$j];
			}
		}
	}

 } 
#line 660 "Chapter 2/Identifiers.w"
;

	for ($sn=0; $sn<$no_sections; $sn++)
		
 { 
#line 725 "Chapter 2/Identifiers.w"
	$section_correct_used_by_block[$sn] =~ s/\:$//;
	$section_correct_used_by_block[$sn] =
		section_list_sort($section_correct_used_by_block[$sn]);
	$section_correct_uses_block[$sn] =
		section_list_sort($section_correct_uses_block[$sn]);

 } 
#line 663 "Chapter 2/Identifiers.w"
;
}

#line 763 "Chapter 2/Identifiers.w"
sub find_structure_ownership {
	my $struc;
	foreach $struc (keys %structures) {
		if (exists $structure_CREATE_in_section{$struc}) {
			$structure_owner{$struc} = $structure_CREATE_in_section{$struc};
		} elsif (exists $structure_declared_owner{$struc}) {
			$structure_owner{$struc} =
				$structure_declared_owner{$struc};
		} else {
			$structure_owner{$struc} =
				$section_leafname[$line_sec[$structure_declaration_line{$struc}]];
		}
	}
}

#line 782 "Chapter 2/Identifiers.w"
sub establish_structure_usage {
	my $member;
	
 { 
#line 811 "Chapter 2/Identifiers.w"
	if ($analyse_structure_setting ne "") {
		if (not(exists($structures{$analyse_structure_setting}))) {
			inweb_fatal_error("no such structure: ".$analyse_structure_setting);
		}
		print "The structure $analyse_structure_setting is owned by ",
			$structure_owner{$analyse_structure_setting}, "\n";
		print "Members of the structure used from other sections are as follows:\n";
	}

 } 
#line 784 "Chapter 2/Identifiers.w"
;
	foreach $member (sort keys %member_structures) {
		if (exists $member_usage_section_list{$member}) {
			my $msul = $member_usage_section_list{$member};
			while ($msul =~ m/^\-(.*?)\:(.*)$/) {
				my $observed_in = $1; $msul = $2;
				my $owners = $member_structures{$member};
				while ($owners =~ m/^(.*?)\:(.*)$/) {
					my $owner = $1; $owners = $2;
					my $susl_chunk = "-".$observed_in.":";
					
 { 
#line 824 "Chapter 2/Identifiers.w"
	if (($analyse_structure_setting ne "") &&
		($analyse_structure_setting eq $owner)) {
		if ($observed_in ne $structure_owner{$owner}) {
			inweb_error($member.": Chapter ".
				$section_chap[$section_number_from_leafname{$observed_in}].
				"/".$observed_in);
		}
	}

 } 
#line 794 "Chapter 2/Identifiers.w"
;
					if (not ($structure_usage_section_list{$owner} =~ m/$susl_chunk/)) {
						$structure_usage_section_list{$owner} .= $susl_chunk;
					}
				}
			}
		} else {
			member_declared_but_not_used($member);
		}
	}
	
 { 
#line 837 "Chapter 2/Identifiers.w"
	my $sec_number;
	for ($sec_number=0; $sec_number<$no_sections; $sec_number++) {
		my $declaration = "";
		my $struc;
		foreach $struc (sort keys %structures) {
			if ($structure_owner{$struc} eq $section_leafname[$sec_number]) {
				my $structure_billing = "";
				
 { 
#line 857 "Chapter 2/Identifiers.w"
	my %usage_list = ();
	my %shorter_usage_list = ();
	my $structure_used_externally = 0;
	my $deviant_ownership_note = "";
	if ($section_leafname[$line_sec[$structure_declaration_line{$struc}]]
		ne $structure_owner{$struc}) {
		$deviant_ownership_note =
			": typedef in $section_leafname[$line_sec[$structure_declaration_line{$struc}]]";
	}

	
 { 
#line 883 "Chapter 2/Identifiers.w"
	my $susl = $structure_usage_section_list{$struc};
	while ($susl =~ m/^\-(.*?)\:(.*)$/) {
		my $client_section = $1; $susl = $2;
		if ($client_section ne $section_leafname[$sec_number]) {
			$structure_sharings++;
			$structure_used_externally = 1;
			$usage_list{sprintf("%05d", $section_number_from_leafname{$client_section})}
				.= "   !- shared with Chapter ".
				$section_chap[$section_number_from_leafname{$client_section}].
				"/".$client_section."\n";
			$shorter_usage_list{sprintf("%05d", $section_number_from_leafname{$client_section})}
				.= $section_sigil[$section_number_from_leafname{$client_section}];
		}
	}

 } 
#line 867 "Chapter 2/Identifiers.w"
;
	if ($structure_used_externally == 0) {
		$structure_billing = "-- Owns struct $struc (private$deviant_ownership_note)\n";
		$private_structures++;
	} else {
		$structure_billing = "-- Owns struct $struc (public$deviant_ownership_note)\n";
		$shared_structures++;
		foreach $k (sort keys %usage_list) {
			$structure_billing .= $usage_list{$k};
			$structure_ownership_summary{$struc} .= $shorter_usage_list{$k} . " ";
		}
	}

 } 
#line 844 "Chapter 2/Identifiers.w"
;
				$declaration .= $structure_billing;
			}
		}
		$section_correct_structures_block[$sec_number] = $declaration;
	}

 } 
#line 804 "Chapter 2/Identifiers.w"
;
}

#line 903 "Chapter 2/Identifiers.w"
sub section_list_sort {
	my $list = $_[0];
	my %lines_unpacked = ();
	my $this_line;
	my $account = "";
	while ($list =~ m/^\:(\d+)\-([^:]*)(.*)$/) {
		$this_line = $prefix. "Chapter ". $1. "/". $2. "\n";
		$lines_unpacked{sprintf("%04d", $section_number_from_leafname{$2})} = ":".$1."-".$2;
		$list = $3;
	}
	foreach $this_line (sort keys %lines_unpacked) {
		$account .= $lines_unpacked{$this_line};
	}
	return $account;
}

#line 923 "Chapter 2/Identifiers.w"
sub section_list_unpack {
	my $prefix = $_[0];
	my $list = $_[1];
	my %lines_unpacked = ();
	my $this_line;
	my $account = "";
	while ($list =~ m/^\:(\d+)\-([^:]*)(.*)$/) {
		$this_line = $prefix. "Chapter ". $1. "/". $2. "\n";
		$lines_unpacked{sprintf("%04d", $section_number_from_leafname{$2})} = $this_line;
		$list = $3;
	}
	foreach $this_line (sort keys %lines_unpacked) {
		$account .= $lines_unpacked{$this_line};
	}
	return $account;
}

#line 943 "Chapter 2/Identifiers.w"
sub check_interface_declarations_for_uses_and_used_by {
	my $sn;
	if ($bibliographic_data{"Strict Usage Rules"} eq "Off") { return; }
	if ($bibliographic_data{"Declare Section Usage"} eq "Off") { return; }
	for ($sn=0; $sn<$no_sections; $sn++) {
		if ($section_declared_used_by_block[$sn] ne
			$section_correct_used_by_block[$sn]) {
			$em = "Interface error:\n"
				.section_list_unpack(
					"%    Says used by ", $section_declared_used_by_block[$sn])
				.section_list_unpack(
					"-- Used by ", $section_correct_used_by_block[$sn]);
			add_error_to_section($sn, $em);
		}
		if ($section_declared_uses_block[$sn] ne
			$section_correct_uses_block[$sn]) {
			$em = "Interface error:\n"
				.section_list_unpack(
					"%    Says uses ", $section_declared_uses_block[$sn])
				.section_list_unpack(
					"-- Uses ", $section_correct_uses_block[$sn]);
			add_error_to_section($sn, $em);
		}
	}
}

#line 972 "Chapter 2/Identifiers.w"
sub check_interface_declarations_for_structures {
	my $sn;
	for ($sn=0; $sn<$no_sections; $sn++) {
		if ($section_declared_structure_interface[$sn] ne
			$section_correct_structures_block[$sn]) {
			add_error_to_section($sn,
				"Incorrect structure billing: should be...\n".
				$section_correct_structures_block[$sn].
				"...and not...\n".
				$section_declared_structure_interface[$sn]);
		}
	}
}

#line 990 "Chapter 2/Identifiers.w"
sub check_function_declared_correct_scope {
	my $sn = $_[0];
	my $f = $_[1];
	my $actual_scope = $_[2];
	if ($bibliographic_data{"Namespaces"} eq "On") {
		if ($f ne "main") {
			if (($actual_scope ne "") && ($functions_declared_scope{$f} eq "")) {
				add_error_to_section($sn,
					"Begin externally called, function $f should belong to a :: namespace");
				return;
			}
			if (($actual_scope eq "") && ($functions_declared_scope{$f} ne "")) {
				add_error_to_section($sn,
					"Begin internally called, function $f must not belong to a :: namespace");
				return;
			}
		}
		$functions_declared_scope{$f} = $actual_scope;
		return;
	}
	if ($bibliographic_data{"Strict Usage Rules"} eq "Off") { return; }
	if ($actual_scope ne $functions_declared_scope{$f}) {
		add_error_to_section($sn,
			"Bad scope: $f should be /".$actual_scope."/ not /".
				$functions_declared_scope{$f}."/");
	}
	if ($f =~ m/^([A-Z].*__)(.*?)$/) {
		my $declared = $1;
		my $within = $section_namespace[$sn];
		$within =~ s/::/__/g;
		if ($within eq "") {
			$fcc = restore_quadpoint($f);
			add_error_to_section($sn,
				"Bad scope: $fcc declared outside of any namespace");
		} elsif (not ($declared =~ m/^$within/)) {
			$fcc = restore_quadpoint($f); $wcc = restore_quadpoint($within);
			add_error_to_section($sn,
				"Bad scope: $fcc not allowed inside the section's namespace $wcc");
		}
	}
}

sub restore_quadpoint {
	my $f = $_[0];
	$f =~ s/__/::/g;
	return $f;
}

#line 1042 "Chapter 2/Identifiers.w"
sub check_section_declares_template_I6 {
	my $sn = $_[0];
	my $f = $_[1];
	if ($bibliographic_data{"Strict Usage Rules"} eq "Off") { return; }
	# $f =~ s/__/::/g;
	if (not ($section_I6_template_identifiers[$sn] =~ m/$f/)) {
		add_error_to_section($sn,
			"Bad scope: $f isn't declared:\n-- Defines {-callv:".$f."}\n");
	}
}

#line 1059 "Chapter 2/Identifiers.w"
sub member_declared_but_not_used {
	my $member = $_[0];
	if ($bibliographic_data{"Strict Usage Rules"} eq "Off") { return; }
	if (exists($members_allowed_to_be_unused{$member})) { return; }
	inweb_error("structure(s) '".$member_structures{$member}."' has or have member '".
		$member."' declared but not used");
}

#line 1073 "Chapter 2/Identifiers.w"
sub check_uniqueness_of_structure_members {
	my $member;
	if ($bibliographic_data{"Strict Usage Rules"} eq "Off") { return; }
	foreach $member (sort keys %member_structures) {
		my $owner_count = 0;
		my $x = $member_structures{$member};
		while ($x =~ m/^(.*?)\:(.*)$/) { $x = $2; $owner_count++; }
		if ($owner_count > 1) {
			inweb_error("element '".$member."' belongs to multiple structures: ".
				$member_structures{$member});
		}
	}
}

#line 1091 "Chapter 2/Identifiers.w"
sub add_error_to_section {
	my $section_number = $_[0];
	my $error_text = $_[1];
	if ($error_text eq "") { print "*** Bad error text ***\n"; exit(1); }
	$section_errors[$section_number] .= $error_text."\n";
}

#line 1101 "Chapter 2/Identifiers.w"
sub report_any_interface_errors_found {
	my $infractions = 0;
	my $sn;
	for ($sn=0; $sn<$no_sections; $sn++) {
		if ($section_errors[$sn] ne "") {
			inweb_error("interface errors on $section_sigil[$sn] ($section_leafname[$sn])");
			print STDERR $section_errors[$sn];
			$infractions++;
		}
	}
	if ($infractions > 0) { inweb_fatal_error("halting because of section errors"); }
}

#line 14 "Chapter 3/The Analyser.w"
sub compile_graphs {
	my $sigil = $_[0];
	if ($sigil eq "0") {
		my $ch;
		for ($ch=0; $ch<$no_chapters; $ch++) { compile_graph($ch); }
	} elsif ($sigil =~ m/^\d+$/) {
		compile_graph(eval($sigil));
	} else {
		inweb_fatal_error("can't compile dependency graph(s) for target $sigil");
	}
	print "Dot files written\n";
}

#line 31 "Chapter 3/The Analyser.w"
sub compile_graph {
	my $ch = $_[0];
	my $dotfile = compile_chapter_graph($ch);
	my $pngfile = pathname_to_png_of_dot_file($ch);
	if ($convert_graphs_switch == 1) {
		system($dot_utility_path." -Tpng \"".$dotfile."\" -o \"".$pngfile."\"");
	}
}

#line 48 "Chapter 3/The Analyser.w"
sub pathname_to_dot_file {
	my $cn = $_[0];
	return $web_setting."Tangled/Chapter-".$cn."-Dependencies.dot";
}

sub pathname_to_png_of_dot_file {
	my $cn = $_[0];
	return $web_setting."Figures/Chapter-".$cn."-Dependencies.png";
}

#line 62 "Chapter 3/The Analyser.w"
sub compile_chapter_graph {
	my $cn = $_[0];
	my $i;

	$dotname = pathname_to_dot_file($cn);
	open DOTFILE, ">".$dotname or die "Can't open dot file $dotname for output";
	
 { 
#line 79 "Chapter 3/The Analyser.w"
	print DOTFILE "digraph L0 {\n";
	print DOTFILE "    size = \"8,8\";\n";
	print DOTFILE "    ordering = out;\n";
	print DOTFILE "    compound = true;\n";
	print DOTFILE "    node [shape = box];\n";

 } 
#line 68 "Chapter 3/The Analyser.w"
;
	
 { 
#line 94 "Chapter 3/The Analyser.w"
	my $i;
	$current_class = -1; $i6_controller = -1;
	for ($i=0; $i<$no_sections; $i++) {
		if ($section_chap[$i] != $cn) { next; }
		
 { 
#line 111 "Chapter 3/The Analyser.w"
	$caption = $section_sigil[$i];
	if ($caption eq "14/meta") { $i6_controller = $i; }
	if ($section_sigil[$i] ne "") { $caption = $section_sigil[$i]; }
	if ($current_class != $equivalence_class[$i]) {
		if ($current_class >= 0) { print DOTFILE "}\n"; }
		$current_class = $equivalence_class[$i];
		print DOTFILE "subgraph cluster", $cn, " {\n";
		print DOTFILE "label=\"Chapter ", $cn, "\";\n";
	}
	print DOTFILE "    n", $i, " [label=\"", $caption, "\"];\n";
	if (($section_I6_template_identifiers[$line_sec[$i]] ne "") ||
		($i6_controller == $i)) {
		$section_I6_template_identifiers[$line_sec[$i]] = "";
		if ($i6_controller != $i) { $dot_i6_calls{$i} = "i6"; }
	}

 } 
#line 98 "Chapter 3/The Analyser.w"
;
	}
	
 { 
#line 184 "Chapter 3/The Analyser.w"
	print DOTFILE "    i6 [shape=circle] [color=orchid] [label=\".i6\"];\n";

 } 
#line 100 "Chapter 3/The Analyser.w"
;
	if ($current_class >= 0) { print DOTFILE "}\n"; }

 } 
#line 69 "Chapter 3/The Analyser.w"
;
	
 { 
#line 130 "Chapter 3/The Analyser.w"
	my $i;
	for ($i=0; $i<$no_sections; $i++) {
		if ($section_chap[$i] != $cn) { next; }
		
 { 
#line 139 "Chapter 3/The Analyser.w"
	my $x = $section_correct_uses_block[$i];
	my $no_outbound_calls = 0;
	while ($x =~ m/^\:(.*?)\-(.*?\.w)(.*)$/) {
		$x = $3;
		$to_section = $section_number_from_leafname{$2};
		$from_chapter = $section_chap[$i];
		$to_chapter = $section_chap[$to_section];
		if ($from_chapter == $to_chapter) {
			$uses_this[$no_outbound_calls] = $to_section;
			$uses_this_section[$no_outbound_calls] = 1;
			$no_outbound_calls++;
		} else {
			$uses_this[$no_outbound_calls] = $to_chapter;
			$uses_this_section[$no_outbound_calls] = 0;
			$no_outbound_calls++;
		}
	}
	
 { 
#line 163 "Chapter 3/The Analyser.w"
	if ($no_outbound_calls > 0) {
		print DOTFILE "    n", $i, " -> ";
	}
	if ($no_outbound_calls > 1) {
		print DOTFILE "{ ";
	}
	for ($z=0; $z<$no_outbound_calls; $z++) {
		if ($uses_this_section[$z] == 1) {
			print DOTFILE "n", $uses_this[$z], " ";
		}
	}
	if ($no_outbound_calls > 1) {
		print DOTFILE "} ";
	}
	if ($no_outbound_calls > 0) {
		print DOTFILE "\n";
	}

 } 
#line 156 "Chapter 3/The Analyser.w"
;
	
 { 
#line 190 "Chapter 3/The Analyser.w"
	if ($dot_i6_calls{$i} ne "") {
		print DOTFILE "    ", $dot_i6_calls{$i}, " -> n", $i, " [color=orchid];\n";
	}

 } 
#line 157 "Chapter 3/The Analyser.w"
;

 } 
#line 133 "Chapter 3/The Analyser.w"
;
	}

 } 
#line 70 "Chapter 3/The Analyser.w"
;
	
 { 
#line 88 "Chapter 3/The Analyser.w"
	print DOTFILE "}\n";

 } 
#line 71 "Chapter 3/The Analyser.w"
;
	close DOTFILE;
	return $dotname;
}

#line 210 "Chapter 3/The Analyser.w"
sub catalogue_the_sections {
	my $sigil = $_[0];
	my $functions_too = $_[1];
	my $only = -1;
	my $cn = -1;

	if ($sigil eq "0") { $only = -1; }
	elsif ($sigil =~ m/^\d+$/) { $only = eval($sigil); }
	else { inweb_fatal_error("can't catalogue target $sigil"); }

	for ($i=0; $i<$no_sections; $i++) {
		if (($only != -1) && ($only != $section_chap[$i])) { next; }
		
 { 
#line 232 "Chapter 3/The Analyser.w"
	if ($cn != $section_chap[$i]) {
		if ($cn >= 0) { print sprintf("      %-9s  %-50s  \n", "--------", "--------"); }
		$cn = $section_chap[$i];
	}

 } 
#line 222 "Chapter 3/The Analyser.w"
;
		
 { 
#line 240 "Chapter 3/The Analyser.w"
	if ($cn != 0) { $main_title = "Chapter ".$cn."/"; }
	else { $main_title = ""; }
	$main_title .= $section_leafname[$i];

	print sprintf("%4d  %-9s  %-50s  ",
		$section_extent[$i], $section_sigil[$i], $main_title);

	if ($functions_too == 1) {
		print $section_namespace[$i];
	} else {
		print $section_namespace[$i], " ";

		if ($functions_usage_count{"compare_word"} > 0) {
			print sprintf("CW:%3d   ", $functions_usage_count{"compare_word"});
		}

		foreach $struc (sort keys %structures) {
			if ($structure_owner{$struc} eq $section_leafname[$i]) {
				print $struc, "  ";
			}
		}
	}
	print "\n";

 } 
#line 223 "Chapter 3/The Analyser.w"
;
		if ($functions_too == 1) 
 { 
#line 279 "Chapter 3/The Analyser.w"
	foreach $f (sort keys %functions_line) {
		if ($f =~ m/__/) {
			if ($section_leafname[$line_sec[$functions_line{$f}]] eq $section_leafname[$i]) {
				$f =~ s/__/::/g;
				print sprintf("      %-9s  %-50s -> \n", "", $f);
			}
		}
	}

 } 
#line 225 "Chapter 3/The Analyser.w"
		else 
 { 
#line 267 "Chapter 3/The Analyser.w"
	foreach $struc (sort keys %structures) {
		if ($structure_owner{$struc} eq $section_leafname[$i]) {
			if ($structure_ownership_summary{$struc} ne "") {
				print sprintf("      %-9s  %-50s  ", "", "");
				print $struc, ": ", $structure_ownership_summary{$struc}, "\n";
			}
		}
	}

 } 
#line 225 "Chapter 3/The Analyser.w"
;
	}
}

#line 295 "Chapter 3/The Analyser.w"
sub catalogue_void_pointers {
	my $sigil = $_[0];
	if ($sigil ne "0") { inweb_fatal_error("can't catalogue voids for target $sigil"); }

	my $el;
	foreach $el (sort keys %member_types) {
		if ($member_types{$el} =~ m/ void\*/) {
			print $el, " in ", $member_structures{$el}, ": ", $member_types{$el}, "\n";
		}
	}
}
#line 22 "Chapter 3/The Swarm.w"
sub weave_swarm {
	my $i;
	for ($i=0; $i < $no_sections; $i++) { $section_weave_number[$j] = -1; }
	for ($i=0; $i < $no_chapters; $i++) { $chapter_weave_number[$j] = -1; }

	if ($swarm_mode >= $SWARM_SECTIONS) {
		for ($i=0; $i < $no_sections; $i++) {
			if (($only_setting eq "") || ($section_sigil[$i] =~ m/^$only_setting\//)) {
				$section_weave_number[$i] = weave_sigil($section_sigil[$i], 0);
			}
		}
	}
	if (($web_is_chaptered == 1) && ($swarm_mode >= $SWARM_CHAPTERS)) {
		for ($i=0; $i < $no_chapters; $i++) {
			if ($only_setting ne "") {
				if ($chapter_sigil[$i] ne $only_setting) { next; }
			}
			$chapter_weave_number[$i] = weave_sigil($chapter_sigil[$i], 0);
			if ($only_setting ne "") {
				$complete_web_weave_number = $chapter_weave_number[$i];
				$complete_PDF_leafname = $chapter_woven_pdf_leafname[$i];
			}
		}
	}
	if (($swarm_mode >= $SWARM_CHAPTERS) && ($only_setting eq "")) {
		$complete_web_weave_number = weave_sigil("0", 0);
	}
	weave_index_templates();
}

#line 56 "Chapter 3/The Swarm.w"
sub weave_index_templates {
	
 { 
#line 64 "Chapter 3/The Swarm.w"
	my $temp_list;
	my $leaf = "";
	if (exists ($bibliographic_data{"Index Template"})) {
		$temp_list = $bibliographic_data{"Index Template"};
	} else {
		if ($web_is_chaptered == 1) {
			$temp_list = $path_to_inweb_setting.'inweb/Materials/chaptered-index.html';
		} else {
			$temp_list = $path_to_inweb_setting.'inweb/Materials/unchaptered-index.html';
		}
		$leaf = "index.html";
	}
	while ($temp_list ne "") {
		my $this_temp;
		if ($temp_list =~ m/^(.*?)\s*\,\s*(.*)$/) {
			$temp_list = $2; $this_temp = $1;
		} else {
			$this_temp = $temp_list; $temp_list = "";
		}
		if ($leaf eq "") {
			$leaf = $this_temp;
			if ($leaf =~ m/^.*\/(.*?)$/) { $leaf = $1; }
		}
		print "Weaving index file: Woven/$leaf\n";
		weave_contents_from_template($this_temp, $leaf);
		$leaf = "";
	}

 } 
#line 57 "Chapter 3/The Swarm.w"
;
	
 { 
#line 96 "Chapter 3/The Swarm.w"
	my $copy_list = $path_to_inweb_setting.'inweb/Materials/download.gif'.
		', '.$path_to_inweb_setting.'inweb/Materials/lemons.jpg';
	if (exists ($bibliographic_data{"Index Extras"})) {
		$temp_list = $bibliographic_data{"Index Extras"};
	}
	my $path_to_copy_binaries = $web_setting."Woven";
	while ($copy_list ne "") {
		my $this_file;
		if ($copy_list =~ m/^(.*?)\s*\,\s*(.*)$/) {
			$copy_list = $2; $this_file = $1;
		} else {
			$this_file = $copy_list; $copy_list = "";
		}
		my $leaf = $this_file;
		if ($leaf =~ m/^.*\/(.*?)$/) { $leaf = $1; }
		print "Copying additional index file: Woven/$leaf\n";
		system("cp '".$this_file."' '".$path_to_copy_binaries."'");
	}

 } 
#line 58 "Chapter 3/The Swarm.w"
;
}

#line 120 "Chapter 3/The Swarm.w"
sub weave_sigil {
	my $request = $_[0]; # The sigil of the target to be weaved
	my $open_afterwards = $_[1]; # Open the PDF in the host OS's viewer
	my $cover_sheet_flag = 0; # Shall we have one?
	my $weave_section_match = ''; # Reg exp for sigil to match
	my $tex_file_leafname; # What to call the resulting \TeX\ file

	my $path_to_loom = $web_setting."Woven/";

	
 { 
#line 151 "Chapter 3/The Swarm.w"
	if ($request eq "0") {
		$weave_section_match = '.*';
		$booklet_title = "Complete Program";
		$tex_file_leafname = "Complete.tex";
		$cover_sheet_flag = 1;
	} elsif ($request =~ m/^\d+$/) {
		my $cn = eval($request);
		$weave_section_match = '^'.$cn.'\/';
		$booklet_title = "Chapter ".$cn;
		$tex_file_leafname = "Chapter-".$cn.".tex";
		$cover_sheet_flag = 1;
	} elsif ($request =~ m/^[A-O]$/) {
		my $cn = eval($request);
		$weave_section_match = '^'.$cn.'\/';
		$booklet_title = "Appendix ".$request;
		$tex_file_leafname = "Appendix-".$request.".tex";
		$cover_sheet_flag = 1;
	} elsif ($request =~ m/^P$/) {
		my $cn = eval($request);
		$weave_section_match = '^'.$cn.'\/';
		$booklet_title = "Preliminaries";
		$tex_file_leafname = "Preliminaries.tex";
		$cover_sheet_flag = 1;
	} elsif ($request =~ m/^(\S+?)\/(\S+)$/) {
		my $cn = eval($request);
		$weave_section_match = '^'.$1.'\/'.$2.'$';
		$booklet_title = $request;
		my $srequest = $request;
		$srequest =~ s/\//-/;
		$tex_file_leafname = $srequest.".tex";
		$cover_sheet_flag = 0;
	} else {
		inweb_fatal_error("unknown weave request: $request");
	}

 } 
#line 129 "Chapter 3/The Swarm.w"
;

	weave_source($path_to_loom.$tex_file_leafname, $cover_sheet_flag, $weave_section_match);
	if ($lines_woven == 0) {
		inweb_fatal_error("empty weave request: $request");
	}
	my $wtn = run_woven_source_through_tex($path_to_loom.$tex_file_leafname,
		$open_afterwards, $cover_sheet_flag, $weave_section_match);
	
 { 
#line 189 "Chapter 3/The Swarm.w"
	print "[", $request, ": ", $page_count[$wtn], "pp ",
		$pdf_size[$wtn]/1024, "K";
	if ($overfull_hbox_count[$wtn] > 0) {
		print ", ", $overfull_hbox_count[$wtn], " overfull hbox(es)";
	}
	if ($tex_error_count[$wtn] > 0) {
		print ", ", $tex_error_count[$wtn], " error(s)";
	}
	print "]\n";

 } 
#line 137 "Chapter 3/The Swarm.w"
;
	return $wtn;
}

#line 215 "Chapter 3/The Swarm.w"
sub run_woven_source_through_tex {
	my $tex_filename = $_[0];
	my $open_PDF = $_[1];
	my $with_cover_sheet = $_[2];
	my $weave_section_match = $_[3];

	my $path_to_tex = "";
	my $tex_leafname = "";
	my $console_filename = "";
	my $console_leafname = "";
	my $log_filename = "";
	my $pdf_filename = "";
	
 { 
#line 242 "Chapter 3/The Swarm.w"
	$tex_leafname = $tex_filename;
	if ($tex_leafname =~ m/^(.*)\/(.*?)$/) { $path_to_tex = $1; $tex_leafname = $2; }
	$console_leafname = $tex_leafname; $console_filename = $tex_filename;
	$console_leafname =~ s/\.tex$/.console/; $console_filename =~ s/\.tex$/.console/;
	$log_filename = $tex_filename; $log_filename =~ s/\.tex$/.log/;
	$pdf_filename = $tex_filename; $pdf_filename =~ s/\.tex$/.pdf/;

 } 
#line 227 "Chapter 3/The Swarm.w"
;

	my $serious_error_count = 0;

	
 { 
#line 252 "Chapter 3/The Swarm.w"
	my $set_cwd = "";
	if ($path_to_tex ne "") { $set_cwd = "cd \"".$path_to_tex."\"; "; }
	$command = $set_cwd.$pdftex_configuration." -interaction=scrollmode \"".$tex_leafname."\" "
		.">\"".$console_leafname."\"";
	system($command);

 } 
#line 231 "Chapter 3/The Swarm.w"
;
	
 { 
#line 263 "Chapter 3/The Swarm.w"
	$overfull_hbox_count[$no_weave_targets] = 0;
	$tex_error_count[$no_weave_targets] = 0;
	$page_count[$no_weave_targets] = 0;
	$pdf_size[$no_weave_targets] = 0;

	open(CONSOLE, $console_filename) or die "no console file?";
	while ($csl = <CONSOLE>) {
		if ($csl =~ m/Output written .*? \((\d+) page.*?(\d+) byte/) {
			$page_count[$no_weave_targets] = eval($1); $pdf_size[$no_weave_targets] = eval($2);
		}
		if ($csl =~ m/verfull \\hbox/) {
			$overfull_hbox_count[$no_weave_targets]++;
		} else {
			if ($csl =~ m/^\!/) {
				$tex_error_count[$no_weave_targets]++;
				$serious_error_count++;
			}
		}
	}
	close (CONSOLE);

 } 
#line 232 "Chapter 3/The Swarm.w"
;
	
 { 
#line 292 "Chapter 3/The Swarm.w"
	if ($serious_error_count == 0) { system("rm \"".$console_filename."\""); }
	system("rm \"".$log_filename."\"");
	system("rm \"".$tex_filename."\"");

 } 
#line 233 "Chapter 3/The Swarm.w"
;

	if ($open_PDF == 1) 
 { 
#line 299 "Chapter 3/The Swarm.w"
	if ($open_command_configuration eq "") {
		inweb_error("no way to open PDF (see configuration file)", $pdf_filename);
	} else {
		system($open_command_configuration." \"".$pdf_filename."\"");
	}

 } 
#line 235 "Chapter 3/The Swarm.w"
;
	return $no_weave_targets++; # Return the weave ID number for this run of \TeX
}

#line 315 "Chapter 3/The Swarm.w"
sub weave_contents_from_template {
	my $path_to_template = $_[0];
	my $contents_page_leafname = $_[1];

	my $no_tlines = 0;
	
 { 
#line 347 "Chapter 3/The Swarm.w"
	if (not(open(TEMPL, $path_to_template))) {
		print "inweb: warning: unable to generate index because can't find template at ",
			$path_to_template, "\n";
		return;
	}
	while ($tl = <TEMPL>) {
		$tlines[$no_tlines++] = $tl;
	}
	close (TEMPL);
	if ($TRACE_CI_EXECUTION == 1) {
		print "Read template <", $path_to_template, ">: ", $no_tlines, " line(s)\n";
	}

 } 
#line 320 "Chapter 3/The Swarm.w"
;
	
 { 
#line 363 "Chapter 3/The Swarm.w"
	my $path_to_contents = $web_setting."Woven/".$contents_page_leafname;
	if (not(open(CONTS, '>'.$path_to_contents))) {
		print "inweb: warning: unable to generate index because can't open to write ",
			$path_to_contents, "\n";
		return;
	}

 } 
#line 321 "Chapter 3/The Swarm.w"
;

	my $lpos = 0; # This is our program counter: a line number in the template
	$stack_pointer = 0; # And this is our stack pointer for tracking of loops
	CYCLE: while ($lpos < $no_tlines) {
		my $tl = $tlines[$lpos++]; # Fetch the line at the program counter and advance
		$tl =~ m/^(.*?)\s*$/; $tl = $1; # Strip trailing spaces
		if ($TRACE_CI_EXECUTION == 1)
			
 { 
#line 373 "Chapter 3/The Swarm.w"
	my $j;
	print sprintf("%04d: %tl\nStack:", $lpos-1, $tl);
	for ($j=0; $j<$stack_pointer; $j++) {
		print " ", $j, ": ", $repeat_stack_variable[$j], "/", $repeat_stack_threshold[$j], " ",
			$repeat_stack_level[$j];
	}
	print "\n";

 } 
#line 329 "Chapter 3/The Swarm.w"
;
		if ($tl =~ m/^\s*\[\[(.*?)\]\]\s*$/) {
			my $command = $1;
			
 { 
#line 386 "Chapter 3/The Swarm.w"
	if ($command =~ m/^Select (.*)$/) {
		my $sigil = $1;
		my $j;
		for ($j = 0; $j<$no_sections; $j++) {
			if ($section_sigil[$j] eq $sigil) {
				start_CI_loop("Section", $j, $j, $lpos);
				next CYCLE;
			}
		}
		for ($j = 0; $j<$no_chapters; $j++) {
			if ($chapter_sigil[$j] eq $sigil) {
				start_CI_loop("Chapter", $j, $j, $lpos);
				next CYCLE;
			}
		}
		inweb_error_at("don't recognise the chapter or section abbreviation $sigil",
			$path_to_template, $lpos);

		next;
	}

 } 
#line 332 "Chapter 3/The Swarm.w"
;
			
 { 
#line 410 "Chapter 3/The Swarm.w"
	if ($command =~ m/^Repeat (Chapter|Section)$/) {
		my $from;
		my $to;
		my $lev = $1;
		if ($lev eq "Chapter") {
			$from = 0;
			$to = $no_chapters-1;
			if ($only_setting) {
				my $j;
				for ($j = 0; $j<$no_chapters; $j++) {
					if ($chapter_sigil[$j] eq $only_setting) {
						start_CI_loop("Chapter", $j, $j, $lpos);
						next CYCLE;
					}
				}
			}
		} elsif ($lev eq "Section") {
			my $within_chapter = heading_topmost_on_stack("Chapter");
			if ($within_chapter == -1) {
				$from = 0;
				$to = $no_sections-1;
			} else {
				$from = -1;
				my $sn;
				for ($sn = 0; $sn < $no_sections; $sn++) {
					if ($section_chap[$sn] == $within_chapter) {
						if ($from == -1) { $from = $sn; }
						$to = $sn;
					}
				}
			}
		} else {
			inweb_error_at("don't know how to repeat $lev: only Chapter or Section",
				$path_to_template, $lpos);
		}
		if ($from >= 0) { start_CI_loop($lev, $from, $to, $lpos); }
		next CYCLE;
	}

 } 
#line 333 "Chapter 3/The Swarm.w"
;
			
 { 
#line 452 "Chapter 3/The Swarm.w"
	if ($command =~ m/^End (Repeat|Select)$/) {
		if ($stack_pointer <= 0) {
			inweb_error_at("stack underflow on contents template", $path_to_template, $lpos);
		}
		$repeat_stack_variable[$stack_pointer-1]++;
		if ($repeat_stack_variable[$stack_pointer-1] >=
			$repeat_stack_threshold[$stack_pointer-1]) {
			end_CI_loop();
		} else {
			$lpos = $repeat_stack_startpos[$stack_pointer-1]; # Back round loop
		}
		next CYCLE;
	}

 } 
#line 334 "Chapter 3/The Swarm.w"
;
			print "Still here, ", $command, "\n";
		}
		
 { 
#line 469 "Chapter 3/The Swarm.w"
	my $rstl;
	for ($rstl = $stack_pointer-1; $rstl >= 0; $rstl--) {
		if ($repeat_stack_variable[$stack_pointer-1] >=
			$repeat_stack_threshold[$stack_pointer-1]) { next CYCLE; }
	}

 } 
#line 337 "Chapter 3/The Swarm.w"
;
		
 { 
#line 514 "Chapter 3/The Swarm.w"
	while ($tl =~ m/^(.*?)\[\[(.*?)\]\](.*?)\s*$/) {
		my $left = $1; my $right = $3; my $subs = $2;
		if (exists($bibliographic_data{$subs})) {
			
 { 
#line 547 "Chapter 3/The Swarm.w"
	$subs = $bibliographic_data{$subs};

 } 
#line 517 "Chapter 3/The Swarm.w"
;
		} elsif ($subs =~ m/^(Chapter|Section|Complete) (.*)$/) {
			my $lev = $1;
			my $detail = $2;
			my $heading_number;
			if ($lev eq "Complete") {
				$heading_number = $complete_web_weave_number;
			} else {
				$heading_number = heading_topmost_on_stack($lev);
				if ($heading_number == -1) {
					inweb_error_at("no $lev is currently selected",
						$path_to_template, $lpos);
				}
			}
			if ($lev eq "Complete") {
				
 { 
#line 552 "Chapter 3/The Swarm.w"
	if ($detail eq "PDF Size") {
		$subs = ($pdf_size[$complete_web_weave_number]/1024)."KB";
	} elsif ($detail eq "Extent") {
		$subs = ($page_count[$complete_web_weave_number])."pp";
	} elsif ($detail eq "Leafname") {
		$subs = $complete_PDF_leafname;
	} else {
		$subs = $detail.' for complete web';
	}

 } 
#line 532 "Chapter 3/The Swarm.w"
;
			} elsif ($lev eq "Chapter") {
				
 { 
#line 568 "Chapter 3/The Swarm.w"
	if ($detail eq "Title") {
		$subs = $chapter_title[$heading_number];
	} elsif ($detail eq "Purpose") {
		$subs = $chapter_rubric[$heading_number];
	} elsif ($detail eq "Leafname") {
		$subs = $chapter_woven_pdf_leafname[$heading_number];
	} elsif ($detail eq "Extent") {
		my $wtn = $chapter_weave_number[$heading_number];
		if ($wtn == -1) { $subs = "--"; } else {
			$subs = $page_count[$wtn]."pp";
		}
	} elsif ($detail eq "PDF Size") {
		my $wtn = $chapter_weave_number[$heading_number];
		if ($wtn == -1) { $subs = "--"; } else {
			$subs = ($pdf_size[$wtn]/1024)."KB";
		}
	} elsif ($detail eq "Errors") {
		my $wtn = $chapter_weave_number[$heading_number];
		if ($wtn == -1) { $subs = ""; } else {
			$subs = "";
			if ($overfull_hbox_count[$wtn] > 0) {
				$subs = $overfull_hbox_count[$wtn]." overfull hbox ";
			}
			if ($tex_error_count[$wtn] > 0) {
				$subs .= $tex_error_count[$wtn]." TeX error";
			}
		}
	} else {
		$subs = $detail.' for '.$lev.' '.$heading_number;
	}

 } 
#line 534 "Chapter 3/The Swarm.w"
;
			} else {
				
 { 
#line 602 "Chapter 3/The Swarm.w"
	if ($detail eq "Title") {
		$subs = $section_leafname[$heading_number];
		$subs =~ s/\.w$//;
	} elsif ($detail eq "Purpose") {
		$subs = $section_purpose[$heading_number];
	} elsif ($detail eq "Leafname") {
		$subs = $section_sigil[$heading_number];
		$subs =~ s/\//-/; $subs = $subs.'.pdf';
	} elsif ($detail eq "Code") {
		$subs = $section_sigil[$heading_number];
	} elsif ($detail eq "Lines") {
		$subs = $section_extent[$heading_number];
	} elsif ($detail eq "Source") {
		$subs = $section_pathname_relative_to_web[$heading_number];
	} elsif ($detail eq "Paragraphs") {
		$subs = $section_no_pars[$heading_number];
	} elsif ($detail eq "Mean") {
		my $denom = $section_no_pars[$heading_number];
		if ($denom == 0) { $denom = 1; }
		$subs = $section_extent[$heading_number]/$denom;
	} elsif ($detail eq "Extent") {
		my $wtn = $section_weave_number[$heading_number];
		if ($wtn == -1) { $subs = "--"; } else {
			$subs = $page_count[$wtn]."pp";
		}
	} elsif ($detail eq "PDF Size") {
		my $wtn = $section_weave_number[$heading_number];
		if ($wtn == -1) { $subs = "--"; } else {
			$subs = ($pdf_size[$wtn]/1024)."KB";
		}
	} elsif ($detail eq "Errors") {
		my $wtn = $section_weave_number[$heading_number];
		if ($wtn == -1) { $subs = ""; } else {
			$subs = "";
			if ($overfull_hbox_count[$wtn] > 0) {
				$subs = $overfull_hbox_count[$wtn]." overfull hbox ";
			}
			if ($tex_error_count[$wtn] > 0) {
				$subs .= $tex_error_count[$wtn]." TeX error";
			}
		}
	} else {
		$subs = $detail.' for '.$lev.' '.$heading_number;
	}
 } 
#line 536 "Chapter 3/The Swarm.w"
;
			}
		} else {
			$subs = '<b>'.$subs.'</b>';
		}
		$tl = $left.$subs.$right;
	}

 } 
#line 338 "Chapter 3/The Swarm.w"
;
		print CONTS $tl, "\n"; # Copy the now finished line to the output
	}
	close (CONTS);
}

#line 479 "Chapter 3/The Swarm.w"
sub heading_topmost_on_stack {
	my $level = $_[0];
	my $rstl;
	for ($rstl = $stack_pointer-1; $rstl >= 0; $rstl--) {
		if ($repeat_stack_level[$rstl] eq $level) {
			return $repeat_stack_variable[$rstl];
		}
	}
	return -1;
}

#line 494 "Chapter 3/The Swarm.w"
sub start_CI_loop {
	my $level = $_[0];
	my $start_point = $_[1];
	my $end_point = $_[2];
	my $first_line_of_body = $_[3];
	$repeat_stack_level[$stack_pointer] = $level;
	$repeat_stack_variable[$stack_pointer] = $start_point;
	$repeat_stack_threshold[$stack_pointer] = $end_point+1;
	$repeat_stack_startpos[$stack_pointer++] = $first_line_of_body;
}
sub end_CI_loop {
	$stack_pointer--;
}

#line 19 "Chapter 3/The Weaver.w"
sub weave_source {
	my $filename = $_[0];
	my $with_cover_sheet = $_[1]; # Should we add a cover sheet at the front?
	my $weave_section_match = $_[2]; # Regular expression which sigils for the lines must match

	open(WEAVEOUT, ">".$filename) or die "inweb: can't open weave file '$filename' for output";
	print WEAVEOUT "% Weave ", $filename, " generated by ", $INWEB_BUILD, "\n";
	
 { 
#line 88 "Chapter 3/The Weaver.w"
	my $ml;
	open(MACROS, $path_to_inweb_setting.'inweb/Materials/inweb-macros.tex')
		or die "inweb: can't open file of TeX macros";
	while ($ml = <MACROS>) {
		$ml =~ m/^(.*)\s*$/; $ml = $1;
		print WEAVEOUT $ml, "\n";
	}
	close MACROS;

 } 
#line 26 "Chapter 3/The Weaver.w"
;
	if ($with_cover_sheet == 1) { weave_cover_sheet(); }

	
 { 
#line 65 "Chapter 3/The Weaver.w"
	$within_TeX_beginlines = 0; # Currently setting copy between |\beginlines| and |\endlines|?
	$weaving_suspended = 0;
	$interface_table_pending = 0;
	$functions_in_par = ""; $structs_in_par = "";
	$current_macro_definition = "";
	$next_heading_without_vertical_skip = 0;
	$show_section_toc_soon = 0; # Is a table of contents for the section imminent?
	$horizontal_rule_just_drawn = 0;
	$chaptermark = ""; $sectionmark = "";

	begin_making_pdf_links(); # Be ready to set PDF hyperlinks from now on

	$lines_woven = 0; # Number of lines in the target to be woven

 } 
#line 29 "Chapter 3/The Weaver.w"
;
	OUTLOOP:
	for ($i=0; $i<$no_lines; $i++) {
		
 { 
#line 102 "Chapter 3/The Weaver.w"
	if ($weave_section_match ne "") {
		if (not ($section_sigil[$line_sec[$i]] =~ m/$weave_section_match/)) { next OUTLOOP; }
	}

 } 
#line 32 "Chapter 3/The Weaver.w"
;
		$lines_woven++; # In principle, then, what remains is in the target; but...
		
 { 
#line 110 "Chapter 3/The Weaver.w"
	if ($line_category[$i] == $TOGGLE_WEAVING_LCAT) {
		if ($weaving_suspended == 0) {
			print WEAVEOUT "\\smallskip\\par\\noindent";
			print WEAVEOUT "{\\ttninepoint\\it ...and so on...}\\smallskip\n";
			$weaving_suspended = 1;
			next OUTLOOP;
		}
		$weaving_suspended = 0;
		next OUTLOOP;
	}
	if ($weaving_suspended == 1) { next OUTLOOP; }

 } 
#line 34 "Chapter 3/The Weaver.w"
;
		
 { 
#line 125 "Chapter 3/The Weaver.w"
	if ($line_category[$i] == $GRAMMAR_LCAT) { next OUTLOOP; }
	if ($line_category[$i] == $GRAMMAR_BODY_LCAT) { next OUTLOOP; }
	if ($line_category[$i] == $INDEX_ENTRY_LCAT) { next OUTLOOP; }

 } 
#line 35 "Chapter 3/The Weaver.w"
;
		
 { 
#line 133 "Chapter 3/The Weaver.w"
	if ($line_category[$i] == $COMMAND_LCAT) {
		my $argument = $line_operand_2[$i];
		if ($line_operand[$i] == $PAGEBREAK_CMD) {
			print WEAVEOUT "\\vfill\\eject\n";
		}
		if ($line_operand[$i] == $BNF_GRAMMAR_CMD) {
			weave_bnf_grammar($argument);
			print WEAVEOUT "\\smallbreak\n";
			print WEAVEOUT "\\hrule\\smallbreak\n";
		}
		if ($line_operand[$i] == $THEMATIC_INDEX_CMD) {
			weave_thematic_index($argument);
			print WEAVEOUT "\\smallbreak\n";
			print WEAVEOUT "\\hrule\\smallbreak\n";
		}
		if ($line_operand[$i] == $FIGURE_CMD) {
			
 { 
#line 163 "Chapter 3/The Weaver.w"
	my $figname = $argument;
	my $width = "";

	if ($figname =~ m/^(\d+)cm\: (.*)$/) {
		$figname = $2;
		$width = " width ".$1."cm";
	}

	print WEAVEOUT "\\pdfximage".$width."{../Figures/".$figname, "}\n";
	print WEAVEOUT "\\smallskip\\noindent",
		"\\hbox to\\hsize{\\hfill\\pdfrefximage \\pdflastximage\\hfill}",
		"\\smallskip\n";

 } 
#line 149 "Chapter 3/The Weaver.w"
;
		}
		# Otherwise assume it was a tangler command, and ignore it here
		next OUTLOOP;
	}

 } 
#line 36 "Chapter 3/The Weaver.w"
;

		# Some of the more baroque front matter of a section...
		
 { 
#line 182 "Chapter 3/The Weaver.w"
	if ($line_category[$i] == $PURPOSE_LCAT) {
		print WEAVEOUT "\\smallskip\\par\\noindent{\\it Purpose}\\smallskip\\noindent\n";
		print WEAVEOUT $line_operand[$i], "\n";
		$show_section_toc_soon = 1;
		$horizontal_rule_just_drawn = 0;
		next OUTLOOP;
	}

 } 
#line 39 "Chapter 3/The Weaver.w"
;
		
 { 
#line 193 "Chapter 3/The Weaver.w"
	if (($show_section_toc_soon == 1) && ($line_text[$i] =~ m/^\s*$/)) {
		print WEAVEOUT "\\medskip";
		$show_section_toc_soon = 0;
		if ($section_toc[$line_sec[$i]] ne "") {
			print WEAVEOUT "\\smallskip\\hrule\\smallskip\\par\\noindent{\\usagefont ",
				$section_toc[$line_sec[$i]], "}\\par\\medskip\\hrule\\bigskip\n";
			$horizontal_rule_just_drawn = 1;
		} else {
			$horizontal_rule_just_drawn = 0;
		}
	}

 } 
#line 40 "Chapter 3/The Weaver.w"
;
		
 { 
#line 211 "Chapter 3/The Weaver.w"
	if ($line_category[$i] == $INTERFACE_LCAT) {
		$interface_table_pending = 1;
		next OUTLOOP;
	}
	if ($line_category[$i] == $INTERFACE_BODY_LCAT) {
		if ($interface_table_pending) {
			$interface_table_pending = 0;
			if ($web_language == $C_FOR_INFORM_LANGUAGE) {
				$horizontal_rule_just_drawn = 0;
				weave_interface_table_for_section($line_sec[$i]);
			}
		}
		next OUTLOOP;
	}

 } 
#line 41 "Chapter 3/The Weaver.w"
;
		
 { 
#line 229 "Chapter 3/The Weaver.w"
	if ($line_category[$i] == $DEFINITIONS_LCAT) {
		print WEAVEOUT "\\smallskip\\par\\noindent{\\it Definitions}\\smallskip\\noindent\n";
		$next_heading_without_vertical_skip = 1;
		$horizontal_rule_just_drawn = 0;
		next OUTLOOP;
	}

 } 
#line 42 "Chapter 3/The Weaver.w"
;
		
 { 
#line 240 "Chapter 3/The Weaver.w"
	if ($line_category[$i] == $BAR_LCAT) {
		
 { 
#line 621 "Chapter 3/The Weaver.w"
	if ($within_TeX_beginlines > 0) {
		print WEAVEOUT '\endlines', "\n"; $within_TeX_beginlines = 0;
	}
	show_endnotes_on_previous_paragraph($functions_in_par, $structs_in_par,
		$current_macro_definition);

 } 
#line 241 "Chapter 3/The Weaver.w"
;
		$functions_in_par = "";
		$structs_in_par = "";
		$current_macro_definition = "";
		$within_TeX_beginlines = 0;
		$next_heading_without_vertical_skip = 1;
		if ($horizontal_rule_just_drawn == 0) {
			print WEAVEOUT "\\par\\medskip\\noindent\\hrule\\medskip\\noindent\n";
		}
		next OUTLOOP;
	}

 } 
#line 43 "Chapter 3/The Weaver.w"
;

		# The crucial junction point between modes...
		
 { 
#line 506 "Chapter 3/The Weaver.w"
	if ($line_category[$i] == $PARAGRAPH_START_LCAT) {
		
 { 
#line 621 "Chapter 3/The Weaver.w"
	if ($within_TeX_beginlines > 0) {
		print WEAVEOUT '\endlines', "\n"; $within_TeX_beginlines = 0;
	}
	show_endnotes_on_previous_paragraph($functions_in_par, $structs_in_par,
		$current_macro_definition);

 } 
#line 507 "Chapter 3/The Weaver.w"
;
		
 { 
#line 556 "Chapter 3/The Weaver.w"
	if ($line_starts_paragraph_on_new_page[$i]) {
		print WEAVEOUT "\\vfill\\eject\n";
	}

 } 
#line 508 "Chapter 3/The Weaver.w"
;

		my $weight = $line_operand[$i];
		my $para_title = $line_operand_2[$i];
		my $new_chap_num = $section_chap[$line_sec[$i]];
		my $secnum = $line_sec[$i];
		my $parnum = $line_paragraph_number[$i];
		my $ornament = $line_paragraph_ornament[$i];

		my $mark = "";
		
 { 
#line 573 "Chapter 3/The Weaver.w"
	if ($weight == 3) { $chaptermark = $para_title; $sectionmark = ""; }
	if ($weight == 2) {
		$sectionmark = $para_title;
		if ($section_sigil[$secnum] ne "") { $chaptermark = $section_sigil[$secnum]; }
		if ($chaptermark ne "") { $sectionmark = " - ".$sectionmark; }
	}

	$mark = $chaptermark.$sectionmark."\\quad\$".$ornament."\$".$parnum;
	if ($DEBUG_MARKING == 1) {
		print "Start par $i: weight $weight, title <$para_title>, ",
			"chap $new_chap_num, sec $secnum, par $parnum, ornament $ornament\n";
		print "Mark: $mark\n";
	}

 } 
#line 518 "Chapter 3/The Weaver.w"
;

		$functions_in_par = "";
		$structs_in_par = "";
		$current_macro_definition = "";

		my $TeX_macro = "";
		
 { 
#line 603 "Chapter 3/The Weaver.w"
	my $j;
	$TeX_macro = "weavesection";
	for ($j=0; $j<$weight; $j++) { $TeX_macro = $TeX_macro."s"; }
	if (($next_heading_without_vertical_skip == 1) && ($weight < 2)) {
		$next_heading_without_vertical_skip = 0;
		$TeX_macro = "ns".$TeX_macro;
	}
	if ($weight == 3) { # a chapter heading: note the inch-high sigil...
		my $brief_title = $para_title;
		$brief_title =~ s/^.*?\: //;
		$para_title = "{\\sinchhigh ".$chapter_sigil[$section_chap[$line_sec[$i]]].
			"}\\quad ".$brief_title;
	}

 } 
#line 525 "Chapter 3/The Weaver.w"
;
		print WEAVEOUT "\\".$TeX_macro, "{", $parnum, "}{", $para_title, "}{",
			$mark, "}{", $ornament, "}{", $section_sigil[$secnum], "}%\n";

		# There's quite likely ordinary text on the line following the paragraph
		# start indication, too, so we need to weave this out:

		if ($line_text[$i] ne "") { print WEAVEOUT $line_text[$i], "\n"; }

		# Chapter headings get a chapter title page, or possibly pages, too:

		if ($weight == 3) {
			my $sigil = $chapter_sigil[$section_chap[$line_sec[$i]]];
			print WEAVEOUT $chapter_rubric{$sigil}, "\\medskip\n";
			my $sn;
			for ($sn=0; $sn<$no_sections; $sn++) {
				if (not($section_sigil[$sn] =~ m/^$sigil\//)) { next; }
				print WEAVEOUT "\\smallskip\\noindent |", $section_sigil[$sn], "|: ",
					"{\\it ", $section_leafname[$sn], "}\\quad\n";
				print WEAVEOUT $section_purpose[$sn];
			}
		}

		# And that completes the new paragraph opening.

		next OUTLOOP;
	}

 } 
#line 46 "Chapter 3/The Weaver.w"
;

		# With all exotica dealt with, we now just have material to weave verbatim...
		my $matter = $line_text[$i];
		if ($line_is_comment[$i] == 1) 
 { 
#line 260 "Chapter 3/The Weaver.w"
	
 { 
#line 270 "Chapter 3/The Weaver.w"
	if ($line_category[$i] == $SOURCE_DISPLAY_LCAT) {
		print WEAVEOUT "\\quotesource{", $line_operand[$i], "}\n";
		next OUTLOOP;
	}

 } 
#line 260 "Chapter 3/The Weaver.w"
;
	
 { 
#line 279 "Chapter 3/The Weaver.w"
	if ($matter =~ m/^\s*$/) {
		print WEAVEOUT "\\smallskip\\par\\noindent%\n";
		next OUTLOOP;
	}

 } 
#line 261 "Chapter 3/The Weaver.w"
;
	
 { 
#line 288 "Chapter 3/The Weaver.w"
	if ($matter =~ m/^\(\.\.\.\)\s+(.*?)$/) { # continue single
		$matter = '\item{}'.$1;
	} elsif ($matter =~ m/^\(-\.\.\.\)\s+(.*?)$/) { # continue double
		$matter = '\itemitem{}'.$1;
	} elsif ($matter =~ m/^\(([a-z0-9A-Z\.]+)\)\s+(.*?)$/) { # begin single
		$matter = '\item{('.$1.')}'.$2;
	} elsif ($matter =~ m/^\(-([a-z0-9A-Z\.]+)\)\s+(.*?)$/) { # begin double
		$matter = '\itemitem{('.$1.')}'.$2;
	}

 } 
#line 262 "Chapter 3/The Weaver.w"
;
	
 { 
#line 302 "Chapter 3/The Weaver.w"
	if ($matter =~ m/^\t\|/) {
		$matter = '\par\noindent\qquad '.$matter;
	}

 } 
#line 263 "Chapter 3/The Weaver.w"
;
	print WEAVEOUT $matter, "\n";
	next OUTLOOP;

 } 
#line 51 "Chapter 3/The Weaver.w"
		else 
 { 
#line 312 "Chapter 3/The Weaver.w"
	
 { 
#line 336 "Chapter 3/The Weaver.w"
	if ($within_TeX_beginlines == 0) {
		print WEAVEOUT "\\beginlines\n"; $within_TeX_beginlines = 1;
	}

 } 
#line 312 "Chapter 3/The Weaver.w"
;
	
 { 
#line 344 "Chapter 3/The Weaver.w"
	if ($matter =~ m/^\s*$/) {
		print WEAVEOUT "\\smallskip\n";
		next OUTLOOP;
	}

 } 
#line 313 "Chapter 3/The Weaver.w"
;

	my $tab_stops_of_indentation = 0;
	
 { 
#line 353 "Chapter 3/The Weaver.w"
	my $spaces_in = 0;
	while ($matter =~ m/^(\s)(.*)$/) {
		$matter = $2;
		$whitespace = $1;
		if ($whitespace eq "\t") {
			$spaces_in = 0;
			$tab_stops_of_indentation++;
		} else {
			$spaces_in++;
			if ($spaces_in == 4) {
				$tab_stops_of_indentation++;
				$spaces_in = 0;
			}
		}
	}

 } 
#line 316 "Chapter 3/The Weaver.w"
;
	
 { 
#line 373 "Chapter 3/The Weaver.w"
	my $i;
	for ($i=0; $i<$tab_stops_of_indentation; $i++) {
		print WEAVEOUT "\\qquad";
	}

 } 
#line 317 "Chapter 3/The Weaver.w"
;

	my $concluding_comment = "";
	
 { 
#line 383 "Chapter 3/The Weaver.w"
	if (line_ends_with_comment($matter)) {
		if ($part_before_comment eq "") {
			$matter = $part_before_comment; my $commentary = $part_within_comment;
			$concluding_comment = "{\\ttninepoint\\it ".$commentary."}";
		} else {
			$matter = $part_before_comment; my $commentary = $part_within_comment;
			if ($commentary =~ m/^C\d+\S+$/) {
				$commentary = "Test with |".$commentary.".txt|";
			}
			$concluding_comment = "\\hfill\\quad {\\ttninepoint\\it ".$commentary."}";
		}
	}

 } 
#line 320 "Chapter 3/The Weaver.w"
;

	
 { 
#line 402 "Chapter 3/The Weaver.w"
	$matter =~ s/\|/\|\\\|\|/g;
	$matter = '|'.$matter.'|';

 } 
#line 322 "Chapter 3/The Weaver.w"
;
	
 { 
#line 409 "Chapter 3/The Weaver.w"
	$matter =~ s/^\|\@d /{\\ninebf define}| /;

 } 
#line 323 "Chapter 3/The Weaver.w"
;

	
 { 
#line 416 "Chapter 3/The Weaver.w"
	if ($matter =~ m/^\|\s*typedef\s+struct\s+(.*?)\s+\{/) {
		$structs_in_par .= $1.",";
	}
	if ($matter =~ m/^\|\/(\*+)\/\s*(.*?\**)(\S+?)\((.*)$/) {
		my $fstars = $1;
		my $ftype = $2;
		my $fname = $3;
		my $frest = $4;
		$matter = '|'.$ftype.'|\pdfliteral direct{0 1 1 0 k}|'.$fname.'|\special{PDF:0 g}|'.
			'('.$frest;
		$functions_in_par .= $fname.",";
	}
	if (($tab_stops_of_indentation == 0) &&
		($matter =~ m/^\|(\S.*?\**)(\S+?)\((.*)$/)) {
		my $ftype = $1;
		my $fname = $2;
		my $frest = $3;
		my $unamended = $fname;
		$fname =~ s/::/__/g;
		if (exists($functions_line{$fname})) {
			$matter = '|'.$ftype.'|\pdfliteral direct{0 1 1 0 k}|'.$unamended.
				'|\special{PDF:0 g}|'.'('.$frest;
			$functions_in_par .= $fname.",";
		}
	}

 } 
#line 325 "Chapter 3/The Weaver.w"
;

	
 { 
#line 447 "Chapter 3/The Weaver.w"
	while ($matter =~ m/^(.*?)\@\<(.*?)\@\>(.*)$/) {
		my $left = $1;
		my $right = $3;
		my $href = $2.' {\sevenss '.$cweb_macros_paragraph_number{$2}.'}';
		my $angled_sname = $2;
		my $xrefcol = '\pdfliteral direct{1 1 0 0 k}';
		my $blackcol = '\special{PDF:0 g}';
		my $tweaked = '$\langle${\xreffont'.$xrefcol.$href.'}'.$blackcol.'$\rangle$';
		if ($right =~ m/^\s*\=(.*)$/) 
 { 
#line 486 "Chapter 3/The Weaver.w"
	$right = $1;
	$tweaked = '\pdfdest num '.link_for_par_name($angled_sname).' fit '.$tweaked;
	$tweaked = $tweaked.' $\equiv$ ';
	$current_macro_definition = $angled_sname;

 } 
#line 456 "Chapter 3/The Weaver.w"
		else 
 { 
#line 494 "Chapter 3/The Weaver.w"
	my $new_p = $line_paragraph_number[$i];
	if (not($angled_paragraph_usage{$angled_sname} =~ m/$new_p,$/)) {
		$angled_paragraph_usage{$angled_sname} .= $new_p.',';
	}
	$tweaked =
		'\pdfstartlink attr{/C [0.9 0 0] /Border [0 0 0]} '.
		'goto num '.link_for_par_name($angled_sname).' '.
		$tweaked.'\pdfendlink';

 } 
#line 456 "Chapter 3/The Weaver.w"
;
		$matter = $left.'|'.$tweaked.'|'.$right;
	}

 } 
#line 327 "Chapter 3/The Weaver.w"
;
	
 { 
#line 464 "Chapter 3/The Weaver.w"
	my $count = 0;
	my $code_matter = 0;
	my $done = "";
	my $number_of_splits = 0;
	my $last_char = "";
	while ($matter =~ m/^(.)(.*?)$/) {
		my $next_char = $1; $matter = $2;
		if (($next_char eq "|") && ($last_char ne "\\")) { $code_matter = 1 - $code_matter; }
		elsif ($code_matter == 1) {
			$count++;
			if ($count > 99) {
				$done = $done."| \n\\quad ...| "; $number_of_splits++; $count = 10;
			}
		}
		$done = $done.$next_char;
		$last_char = $next_char;
	}
	$matter = $done;

 } 
#line 328 "Chapter 3/The Weaver.w"
;

	print WEAVEOUT $matter, $concluding_comment, "\n";
	next OUTLOOP;

 } 
#line 51 "Chapter 3/The Weaver.w"
;
	}
	
 { 
#line 621 "Chapter 3/The Weaver.w"
	if ($within_TeX_beginlines > 0) {
		print WEAVEOUT '\endlines', "\n"; $within_TeX_beginlines = 0;
	}
	show_endnotes_on_previous_paragraph($functions_in_par, $structs_in_par,
		$current_macro_definition);

 } 
#line 53 "Chapter 3/The Weaver.w"
;
	print WEAVEOUT "% End of weave: ", $lines_woven, " lines from ", $no_lines, "\n";
	print WEAVEOUT '\end', "\n";
	close(WEAVEOUT);
}

#line 631 "Chapter 3/The Weaver.w"
sub show_endnotes_on_previous_paragraph {
	my $functions_in_par = $_[0];
	my $structs_in_par = $_[1];
	my $current_macro_definition = $_[2];

	if ($current_macro_definition ne "")
		
 { 
#line 675 "Chapter 3/The Weaver.w"
	my $used_in = $angled_paragraph_usage{$current_macro_definition};
	$used_in =~ s/\,$//;
	print WEAVEOUT "\\penalty1000\n";
	print WEAVEOUT "\\noindent{\\usagefont This code is used in \$\\S\$",
		$used_in, ".}\\smallskip\n";

 } 
#line 638 "Chapter 3/The Weaver.w"
	else {
		my %fnames_done = ();
		while ($functions_in_par =~ m/^(\S+?)\,(.*)$/) {
			my $fname = $1;
			$functions_in_par = $2;
			if ($fnames_done{$fname}++ > 0) { next; }
			if ($fname eq "isdigit") { next; }
			
 { 
#line 684 "Chapter 3/The Weaver.w"
	my $scope = $functions_declared_scope{$fname};

	my @usages;
	my $no_sections_using = 0;
	
 { 
#line 723 "Chapter 3/The Weaver.w"
	my $x;
	for ($x=0; $x<$no_sections; $x++) { $usages[$x] = 0; }
	my $cp = $functions_usage_concisely_described{$fname};
	while ($cp =~ m/^\:(\d+)(.*?)$/) { $usages[eval($1)] = 1; $cp = $2; }
	for ($x=0; $x<$no_sections; $x++) { if ($usages[$x] == 1) { $no_sections_using++; } }

 } 
#line 688 "Chapter 3/The Weaver.w"
;

	my $fname_with_underscores_escaped = $fname;
	$fname_with_underscores_escaped =~ s/__/::/g;
	$fname_with_underscores_escaped =~ s/_/\\_/g;
	print WEAVEOUT "\\par\\noindent";
	print WEAVEOUT "\\penalty10000\n";
	print WEAVEOUT "{\\usagefont The function $fname_with_underscores_escaped is";
	my $clause_begins = 0;
	if ($scope eq "*****") {
		print WEAVEOUT " where execution begins"; $clause_begins = 1;
	}
	if ($scope eq "****") {
		print WEAVEOUT " invoked by a command in a |.i6t| template file"; $clause_begins = 1;
	}
	if (($clause_begins == 1) || (($scope eq "***") || ($scope eq "**"))) {
		if ($no_sections_using > 0) {
			if ($clause_begins) { print WEAVEOUT " and"; }
			print WEAVEOUT " called from ";
			my $x;
			for ($x=0; $x<$no_sections; $x++) {
				if ($usages[$x] == 1) {
					print WEAVEOUT $section_sigil[$x];
					if ($no_sections_using > 2) { print WEAVEOUT ", "; }
					if ($no_sections_using == 2) { print WEAVEOUT " and "; }
					$no_sections_using--;
				}
			}
		}
	}
	print WEAVEOUT ".}\n";

 } 
#line 645 "Chapter 3/The Weaver.w"
;
		}
		while ($structs_in_par =~ m/^(\S+?)\,(.*)$/) {
			my $sname = $1;
			my $sbilling;
			$structs_in_par = $2;
			if ($structure_ownership_summary{$sname} ne "") {
				$sbilling = $structure_ownership_summary{$sname};
				$sbilling =~ s/ /, /g;
				$sbilling =~ s/, $//;
				$sbilling =~ s/, (\S+)$/ and $1/;
				$sbilling = "shared with ".$sbilling;
			} else {
				$sbilling = "private to this section";
			}

			$sname =~ s/_/\\_/g;
			print WEAVEOUT "\\par\\noindent";
			print WEAVEOUT "\\penalty10000\n";
			$sname =~ s/\#/\\#/g;
			print WEAVEOUT "{\\usagefont The structure $sname is $sbilling.}\n";
		}
		print WEAVEOUT "\\smallskip\n";
	}
}

#line 735 "Chapter 3/The Weaver.w"
sub weave_cover_sheet {
	my $cover_sheet = $path_to_inweb_setting.'inweb/Materials/cover-sheet.tex';
	if (exists ($bibliographic_data{"Cover Sheet"})) {
		$cover_sheet = $web_setting.'Materials/'.$bibliographic_data{"Cover Sheet"};
	}

	$bibliographic_data{"Capitalized Title"} = $bibliographic_data{"Title"};
	$bibliographic_data{"Capitalized Title"} =~ tr/a-z/A-Z/;
	$bibliographic_data{"Booklet Title"} = $booklet_title;

	weave_cover_from($cover_sheet);
}

#line 752 "Chapter 3/The Weaver.w"
sub weave_cover_from {
	my $cs_filename = $_[0];
	local *COVER;
	open(COVER, $cs_filename) or die "inweb: cannot find cover sheet file";
	my $csl;
	while ($csl = <COVER>) {
		$csl =~ m/^(.*?)\s*$/; $csl = $1;
		if ($csl =~ m/^\%/) { next; } # a TeX comment begins with a percent sign
		while ($csl =~ m/^(.*?)\[\[(.*?)\]\](.*)$/) {
			print WEAVEOUT $1; my $expander = $2; $csl = $3;
			if ($expander eq "Cover Sheet") {
				my $insert_filename =
					$path_to_inweb_setting.'inweb/Materials/cover-sheet.tex';
				if ($insert_filename ne $cs_filename) {
					weave_cover_from($insert_filename);
				}
			} elsif (exists($bibliographic_data{$expander})) {
				print WEAVEOUT $bibliographic_data{$expander};
			} else {
				print WEAVEOUT $expander;
			}
		}
		print WEAVEOUT $csl, "\n";
	}
	close (COVER);
}

#line 784 "Chapter 3/The Weaver.w"
sub weave_interface_table_for_section {
	my $sect_no = $_[0];
	my $j;
	my $red_text = "\|\\pdfliteral direct\{0 1 1 0 k\}\|";
	my $blue_text = "\|\\pdfliteral direct\{1 1 0 0 k\}\|";
	my $black_text = "\|\\special{PDF:0 g}\|";

	my $fname;
	my %functions_in_order = (); # a device used to sort functions in definition order
	foreach $fname (keys %functions_line) {
		$functions_in_order{sprintf("%07d", $functions_line{$fname})} = $fname;
	}

	my $heading_made = 0;

	foreach $fnamed (sort keys %functions_in_order) {
		$fname = $functions_in_order{$fnamed};
		my $j = $functions_line{$fname};
		if ($line_sec[$j] != $sect_no) { next; }
		if ($functions_declared_scope{$fname} ne "****") { next; }

		if ($heading_made == 0) {
			$heading_made = 1;
			print WEAVEOUT "\\bigbreak\\par\\noindent",
				"{\\it Template interpreter commands}\\smallskip\n";
		}

		print WEAVEOUT "\\par\\noindent\n";
		print WEAVEOUT "{\\sevenss", $line_paragraph_number[$j], "}|  |\n";
		$spc = $functions_arglist{$fname};
		$spc =~ s/\,\s*/\,\n\t\t/g;
		$access = 'callv';
		if ($spc =~ m/FILE \*/) { $access = 'call'; }
		if ($fname =~ m/^(.*)_array$/) { $fname = $1; $access = 'array'; }
		if ($fname =~ m/^(.*)_routine$/) { $fname = $1; $access = 'routine'; }
		$fname =~ s/__/::/g;
		print WEAVEOUT '|{-', $access, ':', $blue_text, $fname, $black_text, "}|\n";
	}
	if ($heading_made == 1) {
		print WEAVEOUT "\\bigbreak\\noindent\n";
	}
}

#line 832 "Chapter 3/The Weaver.w"
sub weave_thematic_index {
	my $wanted= $_[0];
	foreach $subject (sort keys %thematic_indices) {
		my $chunk;
		if (($wanted ne "Remainder") && ($wanted ne $subject)) { next; }
		if ($index_subject_done{$subject}) { next; }
		$index_subject_done{$subject} = 1;
		print WEAVEOUT "{\\bf{", $subject, "}}\\par\n\\smallbreak\\hrule\\smallbreak\n";
		print WEAVEOUT ;
		$chunk = $thematic_indices{$subject};
		while ($chunk =~ m/^(.*?)\.\.\.(\d+)\|(.*)$/) {
			my $entry = $1;
			my $at = $2;
			$chunk = $3;
			print WEAVEOUT "\\line{", $entry,
				"\\leaders\\hbox to 1em{\\hss.\\hss}\\hfill {\\xreffont ",
				$line_csn[eval($at)], "}}\n";
		}
	}
}

#line 860 "Chapter 3/The Weaver.w"
sub begin_making_pdf_links {
	%link_number_for_par_name = ();
	$no_par_name_links = 1;
}

sub link_for_par_name {
	my $par_name = $_[0];
	if (not(exists $link_number_for_par_name{$par_name})) {
		$link_number_for_par_name{$par_name} = $no_par_name_links++;
	}
	return $link_number_for_par_name{$par_name};
}
#line 27 "Chapter 3/Backus-Naur Form.w"
sub parse_bnf_grammar {
	
 { 
#line 41 "Chapter 3/Backus-Naur Form.w"
	my $i;
	my $l;
	my $nonterminal_being_defined;
	$nonterminal_being_defined = "";
	for ($i=0; $i<$bnf_grammar_lines; $i++) {
		$l = $bnf_grammar[$i];
		if ($l =~ m/^\s*\<(.*?)\>\s*(.*)$/) {
			$nonterminal_being_defined = $1; $l = $2;
			if (not(exists $productions{$nonterminal_being_defined}))
				
 { 
#line 62 "Chapter 3/Backus-Naur Form.w"
	$productions{$nonterminal_being_defined} = $i;
	$production_tex{$nonterminal_being_defined}
		= "\\nonterminal{" . $nonterminal_being_defined . "}\$_{\\rm ".
			$section_sigil[$line_sec[$bnf_grammar_source[$i]]] . "}\$";

 } 
#line 50 "Chapter 3/Backus-Naur Form.w"
;
		}
		if ($l =~ m/^\s*$/) { next; } # skip blank line
		if ($l =~ m/^\s*\:\=\s+(.*)$/) 
 { 
#line 73 "Chapter 3/Backus-Naur Form.w"
	my $rhs = $1;
	if ($nonterminal_being_defined eq "") {
		inweb_error("BNF grammar for no obvious nonterminal\n", $bnf_grammar[$i]);
	}
	$no_productions_for{$nonterminal_being_defined}++;
	$productions_for{$nonterminal_being_defined} .= $rhs."&";
	next;

 } 
#line 53 "Chapter 3/Backus-Naur Form.w"
;
		if ($l =~ m/^\s*\.\.\.\s+(.*)$/) 
 { 
#line 87 "Chapter 3/Backus-Naur Form.w"
	my $more_rhs = $1;
	if ($nonterminal_being_defined eq "") {
		inweb_error("BNF grammar for no obvious nonterminal\n", $bnf_grammar[$i]);
	}
	my $existing_rhs = $productions_for{$nonterminal_being_defined};
	$existing_rhs =~ s/\&$//;
	$productions_for{$nonterminal_being_defined} = $existing_rhs." ... ".$more_rhs."&";

 } 
#line 54 "Chapter 3/Backus-Naur Form.w"
;
	}

 } 
#line 28 "Chapter 3/Backus-Naur Form.w"
;
	
 { 
#line 114 "Chapter 3/Backus-Naur Form.w"
	my $nt;
	foreach $nt (sort keys %productions) {
		$bnf_dependencies{$nt} = "";
		$bnf_depth{$nt} = 0;
		$bnf_follows{$nt} = "";
		$productions_for{$nt} =~ s/\[/ \[ /g;
		$productions_for{$nt} =~ s/\]/ \] /g;
		$productions_for{$nt} =~ s/\{/ \{ /g;
		$productions_for{$nt} =~ s/\}/ \} /g;
		$productions_for{$nt} =~ s/\s+/ /g;
	}

 } 
#line 29 "Chapter 3/Backus-Naur Form.w"
;
	
 { 
#line 129 "Chapter 3/Backus-Naur Form.w"
	my $nt;
	foreach $nt (sort keys %productions) {
		my $lines = $productions_for{$nt};
		while ($lines =~ m/^(.*?)\&(.*)$/) {
			my $line = $1; $lines = $2;
			while ($line =~ m/^\s*(\S+)(.*?)$/) {
				my $tok = $1;
				$line = $2;
				if ($tok =~ m/^\<(.*)\>$/) {
					$tok = $1;
					if (exists $production_tex{$tok}) {
						$bnf_dependencies{$tok} .= $nt . ",";
					}
				}
			}
		}
	}

 } 
#line 30 "Chapter 3/Backus-Naur Form.w"
;
	
 { 
#line 154 "Chapter 3/Backus-Naur Form.w"
	foreach $nt (sort keys %productions) {
		if (($bnf_dependencies{$nt} eq "")
			|| ($nt =~ m/\-sentence$/)
			|| ($nt eq "and")
			|| ($nt eq "or")
			|| ($nt eq "and-or")
			|| ($nt eq "paragraph")
			|| ($nt eq "sentence")
			|| ($nt eq "condition")
			|| ($nt eq "action-pattern")
			|| ($nt eq "literal-value")
			|| ($nt eq "type-expression")
			|| ($nt eq "physical-description")
			|| ($nt eq "value")) {
			$bnf_depth{$nt} = 1;
			$bnf_follows{$nt} = "";
		}
	}

 } 
#line 31 "Chapter 3/Backus-Naur Form.w"
;
	
 { 
#line 179 "Chapter 3/Backus-Naur Form.w"
	my $pass;
	for ($pass = 1; $pass <= 2; $pass++) {
		my $changed = 1;
		while ($changed == 1) {
			$changed = 0;
			my $nt;
			foreach $nt (sort keys %productions) {
				if ($bnf_depth{$nt} == 0) {
					$scan = $bnf_dependencies{$nt};
					$min_depth = 10000000; $unfound = 0;
					while ($scan =~ m/^(.*?)\,(.*)$/) {
						$scan = $2;
						$used = $1;
						if ($bnf_depth{$used} > 0) {
							if ($min_depth > $bnf_depth{$used}) {
								$min_depth = $bnf_depth{$used};
								$min_depth_follows = $used;
							}
						} else { if ($pass == 1) { $unfound = 1; } }
					}
					if (($unfound == 0) && ($min_depth < 100000)) {
						$bnf_depth{$nt} = $min_depth+1;
						$bnf_follows{$nt} = $min_depth_follows;
						$changed = 1;
					}
				}
			}
		}
	}

 } 
#line 32 "Chapter 3/Backus-Naur Form.w"
;
	
 { 
#line 216 "Chapter 3/Backus-Naur Form.w"
	my $nt;
	foreach $nt (sort keys %productions) {
		if ($bnf_depth{$nt} == 0) {
			$bnf_depth{$nt} = 1;
		}
	}

 } 
#line 33 "Chapter 3/Backus-Naur Form.w"
;
}

#line 230 "Chapter 3/Backus-Naur Form.w"
sub weave_bnf_grammar {
	my $toshow = $_[0];
	if ($bnf_already_parsed == 0) { parse_bnf_grammar(); $bnf_already_parsed = 1; }

	
 { 
#line 244 "Chapter 3/Backus-Naur Form.w"
	if ($toshow =~ m/^\: (.*?)\,\s*(.*)$/) {
		my $a = $1;
		my $b = $2;
		weave_bnf_grammar(": ".$a);
		weave_bnf_grammar(": ".$b);
		return;
	}

 } 
#line 234 "Chapter 3/Backus-Naur Form.w"
;
	
 { 
#line 256 "Chapter 3/Backus-Naur Form.w"
	if ($toshow =~ m/^\:\s*\-(.*)$/) {
		$tomatch = $1;
		foreach $nt (sort keys %productions) {
			if ($nt =~ m/\-$tomatch$/) {
				weave_nonterminal($nt);
			}
		}
		return;
	}

 } 
#line 235 "Chapter 3/Backus-Naur Form.w"
;
	
 { 
#line 269 "Chapter 3/Backus-Naur Form.w"
	if ($toshow =~ m/^\:\s*(.*)$/) {
		weave_nonterminal($1);
		return;
	}

 } 
#line 236 "Chapter 3/Backus-Naur Form.w"
;
	
 { 
#line 277 "Chapter 3/Backus-Naur Form.w"
	weave_nonterminal("value");
	my $nt;
	foreach $nt (sort keys %productions) {
		if ($bnf_depth{$nt} == 1) {
			weave_nonterminal($nt);
		}
	}

 } 
#line 237 "Chapter 3/Backus-Naur Form.w"
;
	
 { 
#line 288 "Chapter 3/Backus-Naur Form.w"
	foreach $nt (sort keys %productions) {
		if ($production_done{$nt} == 0) {
			print "Error in weave of BNF grammar: omitted ", $production_tex{$nt}, "\n";
			print $nt, ": ", $bnf_depth{$nt}, " ", $bnf_follows{$nt}, " ",
				$bnf_dependencies{$nt}, "\n";
		}
	}
	foreach $nt (sort keys %unknown_productions) {
		print WEAVEOUT "\\medskip{\\bf Unknown production:} \\nonterminal{", $nt, "}\\par\n";
	}

 } 
#line 238 "Chapter 3/Backus-Naur Form.w"
;
}

#line 305 "Chapter 3/Backus-Naur Form.w"
sub weave_nonterminal {
	my $nt = $_[0];
	if ($production_done{$nt} == 1) { return; }
	if ($bnf_depth{$nt} == 1) {
		print WEAVEOUT "\\smallbreak\\hrule\\smallbreak\n";
	} else {
		print WEAVEOUT "\\smallbreak\n";
	}
	
 { 
#line 332 "Chapter 3/Backus-Naur Form.w"
	bnf_indent($bnf_depth{$nt} - 1);
	print WEAVEOUT $production_tex{$nt}, "\n";
	$lines = $productions_for{$nt};
	$joined_lines = 0;
	if ($nt eq "debugging-aspect") { $joined_lines = 1; $join_count = 3; }
	if ($nt eq "determiner") { $joined_lines = 1; $join_count = 2; }
	$lc = 0; $lcm = $join_count - 1;
	while ($lines =~ m/^(.*?)\&(.*)$/) {
		$lc++; $line = $1; $lines = $2;
		
 { 
#line 349 "Chapter 3/Backus-Naur Form.w"
	if ($joined_lines == 1) {
		$lcm++; if ($lcm == $join_count) { $lcm = 0; }
		if ($lc == 1) {
			print WEAVEOUT "\\par";
			bnf_indent($bnf_depth{$nt} - 1);
			print WEAVEOUT "\\qquad ::\$=\$ ";
		} else {
			if ($lcm == 0) {
				print WEAVEOUT "\\par";
				bnf_indent($bnf_depth{$nt} - 1);
				print WEAVEOUT "\\qquad \\phantom{::\$=\$} \\| ";
			} else {
				print WEAVEOUT "\\| ";
			}
		}
	} else {
		print WEAVEOUT "\\par";
		bnf_indent($bnf_depth{$nt} - 1);
		print WEAVEOUT "\\qquad ::\$=\$ ";
	}

 } 
#line 341 "Chapter 3/Backus-Naur Form.w"
;
		
 { 
#line 380 "Chapter 3/Backus-Naur Form.w"
	$last_tok = "";
	while ($line =~ m/^\s*(\S+)(.*?)$/) {
		$tok = $1;
		$line = $2;
		
 { 
#line 394 "Chapter 3/Backus-Naur Form.w"
	if (($last_tok ne "[") && ($last_tok ne "{") && ($last_tok ne "")
		&& ($tok ne "]") && ($tok ne "}")) {
		print WEAVEOUT " ";
	}

 } 
#line 384 "Chapter 3/Backus-Naur Form.w"
;
		$last_tok = $tok;
		
 { 
#line 402 "Chapter 3/Backus-Naur Form.w"
	if ($tok eq "...") {
		print WEAVEOUT "\\par";
		bnf_indent($bnf_depth{$nt} - 1);
		print WEAVEOUT "\\qquad \\phantom{::\$=\$} ";
		next;
	}

 } 
#line 386 "Chapter 3/Backus-Naur Form.w"
;
		
 { 
#line 412 "Chapter 3/Backus-Naur Form.w"
	if ($tok =~ m/^\<(.*)\>$/) {
		$tok = $1;
		if (exists $production_tex{$tok}) {
			print WEAVEOUT $production_tex{$tok};
		} else {
			if ($tok =~ m/^(.*)-name$/) {
				print WEAVEOUT "{\\rm " . $1 . "}";
			} else {
				if ($tok =~ m/^(.*)-usage$/) {
					print WEAVEOUT "{\\it " . $tok . "}";
				} else {
					print WEAVEOUT "\\nonterminal{\\rm !!!!" . $tok . "!!!!}";
					$unknown_productions{$tok}++;
				}
			}
		}
		next;
	}

 } 
#line 387 "Chapter 3/Backus-Naur Form.w"
;
		
 { 
#line 435 "Chapter 3/Backus-Naur Form.w"
	if ($tok eq "{") { $tok = "\$\\{\$"; }
	if ($tok eq "}") { $tok = "\$\\}\$"; }
	if ((length($tok) > 2) &&
		($tok =~ m/^[A-Z\-][A-Z\-0-9]+$/)) {
		print WEAVEOUT "{\\eightbf ", $tok, "}";
		$lexical_productions{$tok}++;
	} else {
		print WEAVEOUT "{\\bf ", $tok, "}";
	}

 } 
#line 388 "Chapter 3/Backus-Naur Form.w"
;
	}

 } 
#line 342 "Chapter 3/Backus-Naur Form.w"
;
		print WEAVEOUT "\n";
	}

 } 
#line 313 "Chapter 3/Backus-Naur Form.w"
;
	
 { 
#line 321 "Chapter 3/Backus-Naur Form.w"
	my $dep;
	foreach $dep (sort keys %productions) {
		if ($bnf_follows{$dep} eq $nt) {
			weave_nonterminal($dep);
		}
	}

 } 
#line 314 "Chapter 3/Backus-Naur Form.w"
;
	$production_done{$nt} = 1;
}

#line 448 "Chapter 3/Backus-Naur Form.w"
sub bnf_indent {
	my $dep = $_[0];
	my $d;
	for ($d=1; $d<=$dep; $d++) {
		print WEAVEOUT "\\quad";
	}
}
#line 15 "Chapter 3/The Tangler.w"
sub tangle_source {
	my $target = $_[0];
	my $dest_file = $_[1];
	my $i;

	if ($target > 0) { print "Tangling independent target $target to $dest_file\n"; }
	language_set($tangle_target_language[$target]);
	if (language_tangles() == 0) { # for documentation webs, for instance
		inweb_fatal_error("can't tangle material in the language '".
			$bibliographic_data{"Language"}."'");
	}

	open(TANGLEOUT, ">".$dest_file) or die "inweb: can't open tangle file '$dest_file' for output";

	print TANGLEOUT language_shebang();
	if ($web_language != $I7_LANGUAGE) {
		print TANGLEOUT language_comment("Tangled output generated by inweb: do not edit");
	}

	for ($i=0; $i<$no_lines; $i++) {
		$line_suppress_tangling[$i] = 0;
		if ($line_category[$i] == $COMMAND_LCAT) {
			$line_suppress_tangling[$i] = 1;
		}
		if ($section_tangle_target[$line_sec[$i]] != $target) {
			$line_suppress_tangling[$i] = 1;
		}
	}

	if (($web_language == $C_LANGUAGE) || ($web_language == $C_FOR_INFORM_LANGUAGE))
		
 { 
#line 65 "Chapter 3/The Tangler.w"
	my $i;
	for ($i=0; $i<$no_lines; $i++) {
		if ($line_text_raw[$i] =~ m/^\s*\#include\s+\<(.*?)\.h\>\s*$/) {
			$clib = $1;
			if (($clib eq "stdio") ||
				($clib eq "ctype") ||
				($clib eq "math") ||
				($clib eq "stdarg") ||
				($clib eq "stdlib") ||
				($clib eq "string") ||
				($clib eq "time")) {
				$line_now_tangled[$i] = 1;
				print TANGLEOUT $line_text_raw[$i], "\n";
			}
		}
	}

 } 
#line 45 "Chapter 3/The Tangler.w"
;
	
 { 
#line 88 "Chapter 3/The Tangler.w"
	my $i;
	for ($i=0; $i<$no_lines; $i++) {
		if (($line_category[$i] == $BEGIN_DEFINITION_LCAT) &&
			($target == $section_tangle_target[$line_sec[$i]])) {
			my $definition_fragment = $line_operand_2[$i];
			$line_suppress_tangling[$i] = 1;
			language_start_definition($line_operand[$i],
				expand_double_squares($definition_fragment, 0));
			$i++;
			while (($i<$no_lines) && ($line_category[$i] == $CONT_DEFINITION_LCAT)) {
				language_prolong_definition(expand_double_squares($line_text_raw[$i], 0));
				$line_suppress_tangling[$i] = 1;
				$i++;
			}
			language_end_definition();
			$i--;
		}
	}

 } 
#line 46 "Chapter 3/The Tangler.w"
;
	if (($web_language == $C_LANGUAGE) || ($web_language == $C_FOR_INFORM_LANGUAGE))
		
 { 
#line 137 "Chapter 3/The Tangler.w"
	my $no_structs_left = 0;
	foreach $struc (keys %structures) {
		my $j;
		$no_structs_left++;
		$structure_declaration_tangled{$struc} = 0;
	}

	while ($no_structs_left > 0) {
		my $changes_made = 0;
		foreach $struc (sort keys %structures) {
			if (($structure_incorporates{$struc} eq "") && # no outward edges
				($structure_declaration_tangled{$struc} == 0)) # but still in graph
				
 { 
#line 169 "Chapter 3/The Tangler.w"
	# Tangle the |typedef| declaration lines...
	my $j;
	for ($j=$structure_declaration_line{$struc}; $j<=$structure_declaration_end{$struc}; $j++) {
		print TANGLEOUT $line_text_raw[$j], "\n";
		$line_suppress_tangling[$j] = 1;
	}
	# ...and keep the counts accurate:
	$no_structs_left--; $changes_made++;
	# (i) Strike this structure name out of the dependency lists of all others...
	foreach $n2 (sort keys %structures) {
		$structure_incorporates{$n2} =~ s/\-\>$struc\b//g;
	}
	# (ii) Remove this structure from further consideration
	$structure_declaration_tangled{$struc} = 1;

 } 
#line 149 "Chapter 3/The Tangler.w"
;
		}
		if ($changes_made == 0) {
			inweb_error("cyclic error in structure dependencies");
			foreach $struc (sort keys %structures) {
				if ($structure_declaration_tangled{$struc} == 0) {
					inweb_error($struc." needs prior declaration of ".
						$structure_incorporates{$struc});
				}
			}
			exit(1);
		}
	}

 } 
#line 48 "Chapter 3/The Tangler.w"
;
	
 { 
#line 189 "Chapter 3/The Tangler.w"
	my $i;
	for ($i=0; $i<$no_lines; $i++) {
		if ($line_category[$i] == $DEFINITIONS_LCAT) {
			$i++;
			my $md_from = $i;
			while (($i<$no_lines) && ($line_category[$i] != $BAR_LCAT)) { $i++; }
			my $md_to = $i;
			tangle_code($md_from, $md_to, 0);
			for ($i=$md_from; $i<$md_to; $i++) { $line_suppress_tangling[$i] = 1; }
			$i--;
		}
	}

 } 
#line 49 "Chapter 3/The Tangler.w"
;
	if (($web_language == $C_LANGUAGE) || ($web_language == $C_FOR_INFORM_LANGUAGE))
		
 { 
#line 212 "Chapter 3/The Tangler.w"
	my $chn;
	for ($chn=0; $chn<$no_chapters; $chn++) {
		print TANGLEOUT "\n",
			language_comment("Functions in chapter ".$chapter_sigil[$chn]), "\n";
		my $sn;
		for ($sn=0; $sn<$no_sections; $sn++) {
			if ($section_chap[$sn] != $chn) { next; }
			print TANGLEOUT "\n", language_comment("Section ".$section_sigil[$sn]);
			foreach $fname (sort keys %functions_line) {
				$j = $functions_line{$fname};
				if ($line_sec[$j] != $sn) { next; }
				$spc = $functions_arglist{$fname};
				$spc =~ s/\,\s*/\,\n\t\t/g;
				print TANGLEOUT $functions_return_type{$fname}, " ", $fname, "(", $spc, ");\n";
				if (exists $dot_i6_identifiers{$fname}) {
					print TANGLEOUT language_comment("accessed via .i6 metalanguage");
				} else {
					print TANGLEOUT $functions_usage_verbosely_described{$fname};
				}
			}
		}
	}

 } 
#line 51 "Chapter 3/The Tangler.w"
;
	tangle_code(0, $no_lines-1, 0);

	close(TANGLEOUT);
}

#line 240 "Chapter 3/The Tangler.w"
sub tangle_code {
	my $from = $_[0]; # Start line
	my $to = $_[1]; # End line
	my $permit_macro = $_[2]; # Allow CWEB macro definition bodies through?

	my $tline;
	my $contiguous = 0;
	for ($tline=$from; $tline<=$to; $tline++) {
		if (($permit_macro == 0) && ($line_occurs_in_CWEB_macro_definition[$tline] == 1)) {
			$contiguous = 0; next;
		}
		if ($line_suppress_tangling[$tline] == 1) { $contiguous = 0; next; }
		if (not(($line_category[$tline] == $CODE_BODY_LCAT))) { $contiguous = 0; next; }
		if ($line_text_raw[$tline] =~ m/^\s*\@c/) { $contiguous = 0; next; }

		if ($line_text_raw[$tline] =~ m/^(.*?)\@\<(.*?)\@\>\s*(.*?)$/)
			
 { 
#line 311 "Chapter 3/The Tangler.w"
	my $prologue = $1; local $name = $2; local $residue = $3;
	if ($residue =~ m/^(.*?)\@\<(.*?)\@\>(.*)$/) {
		inweb_error_at_program_line("only one <...> macro can be used on any single line",
			$tline);
	}
	
 { 
#line 276 "Chapter 3/The Tangler.w"
	if (($contiguous == 0) &&
		(($web_language == $C_LANGUAGE) ||
			($web_language == $C_FOR_INFORM_LANGUAGE) ||
			($web_language == $PERL_LANGUAGE))) {
		$contiguous = 1;
		tangle_out("#line ".$line_source_file_line[$tline].
			" \"".$section_pathname_relative_to_web[$line_sec[$tline]]."\"");
	}

 } 
#line 316 "Chapter 3/The Tangler.w"
;
	tangle_out(expand_double_squares($prologue, 1));
	if (not(exists $cweb_macros_start{$name})) {
		inweb_error_at_program_line("no such <...> macro as '".$name."'", $tline);
	} else {
		if (($web_language == $C_LANGUAGE) ||
			($web_language == $C_FOR_INFORM_LANGUAGE) ||
			($web_language == $PERL_LANGUAGE)) { print TANGLEOUT " { "; }
		tangle_out(expand_double_squares($cweb_macros_surplus_bit{$name}, 1));
		tangle_code($cweb_macros_start{$name}, $cweb_macros_end{$name}, 1);
		if (($web_language == $C_LANGUAGE) ||
			($web_language == $C_FOR_INFORM_LANGUAGE) ||
			($web_language == $PERL_LANGUAGE)) { print TANGLEOUT " } "; }
	}
	$contiguous = 0;
	print TANGLEOUT "\n";
	if ($residue ne "") {
		
 { 
#line 276 "Chapter 3/The Tangler.w"
	if (($contiguous == 0) &&
		(($web_language == $C_LANGUAGE) ||
			($web_language == $C_FOR_INFORM_LANGUAGE) ||
			($web_language == $PERL_LANGUAGE))) {
		$contiguous = 1;
		tangle_out("#line ".$line_source_file_line[$tline].
			" \"".$section_pathname_relative_to_web[$line_sec[$tline]]."\"");
	}

 } 
#line 333 "Chapter 3/The Tangler.w"
;
		tangle_out(expand_double_squares($residue, 1));
	}
	next;

 } 
#line 256 "Chapter 3/The Tangler.w"
;

		
 { 
#line 276 "Chapter 3/The Tangler.w"
	if (($contiguous == 0) &&
		(($web_language == $C_LANGUAGE) ||
			($web_language == $C_FOR_INFORM_LANGUAGE) ||
			($web_language == $PERL_LANGUAGE))) {
		$contiguous = 1;
		tangle_out("#line ".$line_source_file_line[$tline].
			" \"".$section_pathname_relative_to_web[$line_sec[$tline]]."\"");
	}

 } 
#line 258 "Chapter 3/The Tangler.w"
;
		$expanded = expand_double_squares($line_text_raw[$tline], 1);
		if ($expanded =~ m/^\?\:\s*(.*)$/) {
			inweb_error_at_program_line("C-for-Inform error ($1)", $tline);
		}

		tangle_out($expanded);
	}
}

#line 341 "Chapter 3/The Tangler.w"
sub tangle_out {
	my $line_of_code = $_[0];
	if ($web_language == $C_FOR_INFORM_LANGUAGE) {
		$line_of_code =~ s/\:\:/__/g;
	}
	print TANGLEOUT $line_of_code, "\n";
}

#line 359 "Chapter 3/The Tangler.w"
sub expand_double_squares {
	my $line = $_[0];
	my $with_extensions = $_[1];
	my $fore;
	my $aft;
	my $comm;
	my $expanded;
	my $safety_check = 0;
	my $so_far = "";
	while ($line =~ m/^(.+?)\[\[(.*?)\]\](.*)$/) {
		$fore = $1; $line = $3; $comm = $2;
		$so_far .= $fore;
		if (exists ($bibliographic_data{$comm})) {
			$so_far .= $bibliographic_data{$comm};
		} elsif (($with_extensions == 1) && ($web_language == $C_FOR_INFORM_LANGUAGE)) {
			$expanded = expand_double_squared_command($comm);
			if ($expanded =~ m/^\?\: /) { return $expanded; }
			$so_far .= $expanded;
			if ($safety_check++ == 100) {
				return '?: expander gone into infinite regress';
			}
		} else {
			$so_far .= '[['.$comm.']]';
		}
	}
	$so_far .= $line;
	return $so_far;
}
#line 25 "Chapter 3/Programming Languages.w"

#line 29 "Chapter 3/Programming Languages.w"
sub language_set {
	my $lname = $_[0];
	$web_language = -1;
	if ($lname eq "C") { $web_language = $C_LANGUAGE; $tangled_extension = ".c"; }
	if ($lname eq "C++") { $web_language = $C_LANGUAGE; $tangled_extension = ".cpp"; }
	if ($lname eq "C for Inform") {
		$web_language = $C_FOR_INFORM_LANGUAGE; $tangled_extension = ".c";
		
 { 
#line 61 "Chapter 3/Programming Languages.w"
	$blacklisted_functions{"isdigit"} = 1;
	$blacklisted_members{"word_ref1"} = 1;
	$blacklisted_members{"word_ref2"} = 1;
	$blacklisted_members{"next"} = 1;
	$blacklisted_members{"down"} = 1;
	$blacklisted_members{"allocation_id"} = 1;
	$members_allowed_to_be_unused{"handling_routine"} = 1;

 } 
#line 36 "Chapter 3/Programming Languages.w"
;
	}
	if ($lname eq "Perl") { $web_language = $PERL_LANGUAGE;  $tangled_extension = ".pl"; }
	if ($lname eq "Inform 6") { $web_language = $I6_LANGUAGE;  $tangled_extension = ".i6"; }
	if ($lname eq "Inform 7") { $web_language = $I7_LANGUAGE;  $tangled_extension = ".i7x"; }
	if ($lname eq "Plain Text") { $web_language = $PLAIN_LANGUAGE;  $tangled_extension = ".txt"; }
	if ($lname eq "None") { $web_language = $NO_LANGUAGE;  $tangled_extension = ""; }
	if ($web_language == -1) {
		inweb_fatal_error("unsupported programming language ".$lname);
	}
}

#line 72 "Chapter 3/Programming Languages.w"
sub language_file_extension { return $tangled_extension; }

#line 77 "Chapter 3/Programming Languages.w"
sub language_shebang {
	my $text = $_[0];
	if ($web_language == $PERL_LANGUAGE) { return "#!/usr/bin/perl\n\n"; }
	return "";
}

#line 86 "Chapter 3/Programming Languages.w"
sub language_comment {
	my $text = $_[0];
	if ($web_language == $C_LANGUAGE) { return "/* ".$text." */\n"; }
	if ($web_language == $C_FOR_INFORM_LANGUAGE) { return "/* ".$text." */\n"; }
	if ($web_language == $PERL_LANGUAGE) { return "# ".$text."\n"; }
	if ($web_language == $I6_LANGUAGE) { return "! ".$text."\n"; }
	if ($web_language == $I7_LANGUAGE) { return "[".$text."]\n"; }
	return "";
}

#line 99 "Chapter 3/Programming Languages.w"
sub language_and_so_on {
	my $text = $_[0];
	if (($web_language == $C_LANGUAGE) || ($web_language == $C_FOR_INFORM_LANGUAGE)) {
		if ($text =~ m/^\s*\/\* ...and so on... \*\/\s*/) { return 1; }
	}
	if ($web_language == $I6_LANGUAGE) {
		if ($text =~ m/^\s*\!\s*...and so on...\s*$/) { return 1; }
	}
	if ($web_language == $I7_LANGUAGE) {
		if ($text =~ m/^\s*\[\s*...and so on...\s*\]\s*$/) { return 1; }
	}
	return 0;
}

#line 116 "Chapter 3/Programming Languages.w"
sub line_ends_with_comment {
	my $matter = $_[0];
	if (($web_language == $C_LANGUAGE) || ($web_language == $C_FOR_INFORM_LANGUAGE)) {
		if ($matter =~ m/^(.*)\/\*\s*(.*?)\s*\*\/\s*$/) {
			$part_before_comment = $1; $part_within_comment = $2; return 1;
		}
	}
	if ($web_language == $PERL_LANGUAGE) {
		if ($matter =~ m/^\#\s+(.*?)\s*$/) {
			$part_before_comment = ""; $part_within_comment = $1; return 1;
		}
		if ($matter =~ m/^(.*)\s+\#\s+(.*?)\s*$/) {
			$part_before_comment = $1; $part_within_comment = $2; return 1;
		}
	}
	return 0;
}

#line 137 "Chapter 3/Programming Languages.w"
sub language_pagebreak_comment {
	my $l = $_[0];
	if (($web_language == $C_LANGUAGE) || ($web_language == $C_FOR_INFORM_LANGUAGE)) {
		if ($l =~ m/^\s*\/\* PAGEBREAK \*\/\s*$/) { return 1; }
	}
	if ($web_language == $PERL_LANGUAGE) {
		if ($l =~ m/^\s*\#\s+PAGEBREAK\s*$/) { return 1; }
	}
	if ($web_language == $I6_LANGUAGE) {
		if ($l =~ m/^\s*\!\s+PAGEBREAK\s*$/) { return 1; }
	}
	if ($web_language == $I7_LANGUAGE) {
		if ($l =~ m/^\s*\[\s*PAGEBREAK\s*\]\s*$/) { return 1; }
	}
	return 0;
}

#line 158 "Chapter 3/Programming Languages.w"
sub language_tangles {
	if ($web_language == $NO_LANGUAGE) { return 0; }
	return 1;
}

#line 170 "Chapter 3/Programming Languages.w"
sub language_start_definition {
	my $term = $_[0];
	my $startval = $_[1];
	if (($web_language == $C_LANGUAGE) || ($web_language == $C_FOR_INFORM_LANGUAGE)) {
		if ($web_language == $C_FOR_INFORM_LANGUAGE) { $startval =~ s/::/__/g; }
		print TANGLEOUT "#define ", $term, " ", $startval;
		return;
	}
	if ($web_language == $PERL_LANGUAGE) {
		print TANGLEOUT $term, " = ", $startval;
		return;
	}
	inweb_error("programming language $web_language does not support \@d");
}
sub language_prolong_definition {
	my $more = $_[0];
	if (($web_language == $C_LANGUAGE) || ($web_language == $C_FOR_INFORM_LANGUAGE)) {
		if ($web_language == $C_FOR_INFORM_LANGUAGE) { $more =~ s/::/__/g; }
		print TANGLEOUT "\\\n    ", $more;
		return;
	}
	inweb_error("programming language $web_language does not support multiline \@d");
}
sub language_end_definition {
	if (($web_language == $C_LANGUAGE) || ($web_language == $C_FOR_INFORM_LANGUAGE)) {
		print TANGLEOUT "\n";
	}
	if ($web_language == $PERL_LANGUAGE) {
		print TANGLEOUT "\n;\n";
	}
}
#line 15 "Chapter 3/C for Inform.w"
sub full_test_double_squares {
	test_ds("[[w1, w2 == ...]]");
	test_ds("[[w1, w2 == golly]]");
	test_ds("[[word w1 == zowie]]");
	test_ds("[[word w1 == wow/huh/zowie]]");
	test_ds("[[w1, w2 == by the pool]]");
	test_ds("[[w1, w2 == moreover ***]]");
	test_ds("[[w1, w2 == *** by the pool]]");
	test_ds("[[w1, w2 == by the pool ***]]");
	test_ds("[[w1, w2 == golly gosh/moses mrs smith]]");
	test_ds("[[w1, w2 == so mr ### we meet again]]");
	test_ds("[[w1, w2 == hello there ...]]");
	test_ds("[[w1, w2 == ... the memory of water]]");
	test_ds("[[w1, w2 <-- something]]");
	test_ds("[[w1, w2 == ... nantucket ...]]");
	test_ds("[[w1, w2 == ... when ... : w]]");
	test_ds("[[w1, w2 == hot porridge ... when ... : w]]");
	test_ds("[[w1, w2 == ... when ... breakfast is served]]");
	test_ds("[[w1, w2 == ... when ... and ... breakfast is served]]");
	test_ds("[[w1, w2 == ... when ... and ... breakfast is served : w]]");
	test_ds("[[w1, w2 == ... when ... and ... breakfast is served : w, x]]");
	test_ds("[[w1, w2 == ... when ... and ... breakfast is served : w, x, y]]");
	test_ds("[[w1, w2 == ... when ... breakfast is served : w, z, x]]");
	test_ds("[[w1, w2 == bacon ... when ... breakfast is served : w]]");
	test_ds("[[w1, w2 == and now ... --> now1, now2]]");
	test_ds("[[w1, w2 == ... until then --> then1, then2]]");
	test_ds("[[w1, w2 == ... when ... : w --> w1, w2 ... when1, when2]]");
	test_ds("[[w1, w2 == ... when ... : w --> when1, when2 ... w1, w2]]");
	test_ds("[[w1, w2 == ... when ... : w --> when1, w2 ... when2, w1]]");
	test_ds("[[w1, w2 == ... OPENBRACKET for ... only CLOSEBRACKET --> x1, x2 ... vm1, vm2]]");
}

sub test_ds {
	my $original = $_[0];
	print "inweb: testing expansion ", $original, "\n\n";
	print expand_double_squares(" ".$original), "\n\n";
}

#line 59 "Chapter 3/C for Inform.w"
sub expand_double_squared_command {
	my $comm = $_[0];
	my $operator = 0;
	my $lhs;
	my $rhs;
	my $w1;
	my $w2;
	my $single_word_flag = 0;

	
 { 
#line 81 "Chapter 3/C for Inform.w"
	if ($comm =~ m/^(.*?)\s*\=\=\s*(.*?)\s*$/) {
		$operator = 1; $lhs = $1; $rhs = $2;
	} else {
		if ($comm =~ m/^(.*?)\s*\<\-\-\s*(.*?)\s*$/) {
			$operator = 2; $lhs = $1; $rhs = $2;
		}
	}
	if ($operator == 0) {
		return '?: [[ ... ]] with neither <-- nor == operators';
	}

 } 
#line 68 "Chapter 3/C for Inform.w"
;
	
 { 
#line 95 "Chapter 3/C for Inform.w"
	if ($lhs =~ m/^\s*(\S+?)\s*\,\s*(\S+)\s*$/) {
		$w1 = $1; $w2 = $2;
	} else {
		if ($lhs =~ m/^\s*(\S+)\s*$/) {
			$w1 = $1."->word_ref1"; $w2 = $1."->word_ref2";
		} else {
			if ($lhs =~ m/^\s*word\s+(\S+)\s*$/) {
				$w1 = $1; $w2 = $w1; $single_word_flag = 1;
			} else {
				return '?: [[ ... ]] without comma-separated word pair';
			}
		}
	}

 } 
#line 69 "Chapter 3/C for Inform.w"
;
	if ($operator == 1) {
		if ($single_word_flag == 1) 
 { 
#line 120 "Chapter 3/C for Inform.w"
	if ($rhs =~ m/^\s*(\S+?)\s*$/) {
		my $list = $1;
		my $cond = '(('.$w1.'>=0) && (';
		my $ct = 1;
		while ($list =~ m/^([^\/]+)(.*)$/) {
			if ($ct > 1) { $cond .= ' || '; }
			$ct++;
			$cond .= compare_word_p($w1, 0, $1);
			$list = $2; $list =~ s/^\///;
		}
		$cond .= '))';
		return $cond;
	}
	return '?: [[ ... ]] cannot test a single word variable to other than a single word';

 } 
#line 72 "Chapter 3/C for Inform.w"
		else 
 { 
#line 139 "Chapter 3/C for Inform.w"
	my $write_positions = "";
	my $write_ranges = "";
	
 { 
#line 166 "Chapter 3/C for Inform.w"
	if ($rhs =~ m/^(.*)\s*\-\-\>\s*(.*?)\s*$/) {
		$write_ranges = $2; $rhs = $1;
	}
	if ($rhs =~ m/^(.*)\s*\:\s*(.*?)\s*$/) {
		$rhs = $1; $write_positions = $2;
	}
	if (($rhs.' '.$write_positions) =~ m/\-\-\>/) { return '?: [[ ... ]] has too many -->s'; }

	$rhs =~ m/^\s*(.*?)\s*$/; $rhs = $1;
	$write_positions =~ m/^\s*(.*?)\s*$/; $write_positions = $1;
	$write_ranges =~ m/^\s*(.*?)\s*$/; $write_ranges = $1;

 } 
#line 141 "Chapter 3/C for Inform.w"
;

	my $right_unanchored = 0;
	my $left_unanchored = 0;
	
 { 
#line 184 "Chapter 3/C for Inform.w"
	if ($rhs =~ m/^(.*)\s+\*\*\*\s*$/) {
		$rhs = $1;
		$right_unanchored = 1;
	}
	if ($rhs =~ m/^\*\*\*\s+(.*)$/) {
		$rhs = $1;
		$left_unanchored = 1;
	}

 } 
#line 145 "Chapter 3/C for Inform.w"
;

	my $nw = 0;
	
 { 
#line 196 "Chapter 3/C for Inform.w"
	while ($rhs =~ m/^(\S*?)\s+(.*)$/) {
		$words[$nw++] = $1; $rhs = $2;
	}
	$words[$nw++] = $rhs;

 } 
#line 148 "Chapter 3/C for Inform.w"
;

	my $nr = 0;
	
 { 
#line 204 "Chapter 3/C for Inform.w"
	my $i;
	my $range_start = -1;
	for ($i=0; $i < $nw; $i++) {
		if ($words[$i] eq '...') {
			if ($range_start >= 0) {
				$range_from[$nr] = $range_start; $range_to[$nr++] = $i-1;
				$range_start = -1;
			}
		} else {
			if ($range_start == -1) { $range_start = $i; }
		}
	}
	if ($range_start >= 0) {
		$range_from[$nr] = $range_start; $range_to[$nr++] = $nw-1;
	}

 } 
#line 151 "Chapter 3/C for Inform.w"
;
	
 { 
#line 223 "Chapter 3/C for Inform.w"
	my $i;
	for ($i=0; $i<$nr; $i++) {
		$range_length[$i] = $range_to[$i]-$range_from[$i]+1;
		$range_anchor[$i] = -1;
		$range_anchor_direction[$i] = 0;
		$range_from_fixed[$i] = 0;
		$range_to_fixed[$i] = 0;
		if (($range_from[$i] == 0) && ($left_unanchored == 0)) {
			$range_anchor[$i] = 0;
			$range_anchor_direction[$i] = 1;
			$range_from_fixed[$i] = 1;
		}
		if (($range_to[$i] == $nw-1) && ($right_unanchored == 0)) {
			$range_anchor[$i] = $nw-1;
			$range_anchor_direction[$i] = -1;
			$range_to_fixed[$i] = 1;
		}
	}

 } 
#line 152 "Chapter 3/C for Inform.w"
;
	if ($nr == 0) { return "(FALSE)"; }

	my $cond = "(";
	
 { 
#line 245 "Chapter 3/C for Inform.w"
	
 { 
#line 276 "Chapter 3/C for Inform.w"
	$cond .= "(". $w1 . ">=0)";

	my $need = 0; # minimum number of words needed
	my $exact = 1; # is this the exact number of words we must have?
	for ($i=0; $i<$nr; $i++) {
		$need = $need + $range_length[$i];
		if ($range_from_fixed[$i] == 0) { $exact = 0; }
		if ($range_to_fixed[$i] == 0) { $exact = 0; }
	}
	for ($i=0; $i<$nw; $i++) {
		if ($words[$i] eq '...') { $need++; }
	}
	$need--;
	if ($exact == 1) { $op = "=="; } else { $op = ">="; }
	$cond .= " && (". $w2 . $op . var_offset($w1, $need) . ")";

 } 
#line 245 "Chapter 3/C for Inform.w"
;

	my $i;
	for ($i=0; $i<$nr; $i++) { $range_done[$i] = 0; }

	$left_inset = 0;
	$right_inset = 0;
	$left_extent = 0;
	$right_extent = 0;

	
 { 
#line 305 "Chapter 3/C for Inform.w"
	my $j;
	for ($i=0; $i<$nr; $i++) {
		if ($range_done[$i] == 1) { next; }
		if (($range_from[$i] == 0) && ($range_from_fixed[$i] == 1)) {
			for ($j=0; $j<$range_length[$i]; $j++) {
				$cond .= compare_word($w1, $j, $words[$j]);
			}
			$range_done[$i] = 1;
			$left_extent = $range_length[$i];
			$left_inset += $range_length[$i] - 1;
			next;
		}
		if (($range_to[$i] == $nw-1) && ($range_to_fixed[$i] == 1)) {
			for ($j=$range_length[$i]-1; $j>=0; $j--) {
				$cond .= compare_word($w2, 0-$j, $words[$nw-1-$j]);
			}
			$range_done[$i] = 1;
			$right_inset += $range_length[$i] - 1;
			$right_extent = $range_length[$i];
			next;
		}
	}

 } 
#line 255 "Chapter 3/C for Inform.w"
;
	
 { 
#line 347 "Chapter 3/C for Inform.w"
	my $left_var = $w1;
	my $right_var = $w2;
	$unwritten_var_exists = 0;
	$no_written_vars = 0;
	my $i;
	for ($i=0; $i<$nr; $i++) {
		if ($range_done[$i] == 1) { next; }
		if ($range_length[$i] == 1) {
			$cond .= " && (";
			if ($write_positions ne "") {
				if ($write_positions =~ m/^\s*(.*?)\s*\,\s*(.*)$/) {
					$write_var = $1; $write_positions = $2;
				} else { $write_var = $write_positions; $write_positions = ""; }
				$cond .= "(".$write_var."=";
			} else {
				if ($unwritten_var_exists == 1) {
					return '?: [[ ... ]] has insufficient : variables';
				}
				$unwritten_var_exists = 1;
			}
			if ($write_var eq "") { $cond.= "("; }
			$cond .=
				"Text__is_word_intermediate(".$words[$range_from[$i]]."_V,"
				. var_offset($left_var, $left_inset)
				. ","
				. var_offset($right_var, 0-$right_inset)."))";
			if ($write_var ne "") {
				$cond .= ",(".$write_var.">=0))";
				$left_var = $write_var;
				$written_vars[$no_written_vars++] = $write_var;
			} else {
				$cond.= " >= 0)";
			}
			$range_done[$i] = 1;
			next;
		}
	}

 } 
#line 256 "Chapter 3/C for Inform.w"
;

	for ($i=0; $i<$nr; $i++) {
		if ($range_done[$i] == 0) { return '?: [[ ... ]] has intractable range'; }
	}
	
 { 
#line 398 "Chapter 3/C for Inform.w"
	$no_assignments = 0;
	
 { 
#line 411 "Chapter 3/C for Inform.w"
	my $j = 0;
	my $i;
	for ($i=0; $i<$nw; $i++) {
		if ($words[$i] eq '...') {
			if ($j == 0) {
				$from_var = $w1;
				$from_offset = $left_extent;
			} else {
				$from_var = $written_vars[$j-1];
				$from_offset = 1;
			}
			if ($j<$no_written_vars) {
				$to_var = $written_vars[$j];
				$to_offset = -1;
				$j++;
			} else {
				$to_var = $w2;
				$to_offset = 0-$right_extent;
			}
			if ($write_ranges =~ m/^\s*(\S+)\s*\,\s*(\S+)\s*(.*?)\s*$/) {
				$write_from_var = $1;
				$write_to_var = $2;
				$write_ranges = $3;
				assign_set_var($write_from_var, $from_var, $from_offset);
				assign_set_var($write_to_var, $to_var, $to_offset);
				if ($write_ranges ne "") {
					if ($write_ranges =~ m/^\s*\.\.\.\s*(.*)$/) {
						$write_ranges = $1;
					} else {
						return '?: [[ ... ]] pairs of write vars should be divided by ...';
					}
				}
			} else {
				if ($write_ranges ne "") {
					return '?: [[ ... ]] write vars should be in pairs divided by ...';
				}
			}
		}
	}

 } 
#line 399 "Chapter 3/C for Inform.w"
;
	for ($i=0; $i<$no_assignments; $i++) { $assignment_done[$i] = 0; }
	
 { 
#line 468 "Chapter 3/C for Inform.w"
	my $no_done = 0;
	my $safety_check = 0; # in case of a bug in this code, really
	while ($no_done < $no_assignments) {
		
 { 
#line 479 "Chapter 3/C for Inform.w"
	my $i;
	for ($i=0; $i<$no_assignments; $i++) {
		$necessity_count{$var_to_read[$i]} = 0;
		$necessity_count{$var_to_assign[$i]} = 0;
	}
	for ($i=0; $i<$no_assignments; $i++) {
		if ($assignment_done[$i] == 0) {
			if ($var_to_read[$i] ne $var_to_assign[$i]) {
				$necessity_count{$var_to_read[$i]}++;
			}
		}
	}

 } 
#line 471 "Chapter 3/C for Inform.w"
;
		
 { 
#line 495 "Chapter 3/C for Inform.w"
	my $i;
	for ($i=0; $i<$no_assignments; $i++) {
		if (($assignment_done[$i] == 0) && ($necessity_count{$var_to_assign[$i]} == 0)) {
			$cond .= set_var($var_to_assign[$i], $var_to_read[$i], $var_to_offset[$i]);
			$assignment_done[$i] = 1;
			$no_done++;
		}
	}

 } 
#line 472 "Chapter 3/C for Inform.w"
;
		if ($safety_check++ == 1000) 
 { 
#line 516 "Chapter 3/C for Inform.w"
	my $i;
	for ($i=0; $i<$no_assignments; $i++) {
		if ($assignment_done[$i] == 0) {
			inweb_error("  ".$var_to_assign[$i]." = ".$var_to_read[$i]." + ".$var_to_offset[$i]);
		}
	}
	return '?: [[ ... ]] no safe way to write these pairs of variables';

 } 
#line 473 "Chapter 3/C for Inform.w"
;
	}

 } 
#line 401 "Chapter 3/C for Inform.w"
;

 } 
#line 261 "Chapter 3/C for Inform.w"
;

 } 
#line 156 "Chapter 3/C for Inform.w"
;
	$cond .= ")";

	if ($write_ranges ne "") { return '?: [[ ... ]] has too many write pairs of variables'; }
	if ($write_positions ne "") { return '?: [[ ... ]] has too many : variables'; }
	return $cond;

 } 
#line 72 "Chapter 3/C for Inform.w"
;
	}
	if ($operator == 2) 
 { 
#line 112 "Chapter 3/C for Inform.w"
	if ($single_word_flag == 1) {
		return '?: [[ ... ]] cannot assign a single word variable';
	}
	return $w1 . " = " . $rhs . "->word_ref1; ". $w2 . " = " . $rhs . "->word_ref2;";

 } 
#line 74 "Chapter 3/C for Inform.w"
;
	return '?: This should not happen';
}

#line 528 "Chapter 3/C for Inform.w"
sub assign_set_var {
	my $write_var = $_[0];
	my $from_var = $_[1];
	my $from_offset = $_[2];
	if (($from_offset == 0) && ($write_var eq $from_var)) { return ""; }
	$var_to_assign[$no_assignments] = $write_var;
	$var_to_read[$no_assignments] = $from_var;
	$var_to_offset[$no_assignments] = $from_offset;
	$no_assignments++;
}

#line 542 "Chapter 3/C for Inform.w"
sub set_var {
	my $write_var = $_[0];
	my $from_var = $_[1];
	my $from_offset = $_[2];
	if (($from_offset == 0) && ($write_var eq $from_var)) { return ""; }
	return " && (".$write_var."=".var_offset($from_var, $from_offset).")";
}

#line 555 "Chapter 3/C for Inform.w"
sub var_offset {
	my $var = $_[0];
	my $offset = $_[1];
	if ($offset == 0) { return $var; }
	if ($offset > 0) { return $var."+".$offset; }
	return $var."-".(0-$offset);
}

#line 576 "Chapter 3/C for Inform.w"
sub compare_word {
	my $var = $_[0];
	my $offset = $_[1];
	my $with = $_[2];
	my $this;
	my $rest;
	my $cond;

	$cond = " && ";
	if ($with =~ m/\//) {
		$cond .= "(";
		while ($with =~ m/^(.*?)\/(.*)$/) {
			$this = $1; $with = $2;
			$cond .= compare_word_p($var, $offset, $this);
			$cond .= " || ";
		}
		$cond .= compare_word_p($var, $offset, $with);
		$cond .= ")";
	} else {
		$cond .= compare_word_p($var, $offset, $with);
	}
	return $cond;
}

#line 605 "Chapter 3/C for Inform.w"
sub compare_word_p {
	my $var = $_[0];
	my $offset = $_[1];
	my $with = $_[2];
	if ($with eq '###') { return "(TRUE)"; }
	return "(compare_word(" . var_offset($var, $offset) . ", " . $with . "_V))";
}
