pax_global_header00006660000000000000000000000064116734577440014534gustar00rootroot0000000000000052 comment=e50f7d7d907f11f604a3d66339438c6509069085 jikespg-1.3/000077500000000000000000000000001167345774400130335ustar00rootroot00000000000000jikespg-1.3/ChangeLog000066400000000000000000000020201167345774400145770ustar00rootroot000000000000002001-10-10 Eric Blake * src/Makefile: * src/ctabs.c: * src/common.h: * src/globals.c: * src/lpgparse.c: * src/lpgparse.h: Fix copyright issues before release 1.3. 2001-09-05 Eric Blake * src/Makefile: Changed default from AIX to gcc (but it is still hardcoded. Anyone want to autoconfiscate this project?) * src/ctabs.c (init_file, exit_file, exit_parser_files) (print_definitions): * src/common.h: * src/globals.c: * src/lpgparse.c (options): * src/lpgparse.h: Added option jikes, to hack in headers and footers to files generated by jikespg. 1999-11-04 Convert to use IBM Public License Version 1.0 Make this version 1.2. The source files are unchanged except to change text related to the license name/version. 1999-02-10 * Start ChangeLog. Just added *.am automake/autoconf files provided by Aaron Renn (arenn@urbanophile.com) as start toward support GNU's "configure" build process. jikespg-1.3/Makefile.am000066400000000000000000000001471167345774400150710ustar00rootroot00000000000000SUBDIRS = src examples EXTRA_DIST = README.TXT \ jikespg.htm \ license.htm jikespg-1.3/README.TXT000066400000000000000000000020661167345774400143750ustar00rootroot00000000000000The files in this directory and its contained subdirectories collectively comprise the distribution of the IBM Research Jikes Parser Generator (http://www.ibm.com/research/jikes) in source form. This distribution is covered by the IBM Jikes Compiler License Agreement, contained in the file license.htm, and also available from http://www.ibm.com/research/jikes. Almost all files are covered by the license, in particular each and every file that contains the following text near the beginning: This software is subject to the terms of the IBM Jikes Compiler License Agreement available at the following URL: http://www.ibm.com/research/jikes. Copyright (C) 1982, 1999, International Business Machines Corporation and others. All Rights Reserved. You must accept the terms of that agreement to use this software. You must accept the terms of the IBM Jikes Compiler License Agreement to use this software. See the file jikespg.htm for documentation in FAQ (Frequently Asked Questions) format. Philippe Charles Dave Shields 27 January 1999 jikespg-1.3/examples/000077500000000000000000000000001167345774400146515ustar00rootroot00000000000000jikespg-1.3/examples/Makefile.am000066400000000000000000000000241167345774400167010ustar00rootroot00000000000000SUBDIRS = bnf expr jikespg-1.3/examples/bnf/000077500000000000000000000000001167345774400154165ustar00rootroot00000000000000jikespg-1.3/examples/bnf/Ast.java000066400000000000000000000006351167345774400170140ustar00rootroot00000000000000// $Id: Ast.java,v 1.3 1999/11/04 14:02:16 shields Exp $ // This software is subject to the terms of the IBM Jikes Compiler // License Agreement available at the following URL: // http://www.ibm.com/research/jikes. // Copyright (C) 1983, 1999, International Business Machines Corporation // and others. All Rights Reserved. // You must accept the terms of that agreement to use this software. interface Ast { } jikespg-1.3/examples/bnf/LexStream.java000066400000000000000000000043721167345774400201730ustar00rootroot00000000000000// $Id: LexStream.java,v 1.3 1999/11/04 14:02:16 shields Exp $ // This software is subject to the terms of the IBM Jikes Compiler // License Agreement available at the following URL: // http://www.ibm.com/research/jikes. // Copyright (C) 1983, 1999, International Business Machines Corporation // and others. All Rights Reserved. // You must accept the terms of that agreement to use this software. import java.util.Vector; import java.io.FileInputStream; // // LexStream holds a stream of tokens generated from an input and // provides methods to retrieve information from the stream. // public class LexStream implements bnfsym { private int index; final static int INFINITY = Integer.MAX_VALUE; int Next(int i) { return (++i < tokens.size() ? i : tokens.size() - 1); } int Previous(int i) { return (i <= 0 ? 0 : i - 1); } int Peek() { return Next(index); } void Reset(int i) { index = Previous(i); } void Reset() { index = 0; } int Gettoken() { return index = Next(index); } int Gettoken(int end_token) { return index = (index < end_token ? Next(index) : tokens.size() - 1); } int Badtoken() { return 0; } int Kind(int i) { return ((Token) tokens.elementAt(i)).kind; } String Name(int i) { return ((Token) tokens.elementAt(i)).name; } //* //* Constructors and Destructor. //* LexStream(String filename) throws java.io.FileNotFoundException { srcfile = new FileInputStream(filename); } void dump() { for (int i = 1; i < tokens.size(); i++) { System.out.print(" ("); switch(((Token) tokens.elementAt(i)).kind) { case TK_SYMBOL: System.out.print("SYMBOL"); break; case TK_OR: System.out.print("|"); break; case TK_PRODUCES: System.out.print("::="); break; case TK_EOF: System.out.print("EOF"); break; default: System.out.print(((Token) tokens.elementAt(i)).kind); } System.out.print(") : \""); System.out.print(((Token) tokens.elementAt(i)).name); System.out.println("\""); } } Vector tokens = new Vector(); FileInputStream srcfile; } jikespg-1.3/examples/bnf/Main.java000066400000000000000000000017571167345774400171570ustar00rootroot00000000000000// $Id: Main.java,v 1.3 1999/11/04 14:02:16 shields Exp $ // This software is subject to the terms of the IBM Jikes Compiler // License Agreement available at the following URL: // http://www.ibm.com/research/jikes. // Copyright (C) 1983, 1999, International Business Machines Corporation // and others. All Rights Reserved. // You must accept the terms of that agreement to use this software. public class Main { public static void main(String[] args) throws java.io.IOException, java.io.FileNotFoundException { Option option = new Option(args); if (option.filename == null) { System.out.println("No Input File Specified !!!"); return; } LexStream lex_stream = new LexStream(option.filename); Scanner scanner = new Scanner(option, lex_stream); scanner.scan(); if (option.dump) lex_stream.dump(); Parser parser = new Parser(lex_stream); parser.parse(); return; } } jikespg-1.3/examples/bnf/Makefile000066400000000000000000000006311167345774400170560ustar00rootroot00000000000000# This software is subject to the terms of the IBM Jikes Compiler # License Agreement available at the following URL: # http://www.ibm.com/research/jikes. # Copyright (C) 1983, 1999, International Business Machines Corporation # and others. All Rights Reserved. # You must accept the terms of that agreement to use this software. all: jikespg bnf.g jikes *.java clean: rm bnf*.java rm bnf.l rm *.class jikespg-1.3/examples/bnf/Makefile.am000066400000000000000000000014511167345774400174530ustar00rootroot00000000000000JIKESPG = @JIKESPG@ JAVAROOT = . check_JAVA = bnfact.java \ bnfdcl.java \ bnfdef.java \ bnfhdr.java \ bnfprs.java \ bnfsym.java \ Ast.java \ Token.java \ LexStream.java \ Main.java \ Option.java \ Parser.java \ Scanner.java bnfact.java bnfdcl.java bnfdef.java bnfhdr.java bnfprs.java bnfsym.java : bnf.g $(JIKESPG) bnf.g EXTRA_DIST = bnf.g \ example1.bnf \ example2.bnf CLEANFILES = bnf.l MAINTAINERCLEANFILES = bnfact.java \ bnfdcl.java \ bnfdef.java \ bnfhdr.java \ bnfprs.java \ bnfsym.java jikespg-1.3/examples/bnf/Option.java000066400000000000000000000015451167345774400175360ustar00rootroot00000000000000// $Id: Option.java,v 1.3 1999/11/04 14:02:16 shields Exp $ // This software is subject to the terms of the IBM Jikes Compiler // License Agreement available at the following URL: // http://www.ibm.com/research/jikes. // Copyright (C) 1983, 1999, International Business Machines Corporation // and others. All Rights Reserved. // You must accept the terms of that agreement to use this software. class Option { String filename; boolean non_validating = true, dump = false; Option(String [] args) { for (int i = 0; i < args.length; i++) { if (args[i].charAt(0) == '-') { if (args[i].equals("-d")) dump = true; } else { filename = args[i]; break; } } return; } } jikespg-1.3/examples/bnf/Parser.java000066400000000000000000000111451167345774400175170ustar00rootroot00000000000000// $Id: Parser.java,v 1.3 1999/11/04 14:02:16 shields Exp $ // This software is subject to the terms of the IBM Jikes Compiler // License Agreement available at the following URL: // http://www.ibm.com/research/jikes. // Copyright (C) 1996, 1998, International Business Machines Corporation // and others. All Rights Reserved. // You must accept the terms of that agreement to use this software. class Parser extends bnfprs implements bnfsym { final static int STACK_INCREMENT = 128; LexStream lex_stream; bnfhdr actions = new bnfhdr(this); int state_stack_top, stack[], location_stack[]; int parse_stack[]; // // Given a rule of the form A ::= x1 x2 ... xn n > 0 // // the function TOKEN(i) yields the symbol xi, if xi is a terminal // or ti, if xi is a nonterminal that produced a string of the form // xi => ti w. // final int TOKEN(int i) { return location_stack[state_stack_top + (i - 1)]; } // // Given a rule of the form A ::= x1 x2 ... xn n > 0 // // The function SYM(i) yields the AST subtree associated with symbol // xi. NOTE that if xi is a terminal, SYM(i) is undefined ! (However, // see token_action below.) // // setSYM1(int INFO) is a function that allows us to assign an info // to SYM(1). // final int SYM(int i) { return parse_stack[state_stack_top + (i - 1)]; } final void setSYM1(int info) { parse_stack[state_stack_top] = info; } // // When a token is shifted, we may wish to perform an action on // it. One possibility is to invoke "setSYM(null)" to associate // a null subtree with this terminal symbol. // void token_action(int tok) { setSYM1(0); System.out.println("Shifting token " + lex_stream.Name(tok)); } Parser(LexStream lex_stream) { this.lex_stream = lex_stream; } void reallocate_stacks() { int old_stack[] = stack; stack = new int[(old_stack == null ? 0 : old_stack.length) + STACK_INCREMENT]; if (old_stack != null) System.arraycopy(old_stack, 0, stack, 0, old_stack.length); old_stack = location_stack; location_stack = new int[(old_stack == null ? 0 : old_stack.length) + STACK_INCREMENT]; if (old_stack != null) System.arraycopy(old_stack, 0, location_stack, 0, old_stack.length); int old_parse_stack[] = parse_stack; parse_stack = new int[(old_parse_stack == null ? 0 : old_parse_stack.length) + STACK_INCREMENT]; if (old_parse_stack != null) System.arraycopy(old_parse_stack, 0, parse_stack, 0, old_parse_stack.length); return; } void parse() { lex_stream.Reset(); int curtok = lex_stream.Gettoken(), act = START_STATE, current_kind = lex_stream.Kind(curtok); /*****************************************************************/ /* Start parsing. */ /*****************************************************************/ state_stack_top = -1; ProcessTerminals: for (;;) { if (++state_stack_top >= (stack == null ? 0 : stack.length)) reallocate_stacks(); stack[state_stack_top] = act; location_stack[state_stack_top] = curtok; act = t_action(act, current_kind, lex_stream); if (act <= NUM_RULES) state_stack_top--; // make reduction look like a shift-reduce else if (act > ERROR_ACTION) { token_action(curtok); curtok = lex_stream.Gettoken(); current_kind = lex_stream.Kind(curtok); act -= ERROR_ACTION; } else if (act < ACCEPT_ACTION) { token_action(curtok); curtok = lex_stream.Gettoken(); current_kind = lex_stream.Kind(curtok); continue ProcessTerminals; } else break ProcessTerminals; ProcessNonTerminals: do { state_stack_top -= (rhs[act] - 1); actions.rule_action[act].action(); act = nt_action(stack[state_stack_top], lhs[act]); } while(act <= NUM_RULES); } if (act == ERROR_ACTION) { // // Recover or Scream or Whatever !!! // System.out.println("Error detected on token " + curtok); return; } System.out.println("Input parsed successfully"); return; } } jikespg-1.3/examples/bnf/Scanner.java000066400000000000000000000041761167345774400176620ustar00rootroot00000000000000// $Id: Scanner.java,v 1.3 1999/11/04 14:02:16 shields Exp $ // This software is subject to the terms of the IBM Jikes Compiler // License Agreement available at the following URL: // http://www.ibm.com/research/jikes. // Copyright (C) 1983, 1999, International Business Machines Corporation // and others. All Rights Reserved. // You must accept the terms of that agreement to use this software. // // The Scanner object // class Scanner implements bnfsym { int next_byte; Option option; LexStream lex_stream; Scanner(Option option, LexStream lex_stream) { this.lex_stream = lex_stream; this.option = option; } // // // void skip_spaces() throws java.io.IOException { while (next_byte >= 0 && Character.isSpace((char) next_byte)) next_byte = lex_stream.srcfile.read(); return; } // // // String scan_symbol() throws java.io.IOException { StringBuffer buffer = new StringBuffer(); while (next_byte >= 0 && (! Character.isSpace((char) next_byte))) { buffer.append((char) next_byte); next_byte = lex_stream.srcfile.read(); } return buffer.toString(); } // // // void scan() throws java.io.IOException { // // Do not use token indexed at location 0. // Token start_token = new Token(); start_token.kind = 0; start_token.name = ""; lex_stream.tokens.addElement(start_token); next_byte = lex_stream.srcfile.read(); for (skip_spaces(); next_byte >= 0; skip_spaces()) { Token token = new Token(); token.name = scan_symbol(); lex_stream.tokens.addElement(token); if (token.name.equals("::=")) token.kind = TK_PRODUCES; else if (token.name.equals("|")) token.kind = TK_OR; else token.kind = TK_SYMBOL; } Token end_token = new Token(); end_token.kind = TK_EOF; end_token.name = ""; lex_stream.tokens.addElement(end_token); return; } } jikespg-1.3/examples/bnf/Token.java000066400000000000000000000007721167345774400173470ustar00rootroot00000000000000// $Id: Token.java,v 1.3 1999/11/04 14:02:16 shields Exp $ // This software is subject to the terms of the IBM Jikes Compiler // License Agreement available at the following URL: // http://www.ibm.com/research/jikes. // Copyright (C) 1983, 1999, International Business Machines Corporation // and others. All Rights Reserved. // You must accept the terms of that agreement to use this software. public class Token { int kind; String name; void set_name(String name) { this.name = name; } } jikespg-1.3/examples/bnf/bnf.g000066400000000000000000000113031167345774400163310ustar00rootroot00000000000000%Options la=2,gp=java,act,an=bnfact.java,hn=bnfhdr.java,tab=space,fp=bnf,prefix=TK_, %Options nogoto-default,output-size=125,names=max,error-maps %Define -- This software is subject to the terms of the IBM Jikes Parser -- Generator License Agreement available at the following URL: -- http://www.ibm.com/research/jikes. -- Copyright (C) 1983, 1999, International Business Machines Corporation -- and others. All Rights Reserved. -- You must accept the terms of that agreement to use this software. -- This grammar has been augmented with productions that captures -- most errors that a user is likely to make. This saves the need -- to have an error recovery system. -- -- This macro is used to initialize the rule_action array -- to the null_action function. -- %null_action /. new NullAction(), ./ -- -- This macro is used to initialize the rule_action array -- to the no_action function. -- %no_action /. new NoAction(), ./ %Terminals SYMBOL PRODUCES OR EOF ERROR %Alias '::=' ::= PRODUCES '|' ::= OR %EOF ::= EOF %ERROR ::= ERROR %Rules /: class bnfhdr extends bnfact { Action rule_action[] = { null, // no element 0 :/ /. class bnfact { Parser parser; bnfact(Parser parser) { this.parser = parser; } void print_rule(int rule_no) { String rule = new String(); rule = parser.name[parser.non_terminal_index[parser.lhs[rule_no]]] + " ::="; if (parser.rhs[rule_no] == 0) rule += " %empty"; else { for (int i = 1; i <= parser.rhs[rule_no]; i++) { int non_term = parser.SYM(i), term = parser.lex_stream.Kind(parser.TOKEN(i)); rule += (" " + (non_term == 0 ? parser.name[parser.terminal_index[term]] : parser.name[parser.non_terminal_index[non_term]])); } } System.out.println("Reducing rule number " + rule_no + ": " + rule); return; } interface Action { public void action(); } final class NoAction implements Action { public void action() {} } final class NullAction implements Action { public void action() { System.out.println("A null production"); } } ./ bnf ::= %empty /: new act%rule_number(),:/ /. // // Rule %rule_number: %rule_text // final class act%rule_number implements Action { public void action() { print_rule(%rule_number); parser.setSYM1((int) parser.lhs[%rule_number]); } } ./ bnf ::= bnf rules /: new act%rule_number(),:/ /. // // Rule %rule_number: %rule_text // final class act%rule_number implements Action { public void action() { print_rule(%rule_number); parser.setSYM1((int) parser.lhs[%rule_number]); } } ./ rules ::= rule /: new act%rule_number(),:/ /. // // Rule %rule_number: %rule_text // final class act%rule_number implements Action { public void action() { print_rule(%rule_number); parser.setSYM1((int) parser.lhs[%rule_number]); } } ./ rules ::= rules '|' symbol_list /: new act%rule_number(),:/ /. // // Rule %rule_number: %rule_text // final class act%rule_number implements Action { public void action() { print_rule(%rule_number); parser.setSYM1((int) parser.lhs[%rule_number]); } } ./ rule ::= SYMBOL '::=' symbol_list /: new act%rule_number(),:/ /. // // Rule %rule_number: %rule_text // final class act%rule_number implements Action { public void action() { print_rule(%rule_number); parser.setSYM1((int) parser.lhs[%rule_number]); } } ./ symbol_list ::= %empty /: new act%rule_number(),:/ /. // // Rule %rule_number: %rule_text // final class act%rule_number implements Action { public void action() { print_rule(%rule_number); parser.setSYM1((int) parser.lhs[%rule_number]); } } ./ symbol_list ::= symbol_list SYMBOL /: new act%rule_number(),:/ /. // // Rule %rule_number: %rule_text // final class act%rule_number implements Action { public void action() { print_rule(%rule_number); parser.setSYM1((int) parser.lhs[%rule_number]); } } ./ /: }; bnfhdr(Parser parser) { super(parser); } } :/ /. } ./ %End jikespg-1.3/examples/bnf/example1.bnf000066400000000000000000000002541167345774400176220ustar00rootroot00000000000000bnf ::= %empty | bnf rules rules ::= rule | rules '|' symbol_list rule ::= symbol '::=' symbol_list symbol_list ::= %empty | symbol_list symbol jikespg-1.3/examples/bnf/example2.bnf000066400000000000000000000002641167345774400176240ustar00rootroot00000000000000bnf ::= %empty | bnf rules rules ::= rule | rules '|' symbol_list rule ::= symbol '::=' symbol_list symbol_list ::= %empty | symbol_list symbol ::= ::= jikespg-1.3/examples/expr/000077500000000000000000000000001167345774400156275ustar00rootroot00000000000000jikespg-1.3/examples/expr/Ast.java000066400000000000000000000010151167345774400172160ustar00rootroot00000000000000// $Id: Ast.java,v 1.3 1999/11/04 14:02:18 shields Exp $ // This software is subject to the terms of the IBM Jikes Compiler // License Agreement available at the following URL: // http://www.ibm.com/research/jikes. // Copyright (C) 1983, 1999, International Business Machines Corporation // and others. All Rights Reserved. // You must accept the terms of that agreement to use this software. abstract class Ast { int value; abstract public int Value(); abstract public String toString(LexStream lex_stream); } jikespg-1.3/examples/expr/AstBinary.java000066400000000000000000000014141167345774400203660ustar00rootroot00000000000000// $Id: AstBinary.java,v 1.3 1999/11/04 14:02:18 shields Exp $ // This software is subject to the terms of the IBM Jikes Compiler // License Agreement available at the following URL: // http://www.ibm.com/research/jikes. // Copyright (C) 1983, 1999, International Business Machines Corporation // and others. All Rights Reserved. // You must accept the terms of that agreement to use this software. abstract class AstBinary extends Ast { int op; Ast left, right; public String toString(LexStream lex_stream, String operator) { StringBuffer buffer = new StringBuffer(); buffer.append(left.toString(lex_stream)); buffer.append(operator); buffer.append(right.toString(lex_stream)); return buffer.toString(); } } jikespg-1.3/examples/expr/AstMinus.java000066400000000000000000000011371167345774400202370ustar00rootroot00000000000000// $Id: AstMinus.java,v 1.3 1999/11/04 14:02:18 shields Exp $ // This software is subject to the terms of the IBM Jikes Compiler // License Agreement available at the following URL: // http://www.ibm.com/research/jikes. // Copyright (C) 1983, 1999, International Business Machines Corporation // and others. All Rights Reserved. // You must accept the terms of that agreement to use this software. class AstMinus extends AstBinary { public int Value() { return left.Value() - right.Value(); } public String toString(LexStream lex_stream) { return toString(lex_stream, " - "); } } jikespg-1.3/examples/expr/AstNegativeNumber.java000066400000000000000000000011611167345774400220540ustar00rootroot00000000000000// $Id: AstNegativeNumber.java,v 1.3 1999/11/04 14:02:18 shields Exp $ // This software is subject to the terms of the IBM Jikes Compiler // License Agreement available at the following URL: // http://www.ibm.com/research/jikes. // Copyright (C) 1983, 1999, International Business Machines Corporation // and others. All Rights Reserved. // You must accept the terms of that agreement to use this software. class AstNegativeNumber extends Ast { int op, token; public int Value() { return value; } public String toString(LexStream lex_stream) { return "-" + lex_stream.Name(token); } } jikespg-1.3/examples/expr/AstNumber.java000066400000000000000000000011171167345774400203720ustar00rootroot00000000000000// $Id: AstNumber.java,v 1.3 1999/11/04 14:02:18 shields Exp $ // This software is subject to the terms of the IBM Jikes Compiler // License Agreement available at the following URL: // http://www.ibm.com/research/jikes. // Copyright (C) 1983, 1999, International Business Machines Corporation // and others. All Rights Reserved. // You must accept the terms of that agreement to use this software. class AstNumber extends Ast { int token; public int Value() { return value; } public String toString(LexStream lex_stream) { return lex_stream.Name(token); } } jikespg-1.3/examples/expr/AstParen.java000066400000000000000000000013751167345774400202150ustar00rootroot00000000000000// $Id: AstParen.java,v 1.3 1999/11/04 14:02:18 shields Exp $ // This software is subject to the terms of the IBM Jikes Compiler // License Agreement available at the following URL: // http://www.ibm.com/research/jikes. // Copyright (C) 1983, 1999, International Business Machines Corporation // and others. All Rights Reserved. // You must accept the terms of that agreement to use this software. class AstParen extends Ast { Ast expression; public int Value() { return expression.Value(); } public String toString(LexStream lex_stream) { StringBuffer buffer = new StringBuffer(); buffer.append('('); buffer.append(expression.toString(lex_stream)); buffer.append(')'); return buffer.toString(); } } jikespg-1.3/examples/expr/AstPlus.java000066400000000000000000000011351167345774400200650ustar00rootroot00000000000000// $Id: AstPlus.java,v 1.3 1999/11/04 14:02:18 shields Exp $ // This software is subject to the terms of the IBM Jikes Compiler // License Agreement available at the following URL: // http://www.ibm.com/research/jikes. // Copyright (C) 1983, 1999, International Business Machines Corporation // and others. All Rights Reserved. // You must accept the terms of that agreement to use this software. class AstPlus extends AstBinary { public int Value() { return left.Value() + right.Value(); } public String toString(LexStream lex_stream) { return toString(lex_stream, " + "); } } jikespg-1.3/examples/expr/AstSlash.java000066400000000000000000000011371167345774400202160ustar00rootroot00000000000000// $Id: AstSlash.java,v 1.3 1999/11/04 14:02:18 shields Exp $ // This software is subject to the terms of the IBM Jikes Compiler // License Agreement available at the following URL: // http://www.ibm.com/research/jikes. // Copyright (C) 1983, 1999, International Business Machines Corporation // and others. All Rights Reserved. // You must accept the terms of that agreement to use this software. class AstSlash extends AstBinary { public int Value() { return left.Value() / right.Value(); } public String toString(LexStream lex_stream) { return toString(lex_stream, " / "); } } jikespg-1.3/examples/expr/AstStar.java000066400000000000000000000011351167345774400200530ustar00rootroot00000000000000// $Id: AstStar.java,v 1.3 1999/11/04 14:02:18 shields Exp $ // This software is subject to the terms of the IBM Jikes Compiler // License Agreement available at the following URL: // http://www.ibm.com/research/jikes. // Copyright (C) 1983, 1999, International Business Machines Corporation // and others. All Rights Reserved. // You must accept the terms of that agreement to use this software. class AstStar extends AstBinary { public int Value() { return left.Value() * right.Value(); } public String toString(LexStream lex_stream) { return toString(lex_stream, " * "); } } jikespg-1.3/examples/expr/LexStream.java000066400000000000000000000045551167345774400204070ustar00rootroot00000000000000// $Id: LexStream.java,v 1.3 1999/11/04 14:02:18 shields Exp $ // This software is subject to the terms of the IBM Jikes Compiler // License Agreement available at the following URL: // http://www.ibm.com/research/jikes. // Copyright (C) 1983, 1999, International Business Machines Corporation // and others. All Rights Reserved. // You must accept the terms of that agreement to use this software. import java.util.Vector; import java.io.InputStream; // // LexStream holds a stream of tokens generated from an input and // provides methods to retrieve information from the stream. // public class LexStream implements exprsym { private int index; final static int INFINITY = Integer.MAX_VALUE; int Next(int i) { return (++i < tokens.size() ? i : tokens.size() - 1); } int Previous(int i) { return (i <= 0 ? 0 : i - 1); } int Peek() { return Next(index); } void Reset(int i) { index = Previous(i); } void Reset() { index = 0; } int Gettoken() { return index = Next(index); } int Gettoken(int end_token) { return index = (index < end_token ? Next(index) : tokens.size() - 1); } int Badtoken() { return 0; } int Kind(int i) { return ((Token) tokens.elementAt(i)).kind; } String Name(int i) { return ((Token) tokens.elementAt(i)).name; } void dump() { for (int i = 1; i < tokens.size(); i++) { System.out.print(" ("); switch(((Token) tokens.elementAt(i)).kind) { case TK_PLUS: System.out.print("PLUS"); break; case TK_MINUS: System.out.print("MINUS"); break; case TK_STAR: System.out.print("STAR"); break; case TK_SLASH: System.out.print("SLASH"); break; case TK_LPAREN: System.out.print("LPAREN"); break; case TK_RPAREN: System.out.print("RPAREN"); break; case TK_NUMBER: System.out.print("NUMBER"); break; case TK_ERROR: System.out.print("ERROR"); break; case TK_EOF: System.out.print("EOF"); break; default: System.out.print(((Token) tokens.elementAt(i)).kind); } System.out.print(") : \""); System.out.print(((Token) tokens.elementAt(i)).name); System.out.println("\""); } } Vector tokens = new Vector(); } jikespg-1.3/examples/expr/Main.java000066400000000000000000000021511167345774400173550ustar00rootroot00000000000000// $Id: Main.java,v 1.3 1999/11/04 14:02:18 shields Exp $ // This software is subject to the terms of the IBM Jikes Compiler // License Agreement available at the following URL: // http://www.ibm.com/research/jikes. // Copyright (C) 1983, 1999, International Business Machines Corporation // and others. All Rights Reserved. // You must accept the terms of that agreement to use this software. public class Main { public static void main(String[] args) throws java.io.IOException, java.io.FileNotFoundException { Option option = new Option(args); while (true) { System.out.print("Expression: "); LexStream lex_stream = new LexStream(); Scanner scanner = new Scanner(option, lex_stream); scanner.scan(); if (option.dump) lex_stream.dump(); Parser parser = new Parser(lex_stream); Ast root = parser.parse(); if (root != null) System.out.println(" " + root.toString(lex_stream) + " = " + root.Value()); else break; } return; } } jikespg-1.3/examples/expr/Makefile000066400000000000000000000006341167345774400172720ustar00rootroot00000000000000# This software is subject to the terms of the IBM Jikes Compiler # License Agreement available at the following URL: # http://www.ibm.com/research/jikes. # Copyright (C) 1983, 1999, International Business Machines Corporation # and others. All Rights Reserved. # You must accept the terms of that agreement to use this software. all: jikespg expr.g jikes *.java clean: rm expr*.java rm expr.l rm *.class jikespg-1.3/examples/expr/Makefile.am000066400000000000000000000017551167345774400176730ustar00rootroot00000000000000JIKESPG = @JIKESPG@ JAVAROOT = . check_JAVA = expract.java \ exprhdr.java \ exprdcl.java \ exprsym.java \ exprdef.java \ exprprs.java \ Ast.java \ AstBinary.java \ AstMinus.java \ AstNegativeNumber.java \ AstNumber.java \ AstParen.java \ AstPlus.java \ AstSlash.java \ AstStar.java \ LexStream.java \ Main.java \ Option.java \ Parser.java \ Scanner.java \ Token.java expract.java exprhdr.java exprdcl.java exprsym.java exprdef.java exprprs.java : expr.g $(JIKESPG) expr.g EXTRA_DIST = expr.g CLEANFILES = expr.l MAINTAINERCLEANFILES = expract.java \ exprhdr.java \ exprdcl.java \ exprsym.java \ exprdef.java \ exprprs.java jikespg-1.3/examples/expr/Option.java000066400000000000000000000015451167345774400177470ustar00rootroot00000000000000// $Id: Option.java,v 1.3 1999/11/04 14:02:18 shields Exp $ // This software is subject to the terms of the IBM Jikes Compiler // License Agreement available at the following URL: // http://www.ibm.com/research/jikes. // Copyright (C) 1983, 1999, International Business Machines Corporation // and others. All Rights Reserved. // You must accept the terms of that agreement to use this software. class Option { String filename; boolean non_validating = true, dump = false; Option(String [] args) { for (int i = 0; i < args.length; i++) { if (args[i].charAt(0) == '-') { if (args[i].equals("-d")) dump = true; } else { filename = args[i]; break; } } return; } } jikespg-1.3/examples/expr/Parser.java000066400000000000000000000107411167345774400177310ustar00rootroot00000000000000// $Id: Parser.java,v 1.4 1999/11/04 14:02:18 shields Exp $ // This software is subject to the terms of the IBM Jikes Compiler // License Agreement available at the following URL: // http://www.ibm.com/research/jikes. // Copyright (C) 1996, 1999, International Business Machines Corporation // and others. All Rights Reserved. // You must accept the terms of that agreement to use this software. class Parser extends exprprs implements exprsym { final static int STACK_INCREMENT = 128; LexStream lex_stream; exprhdr actions = new exprhdr(this); int state_stack_top, stack[], location_stack[]; Ast parse_stack[]; // // Given a rule of the form A ::= x1 x2 ... xn n > 0 // // the function TOKEN(i) yields the symbol xi, if xi is a terminal // or ti, if xi is a nonterminal that produced a string of the form // xi => ti w. // final int TOKEN(int i) { return location_stack[state_stack_top + (i - 1)]; } // // Given a rule of the form A ::= x1 x2 ... xn n > 0 // // The function SYM(i) yields the AST subtree associated with symbol // xi. NOTE that if xi is a terminal, SYM(i) is undefined ! (However, // see token_action below.) // // setSYM1(Ast ast) is a function that allows us to assign an AST // tree to SYM(1). // final Ast SYM(int i) { return parse_stack[state_stack_top + (i - 1)]; } final void setSYM1(Ast ast) { parse_stack[state_stack_top] = ast; } // // When a token is shifted, we may wish to perform an action on // it. One possibility is to invoke "setSYM(null)" to associate // a null subtree with this terminal symbol. // void token_action(int tok) {} Parser(LexStream lex_stream) { this.lex_stream = lex_stream; } void reallocate_stacks() { int old_stack[] = stack; stack = new int[(old_stack == null ? 0 : old_stack.length) + STACK_INCREMENT]; if (old_stack != null) System.arraycopy(old_stack, 0, stack, 0, old_stack.length); old_stack = location_stack; location_stack = new int[(old_stack == null ? 0 : old_stack.length) + STACK_INCREMENT]; if (old_stack != null) System.arraycopy(old_stack, 0, location_stack, 0, old_stack.length); Ast old_parse_stack[] = parse_stack; parse_stack = new Ast[(old_parse_stack == null ? 0 : old_parse_stack.length) + STACK_INCREMENT]; if (old_parse_stack != null) System.arraycopy(old_parse_stack, 0, parse_stack, 0, old_parse_stack.length); return; } Ast parse() { lex_stream.Reset(); int curtok = lex_stream.Gettoken(), act = START_STATE, current_kind = lex_stream.Kind(curtok); /*****************************************************************/ /* Start parsing. */ /*****************************************************************/ state_stack_top = -1; ProcessTerminals: for (;;) { if (++state_stack_top >= (stack == null ? 0 : stack.length)) reallocate_stacks(); stack[state_stack_top] = act; location_stack[state_stack_top] = curtok; act = t_action(act, current_kind, lex_stream); if (act <= NUM_RULES) state_stack_top--; // make reduction look like a shift-reduce else if (act > ERROR_ACTION) { token_action(curtok); curtok = lex_stream.Gettoken(); current_kind = lex_stream.Kind(curtok); act -= ERROR_ACTION; } else if (act < ACCEPT_ACTION) { token_action(curtok); curtok = lex_stream.Gettoken(); current_kind = lex_stream.Kind(curtok); continue ProcessTerminals; } else break ProcessTerminals; ProcessNonTerminals: do { state_stack_top -= (rhs[act] - 1); actions.rule_action[act].action(); act = nt_action(stack[state_stack_top], lhs[act]); } while(act <= NUM_RULES); } if (act == ERROR_ACTION) { // // Recover or Scream or Whatever !!! // System.out.println("Error detected on token " + curtok); return null; } return parse_stack[0]; } } jikespg-1.3/examples/expr/Scanner.java000066400000000000000000000075131167345774400200710ustar00rootroot00000000000000// $Id: Scanner.java,v 1.3 1999/11/04 14:02:18 shields Exp $ // This software is subject to the terms of the IBM Jikes Compiler // License Agreement available at the following URL: // http://www.ibm.com/research/jikes. // Copyright (C) 1983, 1999, International Business Machines Corporation // and others. All Rights Reserved. // You must accept the terms of that agreement to use this software. // // The Scanner object // class Scanner implements exprsym { int next_byte; Option option; LexStream lex_stream; Scanner(Option option, LexStream lex_stream) { this.lex_stream = lex_stream; this.option = option; } // // // void skip_spaces() throws java.io.IOException { while (next_byte != '\n' && Character.isSpace((char) next_byte)) next_byte = System.in.read(); return; } // // // String scan_symbol() throws java.io.IOException { StringBuffer buffer = new StringBuffer(); while (next_byte != '\n' && (! Character.isSpace((char) next_byte))) { buffer.append((char) next_byte); } return buffer.toString(); } // // // void scan() throws java.io.IOException { // // Do not use token indexed at location 0. // Token start_token = new Token(); start_token.kind = 0; start_token.name = ""; lex_stream.tokens.addElement(start_token); next_byte = System.in.read(); for (skip_spaces(); next_byte != '\n'; skip_spaces()) { Token token = new Token(); switch(next_byte) { case '+': token.kind = TK_PLUS; token.name = "+"; break; case '-': token.kind = TK_MINUS; token.name = "-"; break; case '*': token.kind = TK_STAR; token.name = "*"; break; case '/': token.kind = TK_SLASH; token.name = "/"; break; case '(': token.kind = TK_LPAREN; token.name = "("; break; case ')': token.kind = TK_RPAREN; token.name = ")"; break; default: StringBuffer buffer = new StringBuffer(); if (! Character.isDigit((char) next_byte)) { token.kind = TK_ERROR; while (next_byte != '\n' && (! Character.isSpace((char) next_byte))) { buffer.append((char) next_byte); next_byte = System.in.read(); } System.out.println("The token \"" + buffer.toString() + "\" is illegal"); } else { token.kind = TK_NUMBER; do { buffer.append((char) next_byte); next_byte = System.in.read(); } while (next_byte != '\n' && Character.isDigit((char) next_byte)); } token.name = buffer.toString(); } if (token.kind != TK_ERROR && token.kind != TK_NUMBER) next_byte = System.in.read(); lex_stream.tokens.addElement(token); } Token end_token = new Token(); end_token.kind = TK_EOF; end_token.name = ""; lex_stream.tokens.addElement(end_token); return; } } jikespg-1.3/examples/expr/Token.java000066400000000000000000000007721167345774400175600ustar00rootroot00000000000000// $Id: Token.java,v 1.3 1999/11/04 14:02:18 shields Exp $ // This software is subject to the terms of the IBM Jikes Compiler // License Agreement available at the following URL: // http://www.ibm.com/research/jikes. // Copyright (C) 1983, 1999, International Business Machines Corporation // and others. All Rights Reserved. // You must accept the terms of that agreement to use this software. public class Token { int kind; String name; void set_name(String name) { this.name = name; } } jikespg-1.3/examples/expr/expr.g000066400000000000000000000116011167345774400167540ustar00rootroot00000000000000%Options gp=java,act,tab,an=expract.java,hn=exprhdr.java,tab=space,fp=expr,prefix=TK_, %Options nogoto-default,output-size=125,name=max,error-maps %Define -- This software is subject to the terms of the IBM Jikes Parser -- Generator License Agreement available at the following URL: -- http://www.ibm.com/research/jikes. -- Copyright (C) 1983, 1999, International Business Machines Corporation -- and others. All Rights Reserved. -- You must accept the terms of that agreement to use this software. -- This grammar has been augmented with productions that captures -- most errors that a user is likely to make. This saves the need -- to have an error recovery system. -- -- This macro is used to initialize the rule_action array -- to the null_action function. -- %null_action /. new NullAction(), ./ -- -- This macro is used to initialize the rule_action array -- to the no_action function. -- %no_action /. new NoAction(), ./ %Terminals PLUS MINUS STAR SLASH NUMBER LPAREN RPAREN EOF ERROR %Alias '+' ::= PLUS '-' ::= MINUS '*' ::= STAR '/' ::= SLASH '(' ::= LPAREN ')' ::= RPAREN %EOF ::= EOF %ERROR ::= ERROR %Rules /: class exprhdr extends expract { Action rule_action[] = { null, // no element 0 :/ /. class expract { Parser parser; expract(Parser parser) { this.parser = parser; } interface Action { public void action(); } final class NoAction implements Action { public void action() {} } final class NullAction implements Action { public void action() { parser.setSYM1(null); } } ./ Goal ::= %empty /:%null_action:/ Goal ::= Expression /:%no_action:/ Expression ::= Expression '+' Term /: new act%rule_number(),:/ /. // // Rule %rule_number: %rule_text // final class act%rule_number implements Action { public void action() { AstPlus node = new AstPlus(); node.left = parser.SYM(1); node.op = parser.TOKEN(2); node.right = parser.SYM(3); parser.setSYM1(node); return; } } ./ Expression ::= Expression '-' Term /: new act%rule_number(),:/ /. // // Rule %rule_number: %rule_text // final class act%rule_number implements Action { public void action() { AstMinus node = new AstMinus(); node.left = parser.SYM(1); node.op = parser.TOKEN(2); node.right = parser.SYM(3); parser.setSYM1(node); } } ./ Expression ::= Term /:%no_action:/ Term ::= Term '*' Factor /: new act%rule_number(),:/ /. // // Rule %rule_number: %rule_text // final class act%rule_number implements Action { public void action() { AstStar node = new AstStar(); node.left = parser.SYM(1); node.op = parser.TOKEN(2); node.right = parser.SYM(3); parser.setSYM1(node); } } ./ Term ::= Term '/' Factor /: new act%rule_number(),:/ /. // // Rule %rule_number: %rule_text // final class act%rule_number implements Action { public void action() { AstSlash node = new AstSlash(); node.left = parser.SYM(1); node.op = parser.TOKEN(2); node.right = parser.SYM(3); parser.setSYM1(node); } } ./ Term ::= Factor /:%no_action:/ Factor ::= NUMBER /: new act%rule_number(),:/ /. // // Rule %rule_number: %rule_text // final class act%rule_number implements Action { public void action() { AstNumber node = new AstNumber(); node.token = parser.TOKEN(1); node.value = Integer.parseInt(parser.lex_stream.Name(node.token)); parser.setSYM1(node); } } ./ Factor ::= '-' NUMBER /: new act%rule_number(),:/ /. // // Rule %rule_number: %rule_text // final class act%rule_number implements Action { public void action() { AstNegativeNumber node = new AstNegativeNumber(); node.op = parser.TOKEN(1); node.token = parser.TOKEN(2); node.value = - Integer.parseInt(parser.lex_stream.Name(node.token)); parser.setSYM1(node); } } ./ Factor ::= '(' Expression ')' /: new act%rule_number(),:/ /. // // Rule %rule_number: %rule_text // final class act%rule_number implements Action { public void action() { AstParen node = new AstParen(); node.expression = parser.SYM(2); parser.setSYM1(node); } } ./ /: }; exprhdr(Parser parser) { super(parser); } } :/ /. } ./ %End jikespg-1.3/jikespg.htm000066400000000000000000000132731167345774400152070ustar00rootroot00000000000000 Frequently Asked Questions About Jikes Parser Generator (January 27, 1999)

The IBM Research Jikes Compiler Project

http://www.ibm.com/research/jikes

Frequently Asked Questions About Jikes Parser Generator

January 27, 1999

What is Jikes Parser Generator?

Why is IBM Research making the source available?

What does IBM Research plan to do with the source?

What can I do with the source?

How do I compile the source?

How do I test the parser generator?

Do you have any program documentation?

How do I report bugs?

What is Jikes Parser Generator?

Jikes Parser Generator is the parser generator used by the Jikes Compiler. It takes as input an annotated version of the Java language grammar and produces as output program source and data that is part of the source for the Jikes compiler.

The current version is written in C and reflects its ancient origins; in particular, the parser generator was written at a time when memory was at a premium (work on it began over fifteen years ago), and was designed to be able to process a grammar for Ada in less that 300K running on an original model IBM PC.

Why is IBM Research making the source available?

IBM Research is releasing the source for the parser generator as a companion effort to the release of the source for the Jikes Compiler. The parser generator is used to generate some of the files that comprise the Jikes parser, and so its release makes the full source of the Jikes compiler available in a form not dependent on machine-generated code.

The release of JikesTM Parser Generator does not establish a policy for the rest of IBM outside of Research, nor does it define a standard Source License for Research. Other Source agreements from IBM, including IBM Research, if and when they do come, are likely to be more restrictive with respect to commercial use -- we are allowing almost any use for Jikes because we believe it benefits the Java community and doesn't give away any intellectual property.

What does IBM Research plan to do with the source?

We have no plans to actively work on the source right now, as we want to devote our efforts to improving the Jikes compiler.

If time permits, we would anticipate recoding the parser generator in a more modern language, most likely Java.

What can I do with the source?

Don't forget to read the license carefully. It explains in detail what you can and cannot do.

You can pretty much do whatever you want -- as long as we get some acknowledgment. You can distribute it in binary or source form, take all or part of it and put it in something else, and then redistribute it. It's all up to you.

However, IBM retains control of the names "IBM" and "JikesTM". You can't use them without our permission.

You are under no obligation to tell us what you are doing with the source, or to inform us of any changes you make.

How do I compile the source?

We provide a simple Makefile that works for the IBM AIX system. You will need to adapt it as necessary for other systems. This shouldn't be hard, as the parser generator is just a medium-sized c program that makes few demands on the standard libraries.

To build the source from scratch, do:

    cd jikespg/src
    make clean
    make

How do I test the parser generator?

Two small example programs are included with the parser generator source: bnf and expr.

To try bnf, a simple demonstration of a bnf parser, do:

    cd jikespg/examples/bnf
    make
    java Main example1.bnf
    java Main example2.bnf

To try expr, a simple Java expression evaluator, do:

    cd jikespg/examples/bnf
    make
    java Main 

and type in sample expressions, such as 2+4 when prompted.

You can also bootstrap the parser generator. First, note the size of the executable, then do:

    jikespg jikespg.g
    make
and see if the size of the executable is the same (it should be).

You can try it with Jikes as follows:

    cd jikes/src
    touch java.g
    jikespg java
The files produced by running jikespg should agree with the versions that were present before running jikespg.

Do you have any program documentation?

All that is availalble now is the source. As is common with many works in progress, we have only had time to comment the source as it has evolved.

How do I report bugs?

Please send mail to the mail list jikes-bugs@watson.ibm.com. You need to subscribe to this list before you can post mail; instructions on how to subscribe can be found at http://www.ibm.com/research/jikes/subscribe. Note that only minimal support, indeed possibly no support at all, is offered at the present time. jikespg-1.3/license.htm000066400000000000000000000271561167345774400152020ustar00rootroot00000000000000 IBM PUBLIC LICENSE VERSION 1.0 - JIKES COMPILER

IBM PUBLIC LICENSE VERSION 1.0 - JIKES COMPILER

THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS IBM PUBLIC LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT.

1. DEFINITIONS

"Contribution" means:

  1. in the case of International Business Machines Corporation ("IBM"), the Original Program, and
  2. in the case of each Contributor,
    1. changes to the Program, and
    2. additions to the Program;
    where such changes and/or additions to the Program originate from and are distributed by that particular Contributor. A Contribution 'originates' from a Contributor if it was added to the Program by such Contributor itself or anyone acting on such Contributor's behalf. Contributions do not include additions to the Program which: (i) are separate modules of software distributed in conjunction with the Program under their own license agreement, and (ii) are not derivative works of the Program.

"Contributor" means IBM and any other entity that distributes the Program.

"Licensed Patents " mean patent claims licensable by a Contributor which are necessarily infringed by the use or sale of its Contribution alone or when combined with the Program.

"Original Program" means the original version of the software accompanying this Agreement as released by IBM, including source code, object code and documentation, if any.

"Program" means the Original Program and Contributions.

"Recipient" means anyone who receives the Program under this Agreement, including all Contributors.

2. GRANT OF RIGHTS

  1. Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free copyright license to reproduce, prepare derivative works of, publicly display, publicly perform, distribute and sublicense the Contribution of such Contributor, if any, and such derivative works, in source code and object code form.
  2. Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free patent license under Licensed Patents to make, use, sell, offer to sell, import and otherwise transfer the Contribution of such Contributor, if any, in source code and object code form. This patent license shall apply to the combination of the Contribution and the Program if, at the time the Contribution is added by the Contributor, such addition of the Contribution causes such combination to be covered by the Licensed Patents. The patent license shall not apply to any other combinations which include the Contribution. No hardware per se is licensed hereunder.
  3. Recipient understands that although each Contributor grants the licenses to its Contributions set forth herein, no assurances are provided by any Contributor that the Program does not infringe the patent or other intellectual property rights of any other entity. Each Contributor disclaims any liability to Recipient for claims brought by any other entity based on infringement of intellectual property rights or otherwise. As a condition to exercising the rights and licenses granted hereunder, each Recipient hereby assumes sole responsibility to secure any other intellectual property rights needed, if any. For example, if a third party patent license is required to allow Recipient to distribute the Program, it is Recipient's responsibility to acquire that license before distributing the Program.
  4. Each Contributor represents that to its knowledge it has sufficient copyright rights in its Contribution, if any, to grant the copyright license set forth in this Agreement.

3. REQUIREMENTS

A Contributor may choose to distribute the Program in object code form under its own license agreement, provided that:
  1. it complies with the terms and conditions of this Agreement; and
  2. its license agreement:
    1. effectively disclaims on behalf of all Contributors all warranties and conditions, express and implied, including warranties or conditions of title and non-infringement, and implied warranties or conditions of merchantability and fitness for a particular purpose;
    2. effectively excludes on behalf of all Contributors all liability for damages, including direct, indirect, special, incidental and consequential damages, such as lost profits;
    3. states that any provisions which differ from this Agreement are offered by that Contributor alone and not by any other party; and
    4. states that source code for the Program is available from such Contributor, and informs licensees how to obtain it in a reasonable manner on or through a medium customarily used for software exchange.
When the Program is made available in source code form:
  1. it must be made available under this Agreement; and
  2. a copy of this Agreement must be included with each copy of the Program.
Each Contributor must include the following in a conspicuous location in the Program:
Copyright (C) 1996, 1999 International Business Machines Corporation and others. All Rights Reserved.

In addition, each Contributor must identify itself as the originator of its Contribution, if any, in a manner that reasonably allows subsequent Recipients to identify the originator of the Contribution.

4. COMMERCIAL DISTRIBUTION

Commercial distributors of software may accept certain responsibilities with respect to end users, business partners and the like. While this license is intended to facilitate the commercial use of the Program, the Contributor who includes the Program in a commercial product offering should do so in a manner which does not create potential liability for other Contributors. Therefore, if a Contributor includes the Program in a commercial product offering, such Contributor ("Commercial Contributor") hereby agrees to defend and indemnify every other Contributor ("Indemnified Contributor") against any losses, damages and costs (collectively "Losses") arising from claims, lawsuits and other legal actions brought by a third party against the Indemnified Contributor to the extent caused by the acts or omissions of such Commercial Contributor in connection with its distribution of the Program in a commercial product offering. The obligations in this section do not apply to any claims or Losses relating to any actual or alleged intellectual property infringement. In order to qualify, an Indemnified Contributor must: a) promptly notify the Commercial Contributor in writing of such claim, and b) allow the Commercial Contributor to control, and cooperate with the Commercial Contributor in, the defense and any related settlement negotiations. The Indemnified Contributor may participate in any such claim at its own expense.

For example, a Contributor might include the Program in a commercial product offering, Product X. That Contributor is then a Commercial Contributor. If that Commercial Contributor then makes performance claims, or offers warranties related to Product X, those performance claims and warranties are such Commercial Contributor's responsibility alone. Under this section, the Commercial Contributor would have to defend claims against the other Contributors related to those performance claims and warranties, and if a court requires any other Contributor to pay any damages as a result, the Commercial Contributor must pay those damages.

5. NO WARRANTY

EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely responsible for determining the appropriateness of using and distributing the Program and assumes all risks associated with its exercise of rights under this Agreement, including but not limited to the risks and costs of program errors, compliance with applicable laws, damage to or loss of data, programs or equipment, and unavailability or interruption of operations.

6. DISCLAIMER OF LIABILITY

EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.

7. GENERAL

If any provision of this Agreement is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this Agreement, and without further action by the parties hereto, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable.

If Recipient institutes patent litigation against a Contributor with respect to a patent applicable to software (including a cross-claim or counterclaim in a lawsuit), then any patent licenses granted by that Contributor to such Recipient under this Agreement shall terminate as of the date such litigation is filed. In addition, if Recipient institutes patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Program itself (excluding combinations of the Program with other software or hardware) infringes such Recipient's patent(s), then such Recipient's rights granted under Section 2(b) shall terminate as of the date such litigation is filed.

All Recipient's rights under this Agreement shall terminate if it fails to comply with any of the material terms or conditions of this Agreement and does not cure such failure in a reasonable period of time after becoming aware of such noncompliance. If all Recipient's rights under this Agreement terminate, Recipient agrees to cease use and distribution of the Program as soon as reasonably practicable. However, Recipient's obligations under this Agreement and any licenses granted by Recipient relating to the Program shall continue and survive.

IBM may publish new versions (including revisions) of this Agreement from time to time. Each new version of the Agreement will be given a distinguishing version number. The Program (including Contributions) may always be distributed subject to the version of the Agreement under which it was received. In addition, after a new version of the Agreement is published, Contributor may elect to distribute the Program (including its Contributions) under the new version. No one other than IBM has the right to modify this Agreement. Except as expressly stated in Sections 2(a) and 2(b) above, Recipient receives no rights or licenses to the intellectual property of any Contributor under this Agreement, whether expressly, by implication, estoppel or otherwise. All rights in the Program not expressly granted under this Agreement are reserved.

This Agreement is governed by the laws of the State of New York and the intellectual property laws of the United States of America. No party to this Agreement will bring a legal action under this Agreement more than one year after the cause of action arose. Each party waives its rights to a jury trial in any resulting litigation. jikespg-1.3/src/000077500000000000000000000000001167345774400136225ustar00rootroot00000000000000jikespg-1.3/src/ChangeLog000066400000000000000000000002461167345774400153760ustar00rootroot000000000000001999-11-08 * Initial version. * This is the Jikes Parser Generator. * The license used is now the IBM Public License Version 1.0 jikespg-1.3/src/Makefile000066400000000000000000000042411167345774400152630ustar00rootroot00000000000000# $Id: Makefile,v 1.4 2001/10/10 14:53:10 ericb Exp $ # # This software is subject to the terms of the IBM Jikes Compiler # License Agreement available at the following URL: # http://ibm.com/developerworks/opensource/jikes. # Copyright (C) 1983, 1999, 2001 International Business # Machines Corporation and others. All Rights Reserved. # You must accept the terms of that agreement to use this software. # Makefile for aix for Jikes Parser Generator CC = gcc -O1 all: jikespg jikespg: ctabs.o globals.o lpgparse.o lpgutil.o main.o \ mkfirst.o mkred.o mkstates.o partset.o prntstat.o produce.o \ ptables.o remsp.o resolve.o spacetab.o tabutil.o timetab.o $(CC) -s -o jikespg ctabs.o globals.o lpgparse.o lpgutil.o main.o \ mkfirst.o mkred.o mkstates.o partset.o prntstat.o produce.o \ ptables.o remsp.o resolve.o spacetab.o tabutil.o timetab.o lpgact.i: jikespg.g lpg jikespg rm jikespg.l make rm CRASH_THE_INITIAL_MAKE_COMMAND_TO_BREAK_OUT main.o: main.c common.h $(CC) -c main.c globals.o: globals.c common.h $(CC) -c globals.c lpgparse.o: lpgprs.h lpgdcl.h lpgdef.h lpgact.h lpgact.i lpgsym.h \ common.h lpgparse.h lpgparse.c $(CC) -c lpgparse.c lpgutil.o: lpgutil.c common.h $(CC) -c lpgutil.c mkfirst.o: mkfirst.c common.h $(CC) -c mkfirst.c mkstates.o: mkstates.c common.h $(CC) -c mkstates.c prntstat.o: prntstat.c common.h $(CC) -c prntstat.c mkred.o: mkred.c common.h reduce.h $(CC) -c mkred.c remsp.o: remsp.c common.h reduce.h $(CC) -c remsp.c resolve.o: resolve.c common.h reduce.h $(CC) -c resolve.c ptables.o: ptables.c common.h $(CC) -c ptables.c spacetab.o: spacetab.c common.h space.h $(CC) -c spacetab.c timetab.o: timetab.c common.h $(CC) -c timetab.c tabutil.o: tabutil.c common.h $(CC) -c tabutil.c produce.o: produce.c common.h $(CC) -c produce.c partset.o: partset.c common.h $(CC) -c partset.c ctabs.o: ctabs.c common.h space.h $(CC) -c ctabs.c clean: rm jikespg rm ctabs.o rm globals.o rm lpgparse.o rm lpgutil.o rm main.o rm mkfirst.o rm mkred.o rm mkstates.o rm partset.o rm prntstat.o rm produce.o rm ptables.o rm remsp.o rm resolve.o rm spacetab.o rm tabutil.o rm timetab.o jikespg-1.3/src/Makefile.am000066400000000000000000000015361167345774400156630ustar00rootroot00000000000000bin_PROGRAMS = jikespg jikespg_SOURCES = ctabs.c \ globals.c \ lpgparse.c \ lpgutil.c \ main.c \ mkfirst.c \ mkred.c \ mkstates.c \ partset.c \ prntstat.c \ produce.c \ ptables.c \ remsp.c \ resolve.c \ spacetab.c \ tabutil.c \ timetab.c noinst_HEADERS = c370.h \ common.h \ header.h \ lpgact.h \ lpgact.i \ lpgdcl.h \ lpgdef.h \ lpgparse.h \ lpgprs.h \ lpgsym.h \ reduce.h \ space.h jikespg-1.3/src/c370.h000066400000000000000000000235221167345774400144530ustar00rootroot00000000000000/* $Id: c370.h,v 1.2 1999/11/04 14:02:21 shields Exp $ */ /* This software is subject to the terms of the IBM Jikes Compiler License Agreement available at the following URL: http://www.ibm.com/research/jikes. Copyright (C) 1983, 1999, International Business Machines Corporation and others. All Rights Reserved. You must accept the terms of that agreement to use this software. */ #ifndef C370_INCLUDED #define C370_INCLUDED #if defined(C370) || defined(CW) #define accept_act acc_act #define accept_image accptimg #define action_bit actn_bit #define action_pool act_pool #define action_size act_size #define action_symbols actsymbs #define action_symbols actsymbs #define action_symbols_index_proc asiproc #define adequate_item adqitem #define allocate_boolean_array alcbooln #define allocate_int_array alocint #define allocate_short_array alocshrt #define allocate_goto_map alcgotmp #define allocate_node alocnode #define allocate_reduce_map alcredmp #define allocate_shift_map alcshfmp #define allocate_sr_conflict_element alcsrcnf #define allocate_rr_conflict_element alcrrcnf #define automatic_scope_procs autoscpr #define byte_terminal_range bytterg #define check_size chksize #define compute_action_symbols_range compasr #define compute_closure compclo #define compute_first compfrst #define compute_follow compfoll #define compute_goto_default c_goto_def #define compute_la cmpt_la #define compute_naction_symbols_range compnasr #define compute_next_conflict_set cnc_set #define compute_next_conflict_source cncsrce #define compute_next_la c_nxt_la #define compute_shift_default cmp_shift_def #define conflict_pool cnflpool #define conflicts_bit conflbit #define conflicts_initialization_done cid #define debug_bit dbugbit #define declarations declratn #define default_opt def_opt #define deferred_bit dfrdbit #define deferred_parser_loop defprslp #define deferred_recovery_proc defreclp #define dump_tables dumptabs #define eoft_conflict_trace eoftctr #define eoft_image eoftimge #define eolt_image eolimag #define error_act er_act #define error_image errorimg #define error_maps_bit errmpbit #define error_procs errprocs #define exit_lalrk_process exitlak #define init_lalrk_process initlak #define init_rmpself initrmp #define file_prefix flprefx #define first_bit firstbit #define first_index frstindx #define follow_bit follwbit #define free_conflict_space freecsp #define free_nodes freenode #define free_temporary_space freetspa #define global_declarations globldcl #define global_space_allocated gspalloc #define global_space_used gspausd #define goto_default_bit gdefbit #define goto_size gotosize #define gotodom_size godm_sze #define hact_file hactfile #define highest_level highstlv #define increment incremt #define increment_size incrsze #define item_list itemlist #define item_table itemtabl #define la_offset laoffset #define la_state_root lastatrt #define la_traverse latravrs #define lalr_level lalrlevl #define last_index lastindx #define last_non_terminal lstnontr #define last_symbol lastsymb #define last_terminal lastterm #define lpgaccess laccess #define macro_declarations macrdecl #define manual_scope_procs manlscpr #define max_la_state mxlastat #define max_name_length maxnmlen #define maximum_distance maxdist #define minimum_distance mindist #define naction_symbols nactnsym #define naction_symbols nactnsym #define naction_symbols_index_proc nasiproc #define names_opt namesopt #define new_state_element newstelm #define new_state_elemt nwstelmt #define no_error_procs noerprcs #define non_term_set_size ntsetsiz #define nt_check_bit ntchkbit #define num_entries n_entrys #define num_error_rules nerrule #define num_first_sets nfrstset #define num_goto_reduces n_gotord #define num_gotos numgotos #define num_items n_items #define num_names n_names #define num_non_terminals n_nontml #define num_reductions n_redctn #define num_rr_conflicts n_rrcnfl #define num_rules n_rules #define num_scopes numscps #define num_shift_maps nshftmap #define num_shift_reduces n_shred #define num_shifts n_shifts #define num_single_productions n_sngprd #define num_sr_conflicts n_sr_cnf #define num_states n_states #define num_symbols n_syms #define num_table_entries ntabentr #define num_terminal_states nterm_st #define num_terminals n_termnl #define number_len numlen #define ordered_state ordstat #define output_buffer outbuf #define output_line_no oplnnum #define output_ptr outptr #define output_size outptsz #define overlap_nt_rows ovrlntrw #define overlap_t_rows ovrlptrw #define overlap_tables ovrltabl #define overlay_sim_t_rows ostermrw #define parser_loop prsrloop #define previous prevs #define primary_threshold primthr #define print_space_parser prcsppr #define print_time_parser prctimp #define print_item prntitem #define print_large_token prlrgtok #define print_relevant_slr_items prslritm #define print_state pr_state #define process_conflicts pcnflcts #define process_error_maps perrmps #define process_input prc_inpt #define process_tables p_tables #define read_input readinpt #define read_reduce_bit rdredbit #define real_shift_number rshifnm #define reallocate rallcte #define record_format recrdfmt #define reduce_list red_lst #define reduce_root red_root #define reduce_size redcesz #define remove_single_productions remsp #define reset_temporary_space resettsp #define resolve_conflicts rslvconf #define restore_symbol restsym #define rr_conflict_root rrcnflrt #define scope_rhs_size scrhssz #define scope_right_side scrtsde #define scope_state scpstat #define scope_state_size scstsze #define scopes_bit scpbit #define secondary_threshold secthrd #define shift_check_index shchindx #define shift_check_size shchksz #define shift_default_bit shdefbit #define shift_domain_count shdmn_ct #define shift_image shimage #define shift_size shftsize #define single_productions_bit sp_bit #define sr_conflict_root srcnflrt #define stack_size stksize #define stat_list statlist #define state_index statindx #define state_list statelst #define state_set_size ssetsiz #define states_bit statesbt #define states_of st_of #define string_offset stroffst #define string_size strsize #define string_table s_tab #define symbol_map symbmap #define symno_size symno_sz #define table_opt tab_opt #define table_size tab_size #define temporary_space_allocated tspalloc #define temporary_space_used tspausd #define term_action_size t_act_sz #define term_check_size t_ch_sze #define term_set_size tsetsiz #define term_state_index tstindx #define trace_access traceac #define trace_opt trce_opt #define trace_pool trace_pl #define translate trnslte #define verbose_bit verb_bit #define warnings_bit warnbit #endif #endif /* C370_INCLUDED */ jikespg-1.3/src/common.h000066400000000000000000001002031167345774400152570ustar00rootroot00000000000000/* $Id: common.h,v 1.4 2001/10/10 14:53:10 ericb Exp $ */ /* This software is subject to the terms of the IBM Jikes Compiler License Agreement available at the following URL: http://ibm.com/developerworks/opensource/jikes. Copyright (C) 1983, 1999, 2001 International Business Machines Corporation and others. All Rights Reserved. You must accept the terms of that agreement to use this software. */ #ifndef COMMON_INCLUDED #define COMMON_INCLUDED /*******************************************************************/ /* One of the switches below may have to be set prior to building */ /* JIKES PG. OS2 is for all C compilers running under OS2. DOS is */ /* for all C compilers running under DOS. Note that to run under */ /* DOS, the compiler used must support the Huge model (32-bit ptr */ /* simulation). C370 is for the IBM C compiler running under CMS */ /* or MVS. CW is for the Waterloo C compiler running under VM/CMS. */ /* */ /* This system was built to run on a vanilla Unix or AIX system. */ /* No switch need to be set for such an environment. Set other */ /* switch(es) as needed. Note that the switch C370 should always */ /* be accompanied by either the switch VM or the switch MVS. */ /* */ /*******************************************************************/ /* #define DOS #define OS2 #define MVS #define CW #define C370 #define VM */ #include #include #include #include #include #include "c370.h" /*******************************************************************/ /*******************************************************************/ /** **/ /** GLOBAL CONSTANTS **/ /** **/ /*******************************************************************/ /*******************************************************************/ #define PR_HEADING \ { \ fprintf(syslis, "\f\n\n %-39s%s %-30.24s Page %d\n\n",\ HEADER_INFO, VERSION, timeptr, ++page_no);\ output_line_no = 4;\ } #define MAX_PARM_SIZE 22 #define SYMBOL_SIZE 256 #define MAX_MSG_SIZE (256 + SYMBOL_SIZE) #define PRINT_LINE_SIZE 80 #define PARSER_LINE_SIZE 80 #define MAX_LINE_SIZE 256 #undef PAGE_SIZE #define PAGE_SIZE 55 #define OPTIMIZE_TIME 1 #define OPTIMIZE_SPACE 2 #define MINIMUM_NAMES 1 #define MAXIMUM_NAMES 2 #define OPTIMIZE_PHRASES 3 #define NOTRACE 0 #define TRACE_CONFLICTS 1 #define TRACE_FULL 2 #define STATE_TABLE_UBOUND 1020 #define STATE_TABLE_SIZE (STATE_TABLE_UBOUND + 1) /* 1021 is a prime */ #define SHIFT_TABLE_UBOUND 400 #define SHIFT_TABLE_SIZE (SHIFT_TABLE_UBOUND + 1) /* 401 is a prime */ #define SCOPE_UBOUND 100 #define SCOPE_SIZE (SCOPE_UBOUND + 1) /* 101 is prime */ #undef FALSE #undef TRUE #define FALSE 0 #define TRUE 1 #define IS_A_TERMINAL <= num_terminals #define IS_A_NON_TERMINAL > num_terminals #define SPACE ' ' #define COMMA ',' #define INFINITY ((short) SHRT_MAX) #define OMEGA ((short) SHRT_MIN) #define NIL ((short) SHRT_MIN + 1) #define DEFAULT_SYMBOL 0 /*******************************************************************/ /*******************************************************************/ /** **/ /** ALLOCATE/FREE MACROS **/ /** **/ /*******************************************************************/ /*******************************************************************/ /* The following macro definitions are used to preprocess calls to */ /* allocate routines that require locations. The FFREE macro is */ /* normally an invocation to the FREE routine. It is encoded as */ /* a macro here in case we need to do some debugging on dynamic */ /* storage. */ /*******************************************************************/ #define Allocate_node() allocate_node(hostfile, __LINE__) #define Allocate_int_array(n) allocate_int_array(n, hostfile, __LINE__) #define Allocate_short_array(n) allocate_short_array(n, hostfile, __LINE__) #define Allocate_boolean_array(n) allocate_boolean_array(n, hostfile, __LINE__) #define Allocate_goto_map(n) allocate_goto_map(n, hostfile, __LINE__) #define Allocate_shift_map(n) allocate_shift_map(n, hostfile, __LINE__) #define Allocate_reduce_map(n) allocate_reduce_map(n, hostfile, __LINE__) #define ffree(x) free(x) /* { free(x); x = (void *) ULONG_MAX; } */ /*******************************************************************/ /*******************************************************************/ /** **/ /** PARSING MACROS **/ /** **/ /*******************************************************************/ /*******************************************************************/ /* The following macro definitions are used only in processing the */ /* input source. */ /*******************************************************************/ #define EQUAL_STRING(symb, p) \ (strcmp((symb), string_table + (p) -> st_ptr) == 0) #define EXTRACT_STRING(indx) (&string_table[indx]) #define HT_SIZE 701 /* 701 is a prime */ #define RULEHDR_INCREMENT 1024 #define ACTELMT_INCREMENT 1024 #define DEFELMT_INCREMENT 16 #ifdef DOS #define IOBUFFER_SIZE 8192 #else #define IOBUFFER_SIZE 65536 #endif /*******************************************************************/ /*******************************************************************/ /** **/ /** BIT SET MACROS **/ /** **/ /*******************************************************************/ /*******************************************************************/ /* The following macros are used to define operations on sets that */ /* are represented as bit-strings. BOOLEAN_CELL is a type that is */ /* used as the elemental unit used to construct the sets. For */ /* example, if BOOLEAN_CELL consists of four bytes and assumming */ /* that each byte contains 8 bits then the constant SIZEOF_BC */ /* represents the total number of bits that is contained in each */ /* elemental unit. */ /* */ /* In general, a parameter called "set" or "set"i, where i is an */ /* integer, is a pointer to a set or array of sets; a parameter */ /* called "i" or "j" represents an index in an array of sets; a */ /* parameter called "b" represents a particular element (or bit) */ /* within a set. */ /* */ /*******************************************************************/ #define SIZEOF_BC (sizeof(BOOLEAN_CELL) * CHAR_BIT) #define BC_OFFSET (SIZEOF_BC - 1) /*******************************************************************/ /* This macro takes as argument an array of bit sets called "set", */ /* an integer "nt" indicating the index of a particular set in the */ /* array and an integer "t" indicating a particular element within */ /* the set. IS_IN_SET check whether ot not the element "t" is in */ /* the set "set(nt)". */ /* */ /* The value (nt*term_set_size) is used to determine the starting */ /* address of the set element in question. The value */ /* (??? / SIZEOF_BC) is used to determine the actual BOOLEAN_CELL */ /* containing the bit in question. Finally, the value */ /* (SIZEOF_BC - (t % SIZEOF_BC)) identifies the actual bit in the */ /* unit. The bit in question is pushed to the first position and */ /* and-ed with the value 01. This operation yields the value TRUE */ /* if the bit is on. Otherwise, the value FALSE is obtained. */ /* Recall that in C, one cannot shift (left or right) by 0. This */ /* is why the ? is used here. */ /*******************************************************************/ #define IS_IN_SET(set, i, b) /* is b in set[i] ? */ \ ((set)[(i) * term_set_size + (((b) - 1) / SIZEOF_BC)] & \ (((b) + BC_OFFSET) % SIZEOF_BC ? \ (BOOLEAN_CELL) 1 << (((b) + BC_OFFSET) % SIZEOF_BC) : \ (BOOLEAN_CELL) 1)) /*******************************************************************/ /* The macro SET_UNION takes as argument two arrays of sets: */ /* "set1" and "set2", and two integers "i" and "j" which are */ /* indices to be used to access particular sets in "set1" and */ /* "set2", respectively. SET_UNION computes the union of the two */ /* sets in question and places the result in the relevant set in */ /* "set1". */ /* */ /* The remaining macros are either analoguous to IS_IN_SET or */ /* SET_UNION. */ /* */ /* Note that a macro with the variable "kji" declared in its body */ /* should not be invoked with a parameter of the same name. */ /* */ /*******************************************************************/ #define SET_UNION(set1, i, set2, j) /* set[i] union set2[j] */ \ { \ register int kji; \ for (kji = 0; kji < term_set_size; kji++) \ (set1)[(i) * term_set_size + kji] |= \ (set2)[(j) * term_set_size + kji]; \ } #define INIT_SET(set) /* set = {} */ \ { \ register int kji; \ for (kji = 0; kji < term_set_size; kji++) \ (set)[kji] = 0; \ } #define ASSIGN_SET(set1, i, set2, j) /* set1[i] = set2[j] */ \ { \ register int kji; \ for (kji = 0; kji < term_set_size; kji++) \ (set1)[(i) * term_set_size + kji] = \ (set2)[(j) * term_set_size + kji]; \ } #define SET_BIT_IN(set, i, b) /* set[i] = set[i] with b; */ \ (set)[(i) * term_set_size + (((b) - 1) / SIZEOF_BC)] |= \ (((b) + BC_OFFSET) % SIZEOF_BC ? \ (BOOLEAN_CELL) 1 << (((b) + BC_OFFSET) % SIZEOF_BC) : \ (BOOLEAN_CELL) 1); #define RESET_BIT_IN(set, i, b) /* set[i] = set[i] less b; */ \ (set)[(i) * term_set_size + (((b) - 1) / SIZEOF_BC)] &= \ ~(((b) + BC_OFFSET) % SIZEOF_BC ? \ (BOOLEAN_CELL) 1 << (((b) + BC_OFFSET) % SIZEOF_BC): \ (BOOLEAN_CELL) 1); /*******************************************************************/ /* The following macros are analogous to the ones above, except */ /* that they deal with sets of non-terminals instead of sets of */ /* terminals. */ /*******************************************************************/ #define IS_IN_NTSET(set, i, b) /* is b in set[i] ? */ \ ((set)[(i) * non_term_set_size + (((b) - 1) / SIZEOF_BC)] & \ (((b) + BC_OFFSET) % SIZEOF_BC ? \ (BOOLEAN_CELL) 1 << (((b) + BC_OFFSET) % SIZEOF_BC) : \ (BOOLEAN_CELL) 1)) #define NTSET_UNION(set1, i, set2, j) /* set1[i] union set2[j] */ \ { \ register int kji; \ for (kji = 0; kji < non_term_set_size; kji++) \ (set1)[(i) * non_term_set_size + kji] |= \ (set2)[(j) * non_term_set_size + kji]; \ } #define INIT_NTSET(set) /* set = {} */ \ { \ register int kji; \ for (kji = 0; kji < non_term_set_size; kji++) \ (set)[kji] = 0; \ } #define ASSIGN_NTSET(set1, i, set2, j) /* set1[i] = set2[j] */ \ { \ register int kji; \ for (kji = 0; kji < non_term_set_size; kji++) \ (set1)[(i) * non_term_set_size + kji] = \ (set2)[(j) * non_term_set_size + kji]; \ } #define NTSET_BIT_IN(set, i, b) /* set[i] = set[i] with b; */ \ (set)[(i) * non_term_set_size + (((b) - 1) / SIZEOF_BC)] |= \ (((b) + BC_OFFSET) % SIZEOF_BC ? \ (BOOLEAN_CELL) 1 << (((b) + BC_OFFSET) % SIZEOF_BC) : \ (BOOLEAN_CELL) 1); #define NTRESET_BIT_IN(set, i, b) /* set[i] = set[i] less b; */ \ (set)[(i) * non_term_set_size + (((b) - 1) / SIZEOF_BC)] &= \ ~(((b) + BC_OFFSET) % SIZEOF_BC ? \ (BOOLEAN_CELL) 1 << (((b) + BC_OFFSET) % SIZEOF_BC): \ (BOOLEAN_CELL) 1); /*******************************************************************/ /* The following macros are analogous to the ones above, except */ /* that they deal with sets of states instead of sets of terminals */ /* or non-terminals. */ /*******************************************************************/ #define SET_COLLECTION_BIT(i, b) \ collection[(i) * state_set_size + (((b) - 1) / SIZEOF_BC)] |= \ (((b) + BC_OFFSET) % SIZEOF_BC ? \ (BOOLEAN_CELL) 1 << (((b) + BC_OFFSET) % SIZEOF_BC) : \ (BOOLEAN_CELL) 1); #define EMPTY_COLLECTION_SET(i) \ { \ register int kji; \ for (kji = 0; kji < state_set_size; kji++) \ collection[(i) * state_set_size + kji] = 0; \ } /*******************************************************************/ /* The following macros can be used to check, set, or reset a bit */ /* in a bit-string of any length. */ /*******************************************************************/ #define SET_BIT(set, b) \ (set)[((b) - 1) / SIZEOF_BC] |= \ (((b) + BC_OFFSET) % SIZEOF_BC ? \ (BOOLEAN_CELL) 1 << (((b) + BC_OFFSET) % SIZEOF_BC) : \ (BOOLEAN_CELL) 1); #define RESET_BIT(set, b) \ (set)[((b) - 1) / SIZEOF_BC] &= \ ~(((b) + BC_OFFSET) % SIZEOF_BC ? \ (BOOLEAN_CELL) 1 << (((b) + BC_OFFSET) % SIZEOF_BC): \ (BOOLEAN_CELL) 1); #define IS_ELEMENT(set, b) /* is b in set ? */ \ ((set)[((b) - 1) / SIZEOF_BC] & \ (((b) + BC_OFFSET) % SIZEOF_BC ? \ (BOOLEAN_CELL) 1 << (((b) + BC_OFFSET) % SIZEOF_BC) : \ (BOOLEAN_CELL) 1)) /*******************************************************************/ /*******************************************************************/ /** **/ /** ITERATION MACROS **/ /** **/ /*******************************************************************/ /*******************************************************************/ /* The following macros (ALL_) are used to iterate over a sequence.*/ /*******************************************************************/ #define ALL_LA_STATES(indx) \ (indx = num_states + 1; indx <= (int) max_la_state; indx++) #define ALL_TERMINALS(indx) \ (indx = 1; indx <= num_terminals; indx++) #define ALL_TERMINALS_BACKWARDS(indx) \ (indx = num_terminals; indx >= 1; indx--) #define ALL_NON_TERMINALS(indx) \ (indx = num_terminals + 1; indx <= num_symbols; indx++) #define ALL_NON_TERMINALS_BACKWARDS(indx) \ (indx = num_symbols; indx >= num_terminals + 1; indx--) #define ALL_SYMBOLS(indx) (indx = 1; indx <= num_symbols; indx++) #define ALL_ITEMS(indx) (indx = 1; indx <= (int) num_items; indx++) #define ALL_STATES(indx) (indx = 1; indx <= (int) num_states; indx++) #define ALL_RULES(indx) (indx = 0; indx <= num_rules; indx++) #define ALL_RULES_BACKWARDS(indx) \ (indx = num_rules; indx >= 0; indx--) #define ENTIRE_RHS(indx, rule_no) (indx = rules[rule_no].rhs;\ indx < rules[(rule_no) + 1].rhs;\ indx++) #define RHS_SIZE(rule_no) (rules[(rule_no) + 1].rhs - rules[rule_no].rhs) #define RETRIEVE_STRING(indx) (&string_table[symno[indx].ptr]) #define RETRIEVE_NAME(indx) (&string_table[name[indx]]) /*******************************************************************/ /*******************************************************************/ /** **/ /** MISCELLANEOUS MACROS **/ /** **/ /*******************************************************************/ /*******************************************************************/ #define TOUPPER(c) (islower(c) ? toupper(c) : c) #define MAX(a,b) (((a) > (b)) ? (a) : (b)) #define MIN(a,b) (((a) < (b)) ? (a) : (b)) #define ABS(x) (((x) < 0) ? -(x) : (x)) #define NOT(item) (! item) /**********************************************************************/ /* The following two macros check whether or not the value of an */ /* integer variable exceeds the maximum limit for a short or a long */ /* integer, respectively. Note that the user should declare the */ /* variable in question as a long integer. In the case of INT_CHECK, */ /* this check is meaningful only if INT and SHORT are the same size. */ /* Otherwise, if INT and LONG are of the same size, as is usually the */ /* case on large systems, this check is meaningless - too late !!! */ /**********************************************************************/ #define SHORT_CHECK(var) \ if (var > SHRT_MAX) \ { \ PRNTERR("The limit of a short int value" \ " has been exceeded by " #var); \ exit(12); \ } #define INT_CHECK(var) \ if (var > INT_MAX) \ { \ PRNTERR("The limit of an int value" \ " has been exceeded by " #var); \ exit(12); \ } #define ENDPAGE_CHECK if (++output_line_no >= PAGE_SIZE) \ PR_HEADING #define PRNT(msg) \ { \ printf("%s\n",msg); \ fprintf(syslis,"%s\n",msg); \ ENDPAGE_CHECK; \ } #define PRNTWNG(msg) \ { \ printf("***WARNING: %s\n",msg);\ fprintf(syslis,"***WARNING: %s\n",msg);\ ENDPAGE_CHECK; \ } #define PRNTERR(msg) \ { \ printf("***ERROR: %s\n",msg);\ fprintf(syslis,"***ERROR: %s\n",msg);\ ENDPAGE_CHECK; \ } /*******************************************************************/ /*******************************************************************/ /** **/ /** MACROS FOR DEREFERENCING AUTOMATON HEADER STRUCTURES **/ /** **/ /*******************************************************************/ /*******************************************************************/ #define SHIFT_SYMBOL(hdr, indx) (((hdr).map)[indx].symbol) #define SHIFT_ACTION(hdr, indx) (((hdr).map)[indx].action) #define GOTO_SYMBOL(hdr, indx) (((hdr).map)[indx].symbol) #define GOTO_ACTION(hdr, indx) (((hdr).map)[indx].action) #define GOTO_LAPTR(hdr, indx) (((hdr).map)[indx].laptr) #define REDUCE_SYMBOL(hdr, indx) (((hdr).map)[indx].symbol) #define REDUCE_RULE_NO(hdr, indx) (((hdr).map)[indx].rule_number) /*******************************************************************/ /*******************************************************************/ /** **/ /** OUTPUT MACROS **/ /** **/ /*******************************************************************/ /*******************************************************************/ /* The following macro definitions are used only in processing the */ /* output. */ /*******************************************************************/ #define BUFFER_CHECK(file) \ if ((IOBUFFER_SIZE - (output_ptr - &output_buffer[0])) < 73) \ { \ fwrite(output_buffer, sizeof(char), \ output_ptr - &output_buffer[0], file); \ output_ptr = &output_buffer[0]; \ } /*******************************************************************/ /*******************************************************************/ /** **/ /** GLOBAL DECLARATIONS **/ /** **/ /*******************************************************************/ /*******************************************************************/ typedef unsigned int BOOLEAN_CELL; /* Basic unit used to represent */ /* Bit sets */ typedef BOOLEAN_CELL *SET_PTR; typedef char BOOLEAN; extern const char HEADER_INFO[]; extern const char VERSION[]; extern const char BLANK[]; extern const long MAX_TABLE_SIZE; struct node { struct node *next; int value; }; /*******************************************************************/ /* RULES is the structure that contain the rules of the grammar. */ /* Every rule of the grammar is mapped into an integer, and given */ /* rule, and we have access to a value RHS which is the index */ /* location in the vector RHS where the right-hand-side of the rule*/ /* begins. The right hand side of a certain rule represented by an*/ /* integer I starts at index location RULES[I].RHS in RHS, and */ /* ends at index location RULES[I + 1].RHS - 1. An extra */ /* NUM_RULES + 1 element is used as a "fence" for the last rule. */ /* The RHS vector as mentioned above is used to hold a complete */ /* list of allthe right-hand-side symbols specified in the grammar.*/ /*******************************************************************/ struct ruletab_type { short lhs, rhs; BOOLEAN sp; }; struct shift_type { short symbol, action; }; struct shift_header_type { struct shift_type *map; short size; }; struct reduce_type { short symbol, rule_number; }; struct reduce_header_type { struct reduce_type *map; short size; }; struct goto_type { int laptr; short symbol, action; }; struct goto_header_type { struct goto_type *map; short size; }; struct lastats_type { struct reduce_header_type reduce; short shift_number, in_state; }; struct statset_type { struct node *kernel_items, *complete_items; struct goto_header_type go_to; short shift_number; }; extern char *timeptr; extern long output_line_no; extern char grm_file[], lis_file[], act_file[], hact_file[], tab_file[], prs_file[], sym_file[], def_file[], dcl_file[], file_prefix[], prefix[], suffix[], parm[], msg_line[]; extern FILE *syslis, *sysgrm, *sysact, *syshact, *systab, *syssym, *sysprs, *sysdcl, *sysprs, *sysdef; /******************************************************/ /* The variables below are global counters. */ /******************************************************/ extern long num_items, num_states, max_la_state; extern int num_symbols, symno_size, /* NUM_SYMBOLS + 1 */ num_names, num_terminals, num_non_terminals, num_rules, num_conflict_elements, num_single_productions, gotodom_size; /******************************************************/ /* The variables below are used for options setting. */ /******************************************************/ extern BOOLEAN list_bit, slr_bit, verbose_bit, first_bit, follow_bit, action_bit, edit_bit, states_bit, xref_bit, nt_check_bit, conflicts_bit, read_reduce_bit, goto_default_bit, shift_default_bit, byte_bit, warnings_bit, single_productions_bit, error_maps_bit, debug_bit, deferred_bit, c_bit, cpp_bit, java_bit, jikes_bit, /* undocumented hack for special jikes behavior */ scopes_bit; extern int lalr_level, default_opt, trace_opt, table_opt, names_opt, increment, maximum_distance, minimum_distance, stack_size; extern char escape, ormark, record_format; extern char blockb[], blocke[], hblockb[], hblocke[], errmsg[], gettok[], smactn[], tkactn[]; /*********************************************************************/ /* The variables below are used to hold information about special */ /* grammar symbols. */ /*********************************************************************/ extern short accept_image, eoft_image, eolt_image, empty, error_image; /* Miscellaneous counters. */ extern int num_first_sets, num_shift_maps, page_no; extern long string_offset, string_size, num_shifts, num_shift_reduces, num_gotos, num_goto_reduces, num_reductions, num_sr_conflicts, num_rr_conflicts, num_entries; extern char *string_table; extern short *rhs_sym; extern struct ruletab_type *rules; /***********************************************************************/ /* CLOSURE is a mapping from non-terminal to a set (linked-list) of */ /* non-terminals. The set consists of non-terminals that are */ /* automatically introduced via closure when the original non-terminal */ /* is introduced. */ /* CL_ITEMS is a mapping from each non-terminal to a set (linked list) */ /* of items which are the first item of the rules generated by the */ /* non-terminal in question. ADEQUATE_ITEM is a mapping from each rule */ /* to the last (complete) item produced by that rule. */ /* ITEM_TABLE is used to map each item into a number. Given that */ /* number one can retrieve the rule the item belongs to, the position */ /* of the dot, the symbol following the dot, and FIRST of the suffix */ /* following the "dot symbol". */ /***********************************************************************/ extern struct node **closure, **clitems, **adequate_item; extern struct itemtab { short symbol, rule_number, suffix_index, dot; } *item_table; /***********************************************************************/ /* SYMNO is an array that maps symbol numbers to actual symbols. */ /***********************************************************************/ extern struct symno_type { int ptr, name_index; } *symno; /***********************************************************************/ /* These variables hold the number of BOOLEAN_CELLS required to form a */ /* set of terminals, non-terminals and states, respectively. */ /***********************************************************************/ extern int term_set_size, non_term_set_size, state_set_size; /***********************************************************************/ /* NULL_NT is a boolean vector that indicates whether or not a given */ /* non-terminal is nullable. */ /***********************************************************************/ extern BOOLEAN *null_nt; /***********************************************************************/ /* FOLLOW is a mapping from non-terminals to a set of terminals that */ /* may appear immediately after the non-terminal. */ /***********************************************************************/ extern SET_PTR nt_first, first, follow; /***********************************************************************/ /* NAME is an array containing names to be associated with symbols. */ /* REDUCE is a mapping from each state to reduce actions in that state.*/ /* SHIFT is an array used to hold the complete set of all shift maps */ /* needed to construct the state automaton. Though its size is */ /* NUM_STATES, the actual number of elements used in it is indicated */ /* by the integer NUM_SHIFT_MAPS. NUM_STATES elements were allocated, */ /* because if the user requests that certain single productions be */ /* removed, a Shift map containing actions involving such productions */ /* cannot be shared. */ /***********************************************************************/ extern struct shift_header_type *shift; extern struct reduce_header_type *reduce; extern short *gotodef, *shiftdf, *gd_index, *gd_range; extern int *name; /***********************************************************************/ /* STATSET is a mapping from state number to state information. */ /* LASTATS is a similar mapping for look-ahead states. */ /* IN_STAT is a mapping from each state to the set of states that have */ /* a transition into the state in question. */ /***********************************************************************/ extern struct statset_type *statset; extern struct lastats_type *lastats; extern struct node **in_stat; extern int num_scopes, scope_rhs_size, scope_state_size, num_error_rules; extern struct scope_type { short prefix, suffix, lhs_symbol, look_ahead, state_set; } *scope; extern short *scope_right_side, *scope_state; /*******************************************************************/ /*******************************************************************/ /** **/ /** OUTPUT DECLARATIONS **/ /** **/ /*******************************************************************/ /*******************************************************************/ /* The following external variables are used only in processing */ /* output. */ /*******************************************************************/ extern char *output_ptr, *output_buffer; extern short *symbol_map, *ordered_state, *state_list; extern int *next, *previous, *state_index; extern long table_size, action_size, increment_size; extern short last_non_terminal, last_terminal; extern int accept_act, error_act, first_index, last_index, last_symbol, max_name_length; extern SET_PTR naction_symbols, action_symbols; extern BOOLEAN byte_terminal_range; #endif /* COMMON_INCLUDED */ jikespg-1.3/src/ctabs.c000066400000000000000000003303461167345774400150730ustar00rootroot00000000000000/* $Id: ctabs.c,v 1.4 2001/10/10 14:53:10 ericb Exp $ */ /* This software is subject to the terms of the IBM Jikes Compiler License Agreement available at the following URL: http://ibm.com/developerworks/opensource/jikes. Copyright (C) 1983, 1999, 2001 International Business Machines Corporation and others. All Rights Reserved. You must accept the terms of that agreement to use this software. */ static char hostfile[] = __FILE__; #include #include "common.h" #include "space.h" #include "header.h" static char dcl_tag[SYMBOL_SIZE], sym_tag[SYMBOL_SIZE], def_tag[SYMBOL_SIZE], prs_tag[SYMBOL_SIZE]; static int byte_check_bit = 1; /*********************************************************************/ /* NON_TERMINAL_TIME_ACTION: */ /*********************************************************************/ static void non_terminal_time_action(void) { if (c_bit) fprintf(sysprs, "#define nt_action(state, sym) \\\n" " ((check[state+sym] == sym) ? \\\n" " action[state + sym] : " "default_goto[sym])\n\n"); else if (cpp_bit) fprintf(sysprs, " static int nt_action(int state, int sym)\n" " {\n" " return (check[state + sym] == sym)\n" " ? action[state + sym]\n" " : default_goto[sym];\n" " }\n\n"); else if (java_bit) fprintf(sysprs, " public final static int nt_action(int state, int sym)\n" " {\n" " return (check(state + sym) == sym)\n" " ? action[state + sym]\n" " : default_goto[sym];\n" " }\n\n"); return; } /*********************************************************************/ /* NON_TERMINAL_NO_GOTO_DEFAULT_TIME_ACTION: */ /*********************************************************************/ static void non_terminal_no_goto_default_time_action(void) { if (c_bit) fprintf(sysprs, "#define nt_action(state, sym) action[state + sym]\n\n"); else if (cpp_bit) fprintf(sysprs, " static int nt_action(int state, int sym)\n" " {\n return action[state + sym];\n }\n\n"); else if (java_bit) fprintf(sysprs, " public final static int nt_action(int state, int sym)\n" " {\n return action[state + sym];\n }\n\n"); return; } /*********************************************************************/ /* NON_TERMINAL_SPACE_ACTION: */ /*********************************************************************/ static void non_terminal_space_action(void) { if (c_bit) fprintf(sysprs, "#define nt_action(state, sym) \\\n" " ((base_check[state + sym] == sym) ? \\\n" " base_action[state + sym] : " "default_goto[sym])\n\n"); else if (cpp_bit) fprintf(sysprs, " static int nt_action(int state, int sym)\n" " {\n" " return (base_check[state + sym] == sym)\n" " ? base_action[state + sym]\n" " : default_goto[sym];\n" " }\n\n"); else if (java_bit) fprintf(sysprs, " public final static int nt_action(int state, int sym)\n" " {\n" " return (base_check(state + sym) == sym)\n" " ? base_action[state + sym]\n" " : default_goto[sym];\n" " }\n\n"); return; } /*********************************************************************/ /* NON_TERMINAL_NO_GOTO_DEFAULT_SPACE_ACTION: */ /*********************************************************************/ static void non_terminal_no_goto_default_space_action(void) { if (c_bit) fprintf(sysprs, "#define nt_action(state, sym) " "base_action[state + sym]\n\n"); else if (cpp_bit) fprintf(sysprs, " static int nt_action(int state, int sym)\n" " {\n return base_action[state + sym];\n }\n\n"); else if (java_bit) fprintf(sysprs, " public final static int nt_action(int state, int sym)\n" " {\n return base_action[state + sym];\n }\n\n"); return; } /*********************************************************************/ /* TERMINAL_TIME_ACTION: */ /*********************************************************************/ static void terminal_time_action(void) { if (c_bit) fprintf(sysprs, "#define t_action(state, sym, next_tok) \\\n" " action[check[state + sym] == sym ? state + sym : state]\n\n"); else if (cpp_bit) fprintf(sysprs, " static int t_action(int state, int sym, LexStream *stream)\n" " {\n" " return action[check[state + sym] == sym" " ? state + sym : state];\n" " }\n"); else if (java_bit) fprintf(sysprs, " public final static int t_action(int state, int sym, LexStream stream)\n" " {\n" " return action[check(state + sym) == sym" " ? state + sym : state];\n" " }\n"); return; } /*********************************************************************/ /* TERMINAL_SPACE_ACTION: */ /*********************************************************************/ static void terminal_space_action(void) { if (c_bit) fprintf(sysprs, "#define t_action(state, sym, next_tok) \\\n" " term_action[term_check[base_action[state]+sym] == sym ? \\\n" " base_action[state] + sym : base_action[state]]\n\n"); else if (cpp_bit) fprintf(sysprs, " static int t_action(int state, int sym, LexStream *stream)\n" " {\n" " return term_action[term_check[base_action[state]" "+sym] == sym\n" " ? base_action[state] + sym\n" " : base_action[state]];\n" " }\n"); else if (java_bit) fprintf(sysprs, " public final static int t_action(int state, int sym, LexStream stream)\n" " {\n" " return term_action[term_check[base_action[state]" "+sym] == sym\n" " ? base_action[state] + sym\n" " : base_action[state]];\n" " }\n"); return; } /*********************************************************************/ /* TERMINAL_SHIFT_DEFAULT_SPACE_ACTION: */ /*********************************************************************/ static void terminal_shift_default_space_action(void) { if (c_bit) fprintf(sysprs, "static int t_action(int state, int sym, TokenObject next_tok)\n" "{\n" " int i;\n\n" " if (sym == 0)\n" " return ERROR_ACTION;\n" " i = base_action[state];\n" " if (term_check[i + sym] == sym)\n" " return term_action[i + sym];\n" " i = term_action[i];\n" " return ((shift_check[shift_state[i] + sym] == sym) ?\n" " default_shift[sym] : default_reduce[i]);\n" "}\n\n"); else if (cpp_bit) fprintf(sysprs, " static int t_action(int state, int sym, LexStream *stream)\n" " {\n" " if (sym == 0)\n" " return ERROR_ACTION;\n" " int i = base_action[state];\n" " if (term_check[i + sym] == sym)\n" " return term_action[i + sym];\n" " i = term_action[i];\n" " return ((shift_check[shift_state[i] + sym] == sym) ?\n" " default_shift[sym] : default_reduce[i]);\n" " }\n"); else if (java_bit) fprintf(sysprs, " public final static int t_action(int state, int sym, LexStream stream)\n" " {\n" " if (sym == 0)\n" " return ERROR_ACTION;\n" " int i = base_action[state];\n" " if (term_check[i + sym] == sym)\n" " return term_action[i + sym];\n" " i = term_action[i];\n" " return ((shift_check[shift_state[i] + sym] == sym) ?\n" " default_shift[sym] : default_reduce[i]);\n" " }\n"); return; } /*********************************************************************/ /* TERMINAL_TIME_LALR_K: */ /*********************************************************************/ static void terminal_time_lalr_k(void) { if (c_bit) fprintf(sysprs, "static int t_action(int act, int sym, TokenObject next_tok)\n" "{\n" " int i = act + sym;\n\n" " act = action[check[i] == sym ? i : act];\n\n" " if (act > LA_STATE_OFFSET)\n" " {\n" " for (;;)\n" " {\n" " act -= ERROR_ACTION;\n" " sym = Class(next_tok);\n" " i = act + sym;\n" " act = action[check[i] == sym ? i : act];\n" " if (act <= LA_STATE_OFFSET)\n" " break;\n" " next_tok = Next(next_tok);\n" " }\n" " }\n\n" " return act;\n" "}\n\n"); else if (cpp_bit) fprintf(sysprs, " static int t_action(int act, int sym, LexStream *stream)\n" " {\n" " int i = act + sym;\n\n" " act = action[check[i] == sym ? i : act];\n\n" " if (act > LA_STATE_OFFSET)\n" " {\n" " for (TokenObject tok = stream -> Peek();\n" " ;\n" " tok = stream -> Next(tok))\n" " {\n" " act -= ERROR_ACTION;\n" " sym = stream -> Kind(tok);\n" " i = act + sym;\n" " act = action[check[i] == sym ? i : act];\n" " if (act <= LA_STATE_OFFSET)\n" " break;\n" " }\n" " }\n\n" " return act;\n" " }\n\n"); else if (java_bit) fprintf(sysprs, " public final static int t_action(int act, int sym, LexStream stream)\n" " {\n" " int i = act + sym;\n\n" " act = action[check(i) == sym ? i : act];\n\n" " if (act > LA_STATE_OFFSET)\n" " {\n" " for (int tok = stream.Peek();\n" " ;\n" " tok = stream.Next(tok))\n" " {\n" " act -= ERROR_ACTION;\n" " sym = stream.Kind(tok);\n" " i = act + sym;\n" " act = action[check(i) == sym ? i : act];\n" " if (act <= LA_STATE_OFFSET)\n" " break;\n" " }\n" " }\n\n" " return act;\n" " }\n\n"); return; } /*********************************************************************/ /* TERMINAL_SPACE_LALR_K: */ /*********************************************************************/ static void terminal_space_lalr_k(void) { if (c_bit) fprintf(sysprs, "static int t_action(int state, int sym, TokenObject next_tok)\n" "{\n" " int act = base_action[state],\n" " i = act + sym;\n\n" " act = term_action[term_check[i] == sym ? i : act];\n\n" " if (act > LA_STATE_OFFSET)\n" " {\n" " for (;;)\n" " {\n" " act -= LA_STATE_OFFSET;\n" " sym = Class(next_tok);\n" " i = act + sym;\n" " act = term_action[term_check[i] == sym ? i : act];\n" " if (act <= LA_STATE_OFFSET)\n" " break;\n" " next_tok = Next(next_tok);\n" " }\n" " }\n\n" " return act;\n" "}\n\n"); else if (cpp_bit) fprintf(sysprs, " static int t_action(int act, int sym, LexStream *stream)\n" " {\n" " act = base_action[act];\n" " int i = act + sym;\n\n" " act = term_action[term_check[i] == sym ? i : act];\n\n" " if (act > LA_STATE_OFFSET)\n" " {\n" " for (TokenObject tok = stream -> Peek();\n" " ;\n" " tok = stream -> Next(tok))\n" " {\n" " act -= LA_STATE_OFFSET;\n" " sym = stream -> Kind(tok);\n" " i = act + sym;\n" " act = term_action[term_check[i] == sym ? i : act];\n" " if (act <= LA_STATE_OFFSET)\n" " break;\n" " } \n" " }\n\n" " return act;\n" " }\n"); else if (java_bit) fprintf(sysprs, " public final static int t_action(int act, int sym, LexStream stream)\n" " {\n" " act = base_action[act];\n" " int i = act + sym;\n\n" " act = term_action[term_check[i] == sym ? i : act];\n\n" " if (act > LA_STATE_OFFSET)\n" " {\n" " for (int tok = stream.Peek();\n" " ;\n" " tok = stream.Next(tok))\n" " {\n" " act -= LA_STATE_OFFSET;\n" " sym = stream.Kind(tok);\n" " i = act + sym;\n" " act = term_action[term_check[i] == sym ? i : act];\n" " if (act <= LA_STATE_OFFSET)\n" " break;\n" " } \n" " }\n\n" " return act;\n" " }\n"); return; } /*********************************************************************/ /* TERMINAL_SHIFT_DEFAULT_SPACE_LALR_K: */ /*********************************************************************/ static void terminal_shift_default_space_lalr_k(void) { if (c_bit) fprintf(sysprs, "static int t_action(int state, int sym, TokenObject next_tok)\n" "{\n" " int act = base_action[state],\n" " i = act + sym;\n\n" " if (sym == 0)\n" " act = ERROR_ACTION;\n" " else if (term_check[i] == sym)\n" " act = term_action[i];\n" " else\n" " {\n" " act = term_action[act];\n" " i = shift_state[act] + sym;\n" " act = (shift_check[i] == sym ? default_shift[sym]\n" " : default_reduce[act]);\n" " }\n\n" " while (act > LA_STATE_OFFSET)\n" " {\n" " act -= LA_STATE_OFFSET;\n" " sym = Class(next_tok);\n" " i = act + sym;\n" " if (term_check[i] == sym)\n" " act = term_action[i];\n" " else\n" " {\n" " act = term_action[act];\n" " i = shift_state[act] + sym;\n" " act = (shift_check[i] == sym\n" " ? default_shift[sym]\n" " : default_reduce[act]);\n" " }\n" " if (act <= LA_STATE_OFFSET)\n" " break;\n" " next_tok = Next(next_tok);\n" " }\n\n" " return act;\n" "}\n\n"); else if (cpp_bit) fprintf(sysprs, " static int t_action(int act, int sym, LexStream *stream)\n" " {\n" " act = base_action[act];\n" " int i = act + sym;\n\n" " if (sym == 0)\n" " act = ERROR_ACTION;\n" " else if (term_check[i] == sym)\n" " act = term_action[i];\n" " else\n" " {\n" " act = term_action[act];\n" " i = shift_state[act] + sym;\n" " act = (shift_check[i] == sym ? default_shift[sym]\n" " : default_reduce[act]);\n" " }\n\n" " if (act > LA_STATE_OFFSET)\n" " {\n" " for (TokenObject tok = stream -> Peek();\n" " ;\n" " tok = stream -> Next(tok))\n" " {\n" " act -= LA_STATE_OFFSET;\n" " sym = stream -> Kind(tok);\n" " i = act + sym;\n" " if (term_check[i] == sym)\n" " act = term_action[i];\n" " else\n" " {\n" " act = term_action[act];\n" " i = shift_state[act] + sym;\n" " act = (shift_check[i] == sym\n" " ? default_shift[sym]\n" " : default_reduce[act]);\n" " }\n" " if (act <= LA_STATE_OFFSET)\n" " break;\n" " }\n" " }\n\n" " return act;\n" " }\n"); else if (java_bit) fprintf(sysprs, " public final static int t_action(int act, int sym, LexStream stream)\n" " {\n" " act = base_action[act];\n" " int i = act + sym;\n\n" " if (sym == 0)\n" " act = ERROR_ACTION;\n" " else if (term_check[i] == sym)\n" " act = term_action[i];\n" " else\n" " {\n" " act = term_action[act];\n" " i = shift_state[act] + sym;\n" " act = (shift_check[i] == sym ? default_shift[sym]\n" " : default_reduce[act]);\n" " }\n\n" " if (act > LA_STATE_OFFSET)\n" " {\n" " for (int tok = stream.Peek();\n" " ;\n" " tok = stream.Next(tok))\n" " {\n" " act -= LA_STATE_OFFSET;\n" " sym = stream.Kind(tok);\n" " i = act + sym;\n" " if (term_check[i] == sym)\n" " act = term_action[i];\n" " else\n" " {\n" " act = term_action[act];\n" " i = shift_state[act] + sym;\n" " act = (shift_check[i] == sym\n" " ? default_shift[sym]\n" " : default_reduce[act]);\n" " }\n" " if (act <= LA_STATE_OFFSET)\n" " break;\n" " }\n" " }\n\n" " return act;\n" " }\n"); return; } /*********************************************************************/ /* INIT_FILE: */ /*********************************************************************/ static void init_file(FILE **file, char *file_name, char *file_tag) { char *p; #if defined(C370) && !defined(CW) int size; size = PARSER_LINE_SIZE; if (record_format != 'F') size += 4; sprintf(msg_line, "w, recfm=%cB, lrecl=%d", record_format, size); p = strchr(file_name, '.'); if ((*file = fopen(file_name, msg_line)) == NULL) #else p = strrchr(file_name, '.'); if ((*file = fopen(file_name, "w")) == NULL) #endif { fprintf(stderr, "***ERROR: Symbol file \"%s\" cannot be opened\n", file_name); exit(12); } memcpy(file_tag, file_name, p - file_name); file_tag[p - file_name] = '\0'; if (jikes_bit) fprintf(*file, "// $I"/*CVS hack*/"d$\n" "// DO NOT MODIFY THIS FILE - it is generated using jikespg on java.g.\n" "//\n" "// This software is subject to the terms of the IBM Jikes Compiler Open\n" "// Source License Agreement available at the following URL:\n" "// http://ibm.com/developerworks/opensource/jikes.\n" "// Copyright (C) 1996, 1997, 1998, 1999, 2001, International\n" "// Business Machines Corporation and others. All Rights Reserved.\n" "// You must accept the terms of that agreement to use this software.\n" "//\n\n"); if (c_bit || cpp_bit) { fprintf(*file, "#ifndef %s_INCLUDED\n", file_tag); fprintf(*file, "#define %s_INCLUDED\n\n", file_tag); } if (jikes_bit) fprintf(*file, "#ifdef HAVE_JIKES_NAMESPACE\n" "namespace Jikes { // Open namespace Jikes block\n" "#endif\n\n"); return; } /*********************************************************************/ /* INIT_PARSER_FILES: */ /*********************************************************************/ static void init_parser_files(void) { init_file(&sysdcl, dcl_file, dcl_tag); init_file(&syssym, sym_file, sym_tag); init_file(&sysdef, def_file, def_tag); init_file(&sysprs, prs_file, prs_tag); return; } /*********************************************************************/ /* EXIT_FILE: */ /*********************************************************************/ static void exit_file(FILE **file, char *file_tag) { if (jikes_bit) fprintf(*file, "\n#ifdef HAVE_JIKES_NAMESPACE\n" "} // Close namespace Jikes block\n" "#endif\n"); if (c_bit || cpp_bit) fprintf(*file, "\n#endif /* %s_INCLUDED */\n", file_tag); fclose(*file); return; } /*********************************************************************/ /* EXIT_PRS_FILE: */ /*********************************************************************/ static void exit_parser_files(void) { exit_file(&sysdcl, dcl_tag); exit_file(&syssym, sym_tag); exit_file(&sysdef, def_tag); exit_file(&sysprs, prs_tag); return; } /**************************************************************************/ /* PRINT_C_NAMES: */ /**************************************************************************/ static void print_c_names(void) { char tok[SYMBOL_SIZE + 1]; short *name_len = Allocate_short_array(num_names + 1); long num_bytes = 0; int i, j, k, n; max_name_length = 0; mystrcpy("\nconst char CLASS_HEADER string_buffer[] = {0,\n"); n = 0; j = 0; padline(); for (i = 1; i <= num_names; i++) { strcpy(tok, RETRIEVE_NAME(i)); name_len[i] = strlen(tok); num_bytes += name_len[i]; if (max_name_length < name_len[i]) max_name_length = name_len[i]; k = 0; for (j = 0; j < name_len[i]; j++) { *output_ptr++ = '\''; if (tok[k] == '\'' || tok[k] == '\\') *output_ptr++ = '\\'; if (tok[k] == '\n') *output_ptr++ = escape; else *output_ptr++ = tok[k]; k++; *output_ptr++ = '\''; *output_ptr++ = ','; n++; if (n == 10 && ! (i == num_names && j == name_len[i] - 1)) { n = 0; *output_ptr++ = '\n'; BUFFER_CHECK(sysdcl); padline(); } } } *(output_ptr - 1) = '\n'; /*overwrite last comma*/ BUFFER_CHECK(sysdcl); if (java_bit) mystrcpy(" };\n"); else mystrcpy(" };\n"); /*****************************************************************/ /* Compute and list space required for STRING_BUFFER map. */ /*****************************************************************/ sprintf(msg_line, " Storage required for STRING_BUFFER map: %d Bytes", num_bytes); PRNT(msg_line); /******************************/ /* Write out NAME_START array */ /******************************/ mystrcpy("\nconst unsigned short CLASS_HEADER name_start[] = {0,\n"); padline(); j = 1; k = 0; for (i = 1; i <= num_names; i++) { itoc(j); *output_ptr++ = COMMA; j += name_len[i]; k++; if (k == 10 && i != num_names) { *output_ptr++ = '\n'; BUFFER_CHECK(sysdcl); padline(); k = 0; } } if (k != 0) { *(output_ptr - 1) = '\n'; BUFFER_CHECK(sysdcl); } if (java_bit) mystrcpy(" };\n"); else mystrcpy(" };\n"); /*****************************************************************/ /* Compute and list space required for NAME_START map. */ /*****************************************************************/ sprintf(msg_line, " Storage required for NAME_START map: %d Bytes", (2 * num_names)); PRNT(msg_line); /*******************************/ /* Write out NAME_LENGTH array */ /*******************************/ prnt_shorts("\nconst unsigned char CLASS_HEADER name_length[] = {0,\n", 1, num_names, 10, name_len); /*****************************************************************/ /* Compute and list space required for NAME_LENGTH map. */ /*****************************************************************/ sprintf(msg_line, " Storage required for NAME_LENGTH map: %d Bytes", num_names); PRNT(msg_line); ffree(name_len); return; } /**************************************************************************/ /* PRINT_JAVA_NAMES: */ /**************************************************************************/ static void print_java_names(void) { char tok[SYMBOL_SIZE + 1]; long num_bytes = 0; int i, j, k; max_name_length = 0; mystrcpy("\n public final static String name[] = { null,\n"); for (i = 1; i <= num_names; i++) { int len; strcpy(tok, RETRIEVE_NAME(i)); len = strlen(tok); num_bytes += (len * 2); if (max_name_length < len) max_name_length = len; padline(); *output_ptr++ = '\"'; k = 0; for (j = 0; j < len; j++) { if (tok[j] == '\"' || tok[j] == '\\') *output_ptr++ = '\\'; if (tok[j] == '\n') *output_ptr++ = escape; else *output_ptr++ = tok[j]; k++; if (k == 30 && (! (j == len - 1))) { k = 0; *output_ptr++ = '\"'; *output_ptr++ = ' '; *output_ptr++ = '+'; *output_ptr++ = '\n'; BUFFER_CHECK(sysdcl); padline(); *output_ptr++ = '\"'; } } *output_ptr++ = '\"'; if (i < num_names) *output_ptr++ = ','; *output_ptr++ = '\n'; } BUFFER_CHECK(sysdcl); if (java_bit) mystrcpy(" };\n"); else mystrcpy(" };\n"); /*****************************************************************/ /* Compute and list space required for STRING_BUFFER map. */ /*****************************************************************/ sprintf(msg_line, " Storage required for STRING_BUFFER map: %d Bytes", num_bytes); PRNT(msg_line); return; } /**************************************************************************/ /* PRINT_ERROR_MAPS: */ /**************************************************************************/ static void print_error_maps(void) { short *state_start, *state_stack, *temp, *original, *as_size, *action_symbols_base, *action_symbols_range, *naction_symbols_base, *naction_symbols_range; int i, j, k, n, offset, state_no, symbol; long num_bytes; state_start = Allocate_short_array(num_states + 2); state_stack = Allocate_short_array(num_states + 1); PRNT("\nError maps storage:"); /********************************************************************/ /* We now construct a bit map for the set of terminal symbols that */ /* may appear in each state. Then, we invoke PARTSET to apply the */ /* Partition Heuristic and print it. */ /********************************************************************/ as_size = Allocate_short_array(num_states + 1); if (table_opt == OPTIMIZE_TIME) { original = Allocate_short_array(num_symbols + 1); /*************************************************************/ /* In a compressed TIME table, the terminal and non-terminal */ /* symbols are mixed together when they are remapped. */ /* We shall now recover the original number associated with */ /* each terminal symbol since it lies very nicely in the */ /* range 1..NUM_TERMINALS. This will save a considerable */ /* amount of space in the bit_string representation of sets */ /* as well as time when operations are performed on those */ /* bit-strings. */ /*************************************************************/ for ALL_TERMINALS(symbol) original[symbol_map[symbol]] = symbol; } for ALL_STATES(state_no) { struct shift_header_type sh; struct reduce_header_type red; sh = shift[statset[state_no].shift_number]; as_size[state_no] = sh.size; for (i = 1; i <= sh.size; i++) { if (table_opt == OPTIMIZE_TIME) symbol = original[SHIFT_SYMBOL(sh, i)]; else symbol = SHIFT_SYMBOL(sh, i); SET_BIT_IN(action_symbols, state_no, symbol); } red = reduce[state_no]; as_size[state_no] += red.size; for (i = 1; i <= red.size; i++) { if (table_opt == OPTIMIZE_TIME) symbol = original[REDUCE_SYMBOL(red, i)]; else symbol = REDUCE_SYMBOL(red, i); SET_BIT_IN(action_symbols, state_no, symbol); } } partset(action_symbols, as_size, state_list, state_start, state_stack, num_terminals); ffree(action_symbols); /*************************************************************/ /* Compute and write out the base of the ACTION_SYMBOLS map. */ /*************************************************************/ action_symbols_base = Allocate_short_array(num_states + 1); for ALL_STATES(i) action_symbols_base[state_list[i]] = ABS(state_start[state_list[i]]); if (java_bit) { prnt_shorts("\n public final static char asb[] = {0,\n", 1, num_states, 10, action_symbols_base); } else { prnt_shorts("\nconst unsigned short CLASS_HEADER asb[] = {0,\n", 1, num_states, 10, action_symbols_base); } ffree(action_symbols_base); /**************************************************************/ /* Compute and write out the range of the ACTION_SYMBOLS map. */ /**************************************************************/ offset = state_start[num_states + 1]; action_symbols_range = Allocate_short_array(offset); compute_action_symbols_range(state_start, state_stack, state_list, action_symbols_range); for (i = 0; i < (offset - 1); i++) { if (action_symbols_range[i] > (java_bit ? 127 : 255)) { byte_terminal_range = 0; break; } } if (byte_terminal_range) { if (java_bit) { prnt_shorts("\n public final static byte asr[] = {0,\n", 0, offset - 2, 10, action_symbols_range); } else { prnt_shorts("\nconst unsigned char CLASS_HEADER asr[] = {0,\n", 0, offset - 2, 10, action_symbols_range); } } else { if (java_bit) { prnt_shorts("\n public final static char asr[] = {0,\n", 0, offset - 2, 10, action_symbols_range); } else { prnt_shorts("\nconst unsigned short CLASS_HEADER asr[] = {0,\n", 0, offset - 2, 10, action_symbols_range); } } num_bytes = 2 * num_states; sprintf(msg_line, " Storage required for ACTION_SYMBOLS_BASE map: " "%ld Bytes", num_bytes); PRNT(msg_line); if ((table_opt == OPTIMIZE_TIME) && (last_terminal <= (java_bit ? 127 : 255))) num_bytes = offset - 1; else if ((table_opt != OPTIMIZE_TIME) && (num_terminals <= (java_bit ? 127 : 255))) num_bytes = offset - 1; else num_bytes = 2 * (offset - 1); sprintf(msg_line, " Storage required for ACTION_SYMBOLS_RANGE map: " "%ld Bytes", num_bytes); PRNT(msg_line); ffree(action_symbols_range); /***********************************************************************/ /* We now repeat the same process for the domain of the GOTO table. */ /***********************************************************************/ for ALL_STATES(state_no) { as_size[state_no] = gd_index[state_no + 1] - gd_index[state_no]; for (i = gd_index[state_no]; i <= gd_index[state_no + 1] - 1; i++) { symbol = gd_range[i] - num_terminals; NTSET_BIT_IN(naction_symbols, state_no, symbol); } } partset(naction_symbols, as_size, state_list, state_start, state_stack, num_non_terminals); ffree(as_size); ffree(naction_symbols); for (i = 1; i <= gotodom_size; i++) /* Remap non-terminals */ { if (table_opt == OPTIMIZE_SPACE) gd_range[i] = symbol_map[gd_range[i]] - num_terminals; else gd_range[i] = symbol_map[gd_range[i]]; } /*************************************************************/ /* Compute and write out the base of the NACTION_SYMBOLS map.*/ /*************************************************************/ naction_symbols_base = Allocate_short_array(num_states + 1); for ALL_STATES(i) naction_symbols_base[state_list[i]] = ABS(state_start[state_list[i]]); if (java_bit) { prnt_shorts("\n public final static char nasb[] = {0,\n", 1, num_states, 10, naction_symbols_base); } else { prnt_shorts("\nconst unsigned short CLASS_HEADER nasb[] = {0,\n", 1, num_states, 10, naction_symbols_base); } ffree(naction_symbols_base); /**************************************************************/ /* Compute and write out the range of the NACTION_SYMBOLS map.*/ /**************************************************************/ offset = state_start[num_states + 1]; naction_symbols_range = Allocate_short_array(offset); compute_naction_symbols_range(state_start, state_stack, state_list, naction_symbols_range); if (java_bit) { prnt_shorts("\n public final static char nasr[] = {0,\n", 0, offset - 2, 10, naction_symbols_range); } else { prnt_shorts("\nconst unsigned short CLASS_HEADER nasr[] = {0,\n", 0, offset - 2, 10, naction_symbols_range); } num_bytes = 2 * num_states; sprintf(msg_line, " Storage required for NACTION_SYMBOLS_BASE map: " "%ld Bytes", num_bytes); PRNT(msg_line); num_bytes = 2 * (offset - 1); sprintf(msg_line, " Storage required for NACTION_SYMBOLS_RANGE map: " "%ld Bytes", ((long) 2 * (offset - 1))); PRNT(msg_line); ffree(naction_symbols_range); /*********************************************************************/ /* We write the name_index of each terminal symbol. The array TEMP */ /* is used to remap the NAME_INDEX values based on the new symbol */ /* numberings. If time tables are requested, the terminals and non- */ /* terminals are mixed together. */ /*********************************************************************/ temp = Allocate_short_array(num_symbols + 1); if (table_opt == OPTIMIZE_SPACE) { for ALL_TERMINALS(symbol) temp[symbol_map[symbol]] = symno[symbol].name_index; if (num_names <= (java_bit ? 127 : 255)) { if (java_bit) { prnt_shorts ("\n public final static byte terminal_index[] = {0,\n", 1, num_terminals, 10, temp); } else { prnt_shorts ("\nconst unsigned char CLASS_HEADER terminal_index[] = {0,\n", 1, num_terminals, 10, temp); } num_bytes = num_terminals; } else { if (java_bit) { prnt_shorts ("\n public final static char terminal_index[] = {0,\n", 1, num_terminals, 10, temp); } else { prnt_shorts ("\nconst unsigned short CLASS_HEADER terminal_index[] = {0,\n", 1, num_terminals, 10, temp); } num_bytes = 2 * num_terminals; } /*****************************************************************/ /* Compute and list space required for TERMINAL_INDEX map. */ /*****************************************************************/ sprintf(msg_line, " Storage required for TERMINAL_INDEX map: %d Bytes", num_bytes); PRNT(msg_line); /******************************************************************/ /* We write the name_index of each non_terminal symbol. The array */ /* TEMP is used to remap the NAME_INDEX values based on the new */ /* symbol numberings. */ /******************************************************************/ for ALL_NON_TERMINALS(symbol) temp[symbol_map[symbol]] = symno[symbol].name_index; if (num_names <= (java_bit ? 127 : 255)) { if (java_bit) { prnt_shorts ("\n public final static byte " "non_terminal_index[] = {0,\n", num_terminals + 1, num_symbols, 10, temp); } else { prnt_shorts ("\nconst unsigned char CLASS_HEADER " "non_terminal_index[] = {0,\n", num_terminals + 1, num_symbols, 10, temp); } num_bytes = num_non_terminals; } else { if (java_bit) { prnt_shorts ("\n public final static char " "non_terminal_index[] = {0,\n", num_terminals + 1, num_symbols, 10, temp); } else { prnt_shorts ("\nconst unsigned short CLASS_HEADER " "non_terminal_index[] = {0,\n", num_terminals + 1, num_symbols, 10, temp); } num_bytes = 2 * num_non_terminals; } /*****************************************************************/ /* Compute and list space required for NON_TERMINAL_INDEX map. */ /*****************************************************************/ sprintf(msg_line, " Storage required for NON_TERMINAL_INDEX map: %d Bytes", num_bytes); PRNT(msg_line); } else { for ALL_SYMBOLS(symbol) temp[symbol_map[symbol]] = symno[symbol].name_index; if (num_names <= (java_bit ? 127 : 255)) { if (java_bit) { prnt_shorts ("\n public final static byte symbol_index[] = {0,\n", 1, num_symbols, 10, temp); mystrcpy(" public final static byte terminal_index[] = " "symbol_index;\n"); mystrcpy(" public final static byte non_terminal_index[] = " "symbol_index;\n"); } else { prnt_shorts ("\nconst unsigned char CLASS_HEADER symbol_index[] = {0,\n", 1, num_symbols, 10, temp); mystrcpy("const unsigned char *CLASS_HEADER terminal_index[] = " "&(symbol_index[0]);\n"); mystrcpy("const unsigned char *CLASS_HEADER non_terminal_index[] = " "&(symbol_index[0]);\n"); } num_bytes = num_symbols; } else { if (java_bit) { prnt_shorts ("\n public final static char symbol_index[] = {0,\n", 1, num_symbols, 10, temp); mystrcpy(" public final static char terminal_index[] = " "symbol_index[0];\n"); mystrcpy(" public final static char non_terminal_index[] = " "symbol_index;\n"); } else { prnt_shorts ("\nconst unsigned short CLASS_HEADER symbol_index[] = {0,\n", 1, num_symbols, 10, temp); mystrcpy("const unsigned short *CLASS_HEADER terminal_index[] = " "&(symbol_index[0]);\n"); mystrcpy("const unsigned short *CLASS_HEADER non_terminal_index[] = " "&(symbol_index[0]);\n"); } num_bytes = 2 * num_symbols; } /*****************************************************************/ /* Compute and list space required for SYMBOL_INDEX map. */ /*****************************************************************/ sprintf(msg_line, " Storage required for SYMBOL_INDEX map: %d Bytes", num_bytes); PRNT(msg_line); } if (num_scopes > 0) { short root = 0; short *list; list = Allocate_short_array(scope_rhs_size + 1); for (i = 1; i <= scope_rhs_size; i++) { if (scope_right_side[i] != 0) scope_right_side[i] = symbol_map[scope_right_side[i]]; } for (i = 1; i <= num_scopes; i++) { scope[i].look_ahead = symbol_map[scope[i].look_ahead]; if (table_opt == OPTIMIZE_SPACE) scope[i].lhs_symbol = symbol_map[scope[i].lhs_symbol] - num_terminals; else scope[i].lhs_symbol = symbol_map[scope[i].lhs_symbol]; } /****************************************/ /* Mark all elements of prefix strings. */ /****************************************/ for (i=1; i <= scope_rhs_size; i++) list[i] = -1; for (i = 1; i <= num_scopes; i++) { if (list[scope[i].suffix] < 0) { list[scope[i].suffix] = root; root = scope[i].suffix; } } for (; root != 0; root = list[root]) { for (j = root; scope_right_side[j] != 0; j++) { k = scope_right_side[j]; scope_right_side[j] = temp[k]; } } ffree(list); } if (java_bit) print_java_names(); else print_c_names(); if (num_scopes > 0) { if (scope_rhs_size <= (java_bit ? 127 : 255)) { if (java_bit) mystrcpy("\n public final static byte scope_prefix[] = {\n"); else mystrcpy("\nconst unsigned char CLASS_HEADER scope_prefix[] = {\n"); } else { if (java_bit) mystrcpy("\n public final static char scope_prefix[] = {\n"); else mystrcpy("\nconst unsigned short CLASS_HEADER scope_prefix[] = {\n"); } padline(); k = 0; for (i = 1; i <= num_scopes; i++) { itoc(scope[i].prefix); *output_ptr++ = COMMA; k++; if (k == 10 && i != num_scopes) { *output_ptr++ = '\n'; BUFFER_CHECK(sysdcl); padline(); k = 0; } } if (k != 0) { *(output_ptr - 1) = '\n'; BUFFER_CHECK(sysdcl); } if (java_bit) mystrcpy(" };\n"); else mystrcpy(" };\n"); if (scope_rhs_size <= (java_bit ? 127 : 255)) { if (java_bit) mystrcpy("\n public final static byte scope_suffix[] = {\n"); else mystrcpy("\nconst unsigned char CLASS_HEADER scope_suffix[] = {\n"); } else { if (java_bit) mystrcpy("\n public final static char scope_suffix[] = {\n"); else mystrcpy("\nconst unsigned short CLASS_HEADER scope_suffix[] = {\n"); } padline(); k = 0; for (i = 1; i <= num_scopes; i++) { itoc(scope[i].suffix); *output_ptr++ = COMMA; k++; if (k == 10 && i != num_scopes) { *output_ptr++ = '\n'; BUFFER_CHECK(sysdcl); padline(); k = 0; } } if (k != 0) { *(output_ptr - 1) = '\n'; BUFFER_CHECK(sysdcl); } if (java_bit) mystrcpy(" };\n"); else mystrcpy(" };\n"); if (num_symbols <= (java_bit ? 127 : 255)) { if (java_bit) mystrcpy("\n public final static byte scope_lhs[] = {\n"); else mystrcpy("\nconst unsigned char CLASS_HEADER scope_lhs[] = {\n"); } else { if (java_bit) mystrcpy("\n public final static char scope_lhs[] = {\n"); else mystrcpy("\nconst unsigned short CLASS_HEADER scope_lhs[] = {\n"); } padline(); k = 0; for (i = 1; i <= num_scopes; i++) { itoc(scope[i].lhs_symbol); *output_ptr++ = COMMA; k++; if (k == 10 && i != num_scopes) { *output_ptr++ = '\n'; BUFFER_CHECK(sysdcl); padline(); k = 0; } } if (k != 0) { *(output_ptr - 1) = '\n'; BUFFER_CHECK(sysdcl); } if (java_bit) mystrcpy(" };\n"); else mystrcpy(" };\n"); if (num_terminals <= (java_bit ? 127 : 255)) { if (java_bit) mystrcpy("\n public final static byte scope_la[] = {\n"); else mystrcpy("\nconst unsigned char CLASS_HEADER scope_la[] = {\n"); } else { if (java_bit) mystrcpy("\n public final static char scope_la[] = {\n"); else mystrcpy("\nconst unsigned short CLASS_HEADER scope_la[] = {\n"); } padline(); k = 0; for (i = 1; i <= num_scopes; i++) { itoc(scope[i].look_ahead); *output_ptr++ = COMMA; k++; if (k == 10 && i != num_scopes) { *output_ptr++ = '\n'; BUFFER_CHECK(sysdcl); padline(); k = 0; } } if (k != 0) { *(output_ptr - 1) = '\n'; BUFFER_CHECK(sysdcl); } if (java_bit) mystrcpy(" };\n"); else mystrcpy(" };\n"); if (scope_state_size <= (java_bit ? 127 : 255)) { if (java_bit) mystrcpy("\n public final static byte scope_state_set[] = {\n"); else mystrcpy("\nconst unsigned char CLASS_HEADER scope_state_set[] = {\n"); } else { if (java_bit) mystrcpy("\n public final static char scope_state_set[] = {\n"); else mystrcpy("\nconst unsigned short CLASS_HEADER scope_state_set[] = {\n"); } padline(); k = 0; for (i = 1; i <= num_scopes; i++) { itoc(scope[i].state_set); *output_ptr++ = COMMA; k++; if (k == 10 && i != num_scopes) { *output_ptr++ = '\n'; BUFFER_CHECK(sysdcl); padline(); k = 0; } } if (k != 0) { *(output_ptr - 1) = '\n'; BUFFER_CHECK(sysdcl); } if (java_bit) mystrcpy(" };\n"); else mystrcpy(" };\n"); if (num_symbols <= (java_bit ? 127 : 255)) { if (java_bit) { prnt_shorts ("\n public final static byte scope_rhs[] = {0,\n", 1, scope_rhs_size, 10, scope_right_side); } else { prnt_shorts ("\nconst unsigned char CLASS_HEADER scope_rhs[] = {0,\n", 1, scope_rhs_size, 10, scope_right_side); } } else { if (java_bit) { prnt_shorts ("\n public final static char scope_rhs[] = {0,\n", 1, scope_rhs_size, 10, scope_right_side); } else { prnt_shorts ("\nconst unsigned short CLASS_HEADER scope_rhs[] = {0,\n", 1, scope_rhs_size, 10, scope_right_side); } } if (java_bit) mystrcpy("\n public final static char scope_state[] = {0,\n"); else mystrcpy("\nconst unsigned short CLASS_HEADER scope_state[] = {0,\n"); padline(); k = 0; for (i = 1; i <= scope_state_size; i++) { if (scope_state[i] == 0) itoc(0); else itoc(state_index[scope_state[i]] + num_rules); *output_ptr++ = COMMA; k++; if (k == 10 && i != scope_state_size) { *output_ptr++ = '\n'; BUFFER_CHECK(sysdcl); padline(); k = 0; } } if (k != 0) { *(output_ptr - 1) = '\n'; BUFFER_CHECK(sysdcl); } if (java_bit) mystrcpy(" };\n"); else mystrcpy(" };\n"); if (num_symbols <= (java_bit ? 127 : 255)) { if (java_bit) mystrcpy("\n public final static byte in_symb[] = {0,\n"); else mystrcpy("\nconst unsigned char CLASS_HEADER in_symb[] = {0,\n"); } else { if (java_bit) mystrcpy("\n public final static char in_symb[] = {0,\n"); else mystrcpy("\nconst unsigned short CLASS_HEADER in_symb[] = {0,\n"); } /* Transition symbol */ padline(); *output_ptr++ = '0'; *output_ptr++ = COMMA; k = 1; for (state_no = 2; state_no <= (int) num_states; state_no++) { struct node *q; int item_no; q = statset[state_no].kernel_items; if (q != NULL) { item_no = q -> value - 1; i = item_table[item_no].symbol; } else i = 0; itoc(symbol_map[i]); *output_ptr++ = COMMA; k++; if (k == 10 && state_no != (int) num_states) { *output_ptr++ = '\n'; BUFFER_CHECK(sysdcl); padline(); k = 0; } } if (k != 0) { *(output_ptr - 1) = '\n'; BUFFER_CHECK(sysdcl); } if (java_bit) mystrcpy(" };\n"); else mystrcpy(" };\n"); } return; } /****************************************************************************/ /* PRINT_SYMBOLS: */ /****************************************************************************/ static void print_symbols(void) { int symbol; char line[SYMBOL_SIZE + /* max length of a token symbol */ 2 * MAX_PARM_SIZE + /* max length of prefix + suffix */ 64]; /* +64 for error messages lines */ /* or other fillers(blank, =,...)*/ if (java_bit) { strcpy(line, "interface "); strcat(line, sym_tag); strcat(line, "\n{\n public final static int\n"); } else strcpy(line, "enum {\n"); /*********************************************************/ /* We write the terminal symbols map. */ /*********************************************************/ for ALL_TERMINALS(symbol) { char *tok = RETRIEVE_STRING(symbol); fprintf(syssym, "%s", line); if (tok[0] == '\n' || tok[0] == escape) { tok[0] = escape; sprintf(line, "Escaped symbol %s is an invalid C variable.\n",tok); PRNT(line); } else if (strpbrk(tok, "!%^&*()-+={}[];:\"`~|\\,.<>/?\'") != NULL) { sprintf(line, "%s may be an invalid variable name.\n", tok); PRNT(line); } sprintf(line, " %s%s%s = %i,\n\0", prefix, tok, suffix, symbol_map[symbol]); if (c_bit || cpp_bit) { while(strlen(line) > PARSER_LINE_SIZE) { fwrite(line, sizeof(char), PARSER_LINE_SIZE - 2, syssym); fprintf(syssym, "\\\n"); strcpy(line, &line[PARSER_LINE_SIZE - 2]); } } } line[strlen(line) - 2] = '\0'; /* remove the string ",\n" from last line */ fprintf(syssym, "%s%s", line, (java_bit ? ";\n}\n" : "\n };\n")); return; } /****************************************************************************/ /* PRINT_DEFINITIONS: */ /****************************************************************************/ static void print_definitions(void) { if (java_bit) fprintf(sysdef, "interface %s\n{\n public final static int\n\n", def_tag); else fprintf(sysdef, "enum {\n"); if (error_maps_bit) { if (java_bit) fprintf(sysdef, " ERROR_SYMBOL = %d,\n" " MAX_NAME_LENGTH = %d,\n" " NUM_STATES = %d,\n\n", error_image, max_name_length, num_states); else { if (! jikes_bit) fprintf(sysdef, " ERROR_CODE,\n" " BEFORE_CODE,\n" " INSERTION_CODE,\n" " INVALID_CODE,\n" " SUBSTITUTION_CODE,\n" " DELETION_CODE,\n" " MERGE_CODE,\n" " MISPLACED_CODE,\n" " SCOPE_CODE,\n" " MANUAL_CODE,\n" " SECONDARY_CODE,\n" " EOF_CODE,\n\n"); fprintf(sysdef, " ERROR_SYMBOL = %d,\n" " MAX_DISTANCE = %d,\n" " MIN_DISTANCE = %d,\n" " MAX_NAME_LENGTH = %d,\n" " MAX_TERM_LENGTH = %d,\n" " NUM_STATES = %d,\n\n", error_image, maximum_distance, minimum_distance, max_name_length, max_name_length, num_states); } } if (java_bit) fprintf(sysdef, " NT_OFFSET = %d,\n" " SCOPE_UBOUND = %d,\n" " SCOPE_SIZE = %d,\n" " LA_STATE_OFFSET = %d,\n" " MAX_LA = %d,\n" " NUM_RULES = %d,\n" " NUM_TERMINALS = %d,\n" " NUM_NON_TERMINALS = %d,\n" " NUM_SYMBOLS = %d,\n" " START_STATE = %d,\n" " EOFT_SYMBOL = %d,\n" " EOLT_SYMBOL = %d,\n" " ACCEPT_ACTION = %d,\n" " ERROR_ACTION = %d;\n" "};\n\n", (table_opt == OPTIMIZE_SPACE ? num_terminals : num_symbols), num_scopes - 1, num_scopes, (read_reduce_bit && lalr_level > 1 ? error_act + num_rules : error_act), lalr_level, num_rules, num_terminals, num_non_terminals, num_symbols, state_index[1] + num_rules, eoft_image, eolt_image, accept_act, error_act); else fprintf(sysdef, " NT_OFFSET = %d,\n" " BUFF_UBOUND = %d,\n" " BUFF_SIZE = %d,\n" " STACK_UBOUND = %d,\n" " STACK_SIZE = %d,\n" " SCOPE_UBOUND = %d,\n" " SCOPE_SIZE = %d,\n" " LA_STATE_OFFSET = %d,\n" " MAX_LA = %d,\n" " NUM_RULES = %d,\n" " NUM_TERMINALS = %d,\n" " NUM_NON_TERMINALS = %d,\n" " NUM_SYMBOLS = %d,\n" " START_STATE = %d,\n" " EOFT_SYMBOL = %d,\n" " EOLT_SYMBOL = %d,\n" " ACCEPT_ACTION = %d,\n" " ERROR_ACTION = %d\n" " };\n\n", (table_opt == OPTIMIZE_SPACE ? num_terminals : num_symbols), maximum_distance + lalr_level - 1, maximum_distance + lalr_level, stack_size - 1, stack_size, num_scopes - 1, num_scopes, (read_reduce_bit && lalr_level > 1 ? error_act + num_rules : error_act), lalr_level, num_rules, num_terminals, num_non_terminals, num_symbols, state_index[1] + num_rules, eoft_image, eolt_image, accept_act, error_act); return; } /****************************************************************************/ /* PRINT_EXTERNS: */ /****************************************************************************/ static void print_externs(void) { if (c_bit || cpp_bit) { fprintf(sysprs, "%s SCOPE_REPAIR\n" "%s DEFERRED_RECOVERY\n" "%s FULL_DIAGNOSIS\n" "%s SPACE_TABLES\n\n", (num_scopes > 0 ? "#define" : "#undef "), (deferred_bit ? "#define" : "#undef "), (error_maps_bit ? "#define" : "#undef "), (table_opt == OPTIMIZE_SPACE ? "#define" : "#undef ")); } if (c_bit) fprintf(sysprs, "#define original_state(state) (-%s[state])\n" "#define asi(state) asb[original_state(state)]\n" "#define nasi(state) nasb[original_state(state)]\n" "#define in_symbol(state) in_symb[original_state(state)]\n\n", (table_opt == OPTIMIZE_TIME ? "check" : "base_check")); else if (cpp_bit) { fprintf(sysprs, "class LexStream;\n\n" "class %s_table\n" "{\n" "public:\n", prs_tag); if (error_maps_bit || debug_bit) fprintf(sysprs, " static int original_state(int state) " "{ return -%s[state]; }\n", (table_opt == OPTIMIZE_TIME ? "check" : "base_check")); if (error_maps_bit) { fprintf(sysprs, " static int asi(int state) " "{ return asb[original_state(state)]; }\n" " static int nasi(int state) " "{ return nasb[original_state(state)]; }\n"); if (num_scopes > 0) fprintf(sysprs, " static int in_symbol(int state) " "{ return in_symb[original_state(state)]; }\n"); } fprintf(sysprs, "\n"); } else if (java_bit) { fprintf(sysprs, "abstract class %s extends %s implements %s\n{\n", prs_tag, dcl_tag, def_tag); if (error_maps_bit || debug_bit) { fprintf(sysprs, " public final static int original_state(int state) " "{ return -%s(state); }\n", (table_opt == OPTIMIZE_TIME ? "check" : "base_check")); if (error_maps_bit) { fprintf(sysprs, " public final static int asi(int state) " "{ return asb[original_state(state)]; }\n" " static int nasi(int state) " "{ return nasb[original_state(state)]; }\n"); if (num_scopes > 0) fprintf(sysprs, " public final static int in_symbol(int state) " "{ return in_symb[original_state(state)]; }\n"); } fprintf(sysprs, "\n"); } } if (c_bit || cpp_bit) { fprintf(sysprs, "%s const unsigned char rhs[];\n", (c_bit ? "extern" : " static")); if (check_size > 0 || table_opt == OPTIMIZE_TIME) { BOOLEAN small = byte_check_bit && (! error_maps_bit); fprintf(sysprs, "%s const %s check_table[];\n" "%s const %s *%s;\n", (c_bit ? "extern" : " static"), (small ? "unsigned char " : " signed short"), (c_bit ? "extern" : " static"), (small ? "unsigned char " : " signed short"), (table_opt == OPTIMIZE_TIME ? "check" : "base_check")); } fprintf(sysprs, "%s const unsigned short lhs[];\n" "%s const unsigned short *%s;\n", (c_bit ? "extern" : " static"), (c_bit ? "extern" : " static"), (table_opt == OPTIMIZE_TIME ? "action" : "base_action")); if (goto_default_bit) fprintf(sysprs, "%s const unsigned short default_goto[];\n", (c_bit ? "extern" : " static")); if (table_opt == OPTIMIZE_SPACE) { fprintf(sysprs, "%s const unsigned %s term_check[];\n", (c_bit ? "extern" : " static"), (num_terminals <= (java_bit ? 127 : 255) ? "char " : "short")); fprintf(sysprs, "%s const unsigned short term_action[];\n", (c_bit ? "extern" : " static")); if (shift_default_bit) { fprintf(sysprs, "%s const unsigned short default_reduce[];\n", (c_bit ? "extern" : " static")); fprintf(sysprs, "%s const unsigned short shift_state[];\n", (c_bit ? "extern" : " static")); fprintf(sysprs, "%s const unsigned %s shift_check[];\n", (c_bit ? "extern" : " static"), (num_terminals <= (java_bit ? 127 : 255) ? "char " : "short")); fprintf(sysprs, "%s const unsigned short default_shift[];\n", (c_bit ? "extern" : " static")); } } if (error_maps_bit) { fprintf(sysprs, "\n" "%s const unsigned short asb[];\n" "%s const unsigned %s asr[];\n" "%s const unsigned short nasb[];\n" "%s const unsigned short nasr[];\n" "%s const unsigned short name_start[];\n" "%s const unsigned char name_length[];\n" "%s const char string_buffer[];\n", (c_bit ? "extern" : " static"), (c_bit ? "extern" : " static"), (byte_terminal_range <= (java_bit ? 127 : 255) ? "char " : "short"), (c_bit ? "extern" : " static"), (c_bit ? "extern" : " static"), (c_bit ? "extern" : " static"), (c_bit ? "extern" : " static"), (c_bit ? "extern" : " static")); if (table_opt == OPTIMIZE_SPACE) { fprintf(sysprs, "%s const unsigned %s terminal_index[];\n" "%s const unsigned %s non_terminal_index[];\n", (c_bit ? "extern" : " static"), (num_names <= (java_bit ? 127 : 255) ? "char " : "short"), (c_bit ? "extern" : " static"), (num_names <= (java_bit ? 127 : 255) ? "char " : "short")); } else { fprintf(sysprs, "%s const unsigned %s symbol_index[];\n" "%s const unsigned %s *terminal_index;\n" "%s const unsigned %s *non_terminal_index;\n", (c_bit ? "extern" : " static"), (num_names <= (java_bit ? 127 : 255) ? "char " : "short"), (c_bit ? "extern" : " static"), (num_names <= (java_bit ? 127 : 255) ? "char " : "short"), (c_bit ? "extern" : " static"), (num_names <= (java_bit ? 127 : 255) ? "char " : "short")); } if (num_scopes > 0) { fprintf(sysprs, "%s const unsigned %s scope_prefix[];\n" "%s const unsigned %s scope_suffix[];\n" "%s const unsigned %s scope_lhs[];\n" "%s const unsigned %s scope_la[];\n" "%s const unsigned %s scope_state_set[];\n" "%s const unsigned %s scope_rhs[];\n" "%s const unsigned short scope_state[];\n" "%s const unsigned %s in_symb[];\n", (c_bit ? "extern" : " static"), (scope_rhs_size <= (java_bit ? 127 : 255) ? "char " : "short"), (c_bit ? "extern" : " static"), (scope_rhs_size <= (java_bit ? 127 : 255) ? "char " : "short"), (c_bit ? "extern" : " static"), (num_symbols <= (java_bit ? 127 : 255) ? "char " : "short"), (c_bit ? "extern" : " static"), (num_terminals <= (java_bit ? 127 : 255) ? "char " : "short"), (c_bit ? "extern" : " static"), (scope_state_size <= (java_bit ? 127 : 255) ? "char " : "short"), (c_bit ? "extern" : " static"), (num_symbols <= (java_bit ? 127 : 255) ? "char " : "short"), (c_bit ? "extern" : " static"), (c_bit ? "extern" : " static"), (num_symbols <= (java_bit ? 127 : 255) ? "char " : "short")); } } fprintf(sysprs, "\n"); } if (table_opt == OPTIMIZE_SPACE) { if (goto_default_bit) non_terminal_space_action(); else non_terminal_no_goto_default_space_action(); if (lalr_level > 1) { if (shift_default_bit) terminal_shift_default_space_lalr_k(); else terminal_space_lalr_k(); } else { if (shift_default_bit) terminal_shift_default_space_action(); else terminal_space_action(); } } else { if (goto_default_bit) non_terminal_time_action(); else non_terminal_no_goto_default_time_action(); if (lalr_level > 1) terminal_time_lalr_k(); else terminal_time_action(); } if (cpp_bit) fprintf(sysprs, "};\n"); else if (java_bit) fprintf(sysprs, "}\n"); return; } /**************************************************************************/ /* PRINT_SPACE_TABLES: */ /**************************************************************************/ static void print_space_tables(void) { int *check, *action; int la_state_offset, i, j, k, indx, act, result_act, default_count = 0, goto_count = 0, goto_reduce_count = 0, reduce_count = 0, la_shift_count = 0, shift_count = 0, shift_reduce_count = 0; int rule_no, symbol, state_no; long offset; check = Allocate_int_array(table_size + 1); action = Allocate_int_array(table_size + 1); output_ptr = &output_buffer[0]; /******************************************************************/ /* Prepare header card with proper information, and write it out. */ /******************************************************************/ offset = error_act; if (lalr_level > 1) { if (read_reduce_bit) offset += num_rules; la_state_offset = offset; } else la_state_offset = error_act; if (offset > (MAX_TABLE_SIZE + 1)) { sprintf(msg_line, "Table contains entries that are > " "%d; Processing stopped.", MAX_TABLE_SIZE + 1); PRNTERR(msg_line); exit(12); } for (i = 1; i <= check_size; i++) check[i] = DEFAULT_SYMBOL; for (i = 1; i <= (int) action_size; i++) action[i] = error_act; /********************************************************************/ /* Update the default non-terminal action of each state with the */ /* appropriate corresponding terminal state starting index. */ /********************************************************************/ for (i = 1; i <= num_terminal_states; i++) { indx = term_state_index[i]; state_no = new_state_element[i].image; /*********************************************************************/ /* Update the action link between the non-terminal and terminal */ /* tables. If error-maps are requested, an indirect linking is made */ /* as follows: */ /* Each non-terminal row identifies its original state number, and */ /* a new vector START_TERMINAL_STATE indexable by state numbers */ /* identifies the starting point of each state in the terminal table.*/ /*********************************************************************/ if (state_no <= (int) num_states) { for (; state_no != NIL; state_no = state_list[state_no]) action[state_index[state_no]] = indx; } else { for (; state_no != NIL; state_no = state_list[state_no]) { act = la_state_offset + indx; state_index[state_no] = act; } } } /*********************************************************************/ /* Now update the non-terminal tables with the non-terminal actions.*/ /*********************************************************************/ for ALL_STATES(state_no) { struct goto_header_type go_to; indx = state_index[state_no]; go_to = statset[state_no].go_to; for (j = 1; j <= go_to.size; j++) { symbol = GOTO_SYMBOL(go_to, j); i = indx + symbol; if (goto_default_bit || nt_check_bit) check[i] = symbol; act = GOTO_ACTION(go_to, j); if (act > 0) { action[i] = state_index[act] + num_rules; goto_count++; } else { action[i] = -act; goto_reduce_count++; } } } if (error_maps_bit || debug_bit) { if (check_size == 0) { check_size = action_size; for (i = 0; i <= check_size; i++) check[i] = 0; } for ALL_STATES(state_no) check[state_index[state_no]] = -state_no; } for (i = 1; i <= check_size; i++) { if (check[i] < 0 || check[i] > (java_bit ? 127 : 255)) byte_check_bit = 0; } if (c_bit) mystrcpy("\n#define CLASS_HEADER\n\n"); else if (cpp_bit) { mystrcpy("\n#define CLASS_HEADER "); mystrcpy(prs_tag); mystrcpy("_table::\n\n"); } else { mystrcpy("abstract class "); mystrcpy(dcl_tag); mystrcpy(" implements "); mystrcpy(def_tag); mystrcpy("\n{\n"); } /*********************************************************************/ /* Write size of right hand side of rules followed by CHECK table. */ /*********************************************************************/ if (java_bit) mystrcpy(" public final static byte rhs[] = {0,\n"); else mystrcpy("const unsigned char CLASS_HEADER rhs[] = {0,\n"); padline(); k = 0; for (i = 1; i <= num_rules; i++) { k++; if (k > 15) { *output_ptr++ = '\n'; BUFFER_CHECK(sysdcl); padline(); k = 1; } itoc(RHS_SIZE(i)); *output_ptr++ = COMMA; } *(output_ptr - 1) = '\n'; BUFFER_CHECK(sysdcl); if (java_bit) mystrcpy(" };\n"); else mystrcpy(" };\n"); *output_ptr++ = '\n'; if (check_size > 0) { if (byte_check_bit && ! error_maps_bit) { if (java_bit) mystrcpy(" public final static byte check_table[] = {\n"); else mystrcpy("const unsigned char CLASS_HEADER check_table[] = {\n"); } else { if (java_bit) mystrcpy(" public final static short check_table[] = {\n"); else mystrcpy("const signed short CLASS_HEADER check_table[] = {\n"); } padline(); k = 0; for (i = 1; i <= check_size; i++) { k++; if (k > 10) { *output_ptr++ = '\n'; BUFFER_CHECK(sysdcl); padline(); k = 1; } itoc(check[i]); *output_ptr++ = COMMA; } *(output_ptr - 1) = '\n'; BUFFER_CHECK(sysdcl); if (java_bit) mystrcpy(" };\n"); else mystrcpy(" };\n"); *output_ptr++ = '\n'; if (byte_check_bit && (! error_maps_bit)) { if (java_bit) mystrcpy(" public final static byte base_check(int i)" "\n {\n return check_table[i - (NUM_RULES + 1)];\n }\n"); else mystrcpy("const unsigned char *CLASS_HEADER base_check = " "&(check_table[0]) - (NUM_RULES + 1);\n"); } else { if (java_bit) mystrcpy(" public final static short base_check(int i) " "\n {\n return check_table[i - (NUM_RULES + 1)];\n }\n"); else mystrcpy("const signed short *CLASS_HEADER base_check = " "&(check_table[0]) - (NUM_RULES + 1);\n"); } *output_ptr++ = '\n'; } /*********************************************************************/ /* Write left hand side symbol of rules followed by ACTION table. */ /*********************************************************************/ if (java_bit) mystrcpy(" public final static char lhs[] = {0,\n"); else mystrcpy("const unsigned short CLASS_HEADER lhs[] = {0,\n"); padline(); k = 0; for (i = 1; i <= num_rules; i++) { itoc(symbol_map[rules[i].lhs] - num_terminals); *output_ptr++ = COMMA; k++; if (k == 15) { *output_ptr++ = '\n'; BUFFER_CHECK(sysdcl); padline(); k = 0; } } *output_ptr++ = '\n'; *output_ptr++ = '\n'; BUFFER_CHECK(sysdcl); padline(); k = 0; if (error_maps_bit) { int max_indx; max_indx = accept_act - num_rules - 1; for (i = 1; i <= max_indx; i++) check[i] = OMEGA; for ALL_STATES(state_no) check[state_index[state_no]] = state_no; j = num_states + 1; for (i = max_indx; i >= 1; i--) { state_no = check[i]; if (state_no != OMEGA) { j--; ordered_state[j] = i + num_rules; state_list[j] = state_no; } } } for (i = 1; i <= (int) action_size; i++) { itoc(action[i]); *output_ptr++ = COMMA; k++; if (k == 10 && i != (int) action_size) { *output_ptr++ = '\n'; BUFFER_CHECK(sysdcl); padline(); k = 0; } } if (k != 0) { *(output_ptr - 1) = '\n'; BUFFER_CHECK(sysdcl); } if (java_bit) mystrcpy(" };\n"); else mystrcpy(" };\n"); *output_ptr++ = '\n'; BUFFER_CHECK(sysdcl); if (java_bit) mystrcpy(" public final static char base_action[] = lhs;\n"); else mystrcpy("const unsigned short *CLASS_HEADER base_action = lhs;\n"); *output_ptr++ = '\n'; /********************************************************************/ /* Initialize the terminal tables,and update with terminal actions. */ /********************************************************************/ for (i = 1; i <= term_check_size; i++) check[i] = DEFAULT_SYMBOL; for (i = 1; i <= term_action_size; i++) action[i] = error_act; for (state_no = 1; state_no <= num_terminal_states; state_no++) { struct shift_header_type sh; struct reduce_header_type red; indx = term_state_index[state_no]; sh = shift[new_state_element[state_no].shift_number]; for (j = 1; j <= sh.size; j++) { symbol = SHIFT_SYMBOL(sh, j); act = SHIFT_ACTION(sh, j); if ((! shift_default_bit) || (act != shiftdf[symbol])) { i = indx + symbol; check[i] = symbol; if (act > (int) num_states) { result_act = state_index[act]; la_shift_count++; } else if (act > 0) { result_act = state_index[act] + num_rules; shift_count++; } else { result_act = -act + error_act; shift_reduce_count++; } if (result_act > (MAX_TABLE_SIZE + 1)) { sprintf(msg_line, "Table contains look-ahead shift entry that is >" " %d; Processing stopped.", MAX_TABLE_SIZE + 1); PRNTERR(msg_line); return; } action[i] = result_act; } } red = new_state_element[state_no].reduce; for (j = 1; j <= red.size; j++) { symbol = REDUCE_SYMBOL(red, j); rule_no = REDUCE_RULE_NO(red, j); i = indx + symbol; check[i] = symbol; action[i] = rule_no; reduce_count++; } rule_no = REDUCE_RULE_NO(red, 0); if (rule_no != error_act) default_count++; check[indx] = DEFAULT_SYMBOL; if (shift_default_bit) action[indx] = state_no; else action[indx] = rule_no; } PRNT("\n\nActions in Compressed Tables:"); sprintf(msg_line," Number of Shifts: %d",shift_count); PRNT(msg_line); sprintf(msg_line," Number of Shift/Reduces: %d",shift_reduce_count); PRNT(msg_line); if (max_la_state > num_states) { sprintf(msg_line, " Number of Look-Ahead Shifts: %d", la_shift_count); PRNT(msg_line); } sprintf(msg_line," Number of Gotos: %d",goto_count); PRNT(msg_line); sprintf(msg_line," Number of Goto/Reduces: %d",goto_reduce_count); PRNT(msg_line); sprintf(msg_line," Number of Reduces: %d",reduce_count); PRNT(msg_line); sprintf(msg_line," Number of Defaults: %d",default_count); PRNT(msg_line); /********************************************************************/ /* Write Terminal Check Table. */ /********************************************************************/ if (num_terminals <= (java_bit ? 127 : 255)) { if (java_bit) prnt_ints("\n public final static byte term_check[] = {0,\n", 1, term_check_size, 15, check); else prnt_ints("\nconst unsigned char CLASS_HEADER term_check[] = {0,\n", 1, term_check_size, 15, check); } else { if (java_bit) prnt_ints("\n public final static char term_check[] = {0,\n", 1, term_check_size, 15, check); else prnt_ints("\nconst unsigned short CLASS_HEADER term_check[] = {0,\n", 1, term_check_size, 15, check); } /********************************************************************/ /* Write Terminal Action Table. */ /********************************************************************/ if (java_bit) prnt_ints("\n public final static char term_action[] = {0,\n", 1, term_action_size, 10, action); else prnt_ints("\nconst unsigned short CLASS_HEADER term_action[] = {0,\n", 1, term_action_size, 10, action); /********************************************************************/ /* If GOTO_DEFAULT is requested, we print out the GOTODEF vector. */ /********************************************************************/ if (goto_default_bit) { if (java_bit) mystrcpy("\n public final static char default_goto[] = {0,\n"); else mystrcpy("\nconst unsigned short CLASS_HEADER default_goto[] = {0,\n"); padline(); k = 0; for ALL_NON_TERMINALS(symbol) { act = gotodef[symbol]; if (act < 0) result_act = -act; else if (act == 0) result_act = error_act; else result_act = state_index[act] + num_rules; itoc(result_act); *output_ptr++ = COMMA; k++; if (k == 10 && symbol != num_symbols) { *output_ptr++ = '\n'; BUFFER_CHECK(sysdcl); padline(); k = 0; } } if (k != 0) { *(output_ptr - 1) = '\n'; BUFFER_CHECK(sysdcl); } if (java_bit) mystrcpy(" };\n"); else mystrcpy(" };\n"); } if (shift_default_bit) { if (java_bit) mystrcpy("\n public final static char default_reduce[] = {0,\n"); else mystrcpy("\nconst unsigned short CLASS_HEADER default_reduce[] = {0,\n"); padline(); k = 0; for (i = 1; i <= num_terminal_states; i++) { struct reduce_header_type red; red = new_state_element[i].reduce; itoc(REDUCE_RULE_NO(red, 0)); *output_ptr++ = COMMA; k++; if (k == 10 && i != num_terminal_states) { *output_ptr++ = '\n'; BUFFER_CHECK(sysdcl); padline(); k = 0; } } if (k != 0) { *(output_ptr - 1) = '\n'; BUFFER_CHECK(sysdcl); } if (java_bit) mystrcpy(" };\n"); else mystrcpy(" };\n"); if (java_bit) mystrcpy("\n public final static char shift_state[] = {0,\n"); else mystrcpy("\nconst unsigned short CLASS_HEADER shift_state[] = {0,\n"); padline(); k = 0; for (i = 1; i <= num_terminal_states; i++) { itoc(shift_check_index[shift_image[i]]); *output_ptr++ = COMMA; k++; if (k == 10 && i != num_terminal_states) { *output_ptr++ = '\n'; BUFFER_CHECK(sysdcl); padline(); k = 0; } } if (k != 0) { *(output_ptr - 1) = '\n'; BUFFER_CHECK(sysdcl); } if (java_bit) mystrcpy(" };\n"); else mystrcpy(" };\n"); for (i = 1; i <= shift_check_size; i++) check[i] = DEFAULT_SYMBOL; for (i = 1; i <= shift_domain_count; i++) { struct shift_header_type sh; indx = shift_check_index[i]; sh = shift[real_shift_number[i]]; for (j = 1; j <= sh.size; j++) { symbol = SHIFT_SYMBOL(sh, j); check[indx + symbol] = symbol; } } if (num_terminals <= (java_bit ? 127 : 255)) { if (java_bit) mystrcpy("\n public final static byte shift_check[] = {0,\n"); else mystrcpy("\nconst unsigned char CLASS_HEADER shift_check[] = {0,\n"); } else { if (java_bit) mystrcpy("\n public final static char shift_check[] = {0,\n"); else mystrcpy("\nconst unsigned short CLASS_HEADER shift_check[] = {0,\n"); } padline(); k = 0; for (i = 1; i <= shift_check_size; i++) { itoc(check[i]); *output_ptr++ = COMMA; k++; if (k == 10 && i != shift_check_size) { *output_ptr++ = '\n'; BUFFER_CHECK(sysdcl); padline(); k = 0; } } if (k != 0) { *(output_ptr - 1) = '\n'; BUFFER_CHECK(sysdcl); } if (java_bit) mystrcpy(" };\n"); else mystrcpy(" };\n"); if (java_bit) mystrcpy("\n public final static char default_shift[] = {0,\n"); else mystrcpy("\nconst unsigned short CLASS_HEADER default_shift[] = {0,\n"); padline(); k = 0; for ALL_TERMINALS(symbol) { act = shiftdf[symbol]; if (act < 0) result_act = -act + error_act; else if (act == 0) result_act = error_act; else if (act > (int) num_states) result_act = state_index[act]; else result_act = state_index[act] + num_rules; if (result_act > (MAX_TABLE_SIZE + 1)) { sprintf(msg_line, "Table contains look-ahead shift entry that is >" " %d; Processing stopped.", MAX_TABLE_SIZE + 1); PRNTERR(msg_line); return; } itoc(result_act); *output_ptr++ = COMMA; k++; if (k == 10 && i != num_terminals) { *output_ptr++ = '\n'; BUFFER_CHECK(sysdcl); padline(); k = 0; } } if (k != 0) { *(output_ptr - 1) = '\n'; BUFFER_CHECK(sysdcl); } if (java_bit) mystrcpy(" };\n"); else mystrcpy(" };\n"); } ffree(check); ffree(action); if (error_maps_bit) print_error_maps(); if (! byte_check_bit) { if (java_bit) { PRNT("\n***Warning: Base Check vector contains value " "> 127. 16-bit words used."); } else { PRNT("\n***Warning: Base Check vector contains value " "> 255. 16-bit words used."); } } if (! byte_terminal_range) { if (java_bit) { PRNT("***Warning: Terminal symbol > 127. 16-bit words used."); } else { PRNT("***Warning: Terminal symbol > 255. 16-bit words used."); } } if (java_bit) mystrcpy("}\n"); fwrite(output_buffer, sizeof(char), output_ptr - &output_buffer[0], sysdcl); return; } /**************************************************************************/ /* PRINT_TIME_TABLES: */ /**************************************************************************/ static void print_time_tables(void) { int *action, *check; int la_shift_count = 0, shift_count = 0, goto_count = 0, default_count = 0, reduce_count = 0, shift_reduce_count = 0, goto_reduce_count = 0; int indx, la_state_offset, act, result_act, i, j, k, symbol, state_no; short default_rule; long offset; state_list = Allocate_short_array(max_la_state + 1); output_ptr = &output_buffer[0]; check = next; action = previous; offset = error_act; if (lalr_level > 1) { if (read_reduce_bit) offset += num_rules; la_state_offset = offset; } else la_state_offset = error_act; if (offset > (MAX_TABLE_SIZE + 1)) { sprintf(msg_line, "Table contains entries that are > " "%d; Processing stopped.", MAX_TABLE_SIZE + 1); PRNTERR(msg_line); exit(12); } /*********************************************************************/ /* Initialize all unfilled slots with default values. */ /* RECALL that the vector "check" is aliased to the vector "next". */ /*********************************************************************/ indx = first_index; for (i = indx; (i != NIL) && (i <= (int) action_size); i = indx) { indx = next[i]; check[i] = DEFAULT_SYMBOL; action[i] = error_act; } for (i = (int) action_size + 1; i <= (int) table_size; i++) check[i] = DEFAULT_SYMBOL; /*********************************************************************/ /* We set the rest of the table with the proper table entries. */ /*********************************************************************/ for (state_no = 1; state_no <= (int) max_la_state; state_no++) { struct goto_header_type go_to; struct shift_header_type sh; struct reduce_header_type red; indx = state_index[state_no]; if (state_no > (int) num_states) { sh = shift[lastats[state_no].shift_number]; red = lastats[state_no].reduce; } else { go_to = statset[state_no].go_to; for (j = 1; j <= go_to.size; j++) { symbol = GOTO_SYMBOL(go_to, j); i = indx + symbol; if (goto_default_bit || nt_check_bit) check[i] = symbol; else check[i] = DEFAULT_SYMBOL; act = GOTO_ACTION(go_to, j); if (act > 0) { action[i] = state_index[act] + num_rules; goto_count++; } else { action[i] = -act; goto_reduce_count++; } } sh = shift[statset[state_no].shift_number]; red = reduce[state_no]; } for (j = 1; j <= sh.size; j++) { symbol = SHIFT_SYMBOL(sh, j); i = indx + symbol; check[i] = symbol; act = SHIFT_ACTION(sh, j); if (act > (int) num_states) { result_act = la_state_offset + state_index[act]; la_shift_count++; } else if (act > 0) { result_act = state_index[act] + num_rules; shift_count++; } else { result_act = -act + error_act; shift_reduce_count++; } if (result_act > (MAX_TABLE_SIZE + 1)) { sprintf(msg_line, "Table contains look-ahead shift entry that is >" " %d; Processing stopped.", MAX_TABLE_SIZE + 1); PRNTERR(msg_line); return; } action[i] = result_act; } /*********************************************************************/ /* We now initialize the elements reserved for reduce actions in */ /* the current state. */ /*********************************************************************/ default_rule = REDUCE_RULE_NO(red, 0); for (j = 1; j <= red.size; j++) { if (REDUCE_RULE_NO(red, j) != default_rule) { symbol = REDUCE_SYMBOL(red, j); i = indx + symbol; check[i] = symbol; act = REDUCE_RULE_NO(red, j); if (rules[act].lhs == accept_image) action[i] = accept_act; else action[i] = act; reduce_count++; } } /*********************************************************************/ /* We now initialize the element reserved for the DEFAULT reduce */ /* action of the current state. If error maps are requested, the */ /* default slot is initialized to the original state number, and the */ /* corresponding element of the DEFAULT_REDUCE array is initialized. */ /* Otherwise it is initialized to the rule number in question. */ /*********************************************************************/ i = indx + DEFAULT_SYMBOL; check[i] = DEFAULT_SYMBOL; act = REDUCE_RULE_NO(red, 0); if (act == OMEGA) action[i] = error_act; else { action[i] = act; default_count++; } } PRNT("\n\nActions in Compressed Tables:"); sprintf(msg_line, " Number of Shifts: %d", shift_count); PRNT(msg_line); sprintf(msg_line, " Number of Shift/Reduces: %d", shift_reduce_count); PRNT(msg_line); if (max_la_state > num_states) { sprintf(msg_line, " Number of Look-Ahead Shifts: %d", la_shift_count); PRNT(msg_line); } sprintf(msg_line, " Number of Gotos: %d", goto_count); PRNT(msg_line); sprintf(msg_line, " Number of Goto/Reduces: %d", goto_reduce_count); PRNT(msg_line); sprintf(msg_line, " Number of Reduces: %d", reduce_count); PRNT(msg_line); sprintf(msg_line, " Number of Defaults: %d", default_count); PRNT(msg_line); if (error_maps_bit || debug_bit) { for ALL_STATES(state_no) check[state_index[state_no]] = -state_no; } for (i = 1; i <= (int) table_size; i++) { if (check[i] < 0 || check[i] > (java_bit ? 127 : 255)) byte_check_bit = 0; } if (c_bit) mystrcpy("\n#define CLASS_HEADER\n\n"); else if (cpp_bit) { mystrcpy("\n#define CLASS_HEADER "); mystrcpy(prs_tag); mystrcpy("_table::\n\n"); } else if (java_bit) { mystrcpy("abstract class "); mystrcpy(dcl_tag); mystrcpy(" implements "); mystrcpy(def_tag); mystrcpy("\n{\n"); } /*********************************************************************/ /* Write size of right hand side of rules followed by CHECK table. */ /*********************************************************************/ if (java_bit) mystrcpy(" public final static byte rhs[] = {0,\n"); else mystrcpy("const unsigned char CLASS_HEADER rhs[] = {0,\n"); padline(); k = 0; for (i = 1; i <= num_rules; i++) { k++; if (k > 15) { *output_ptr++ = '\n'; BUFFER_CHECK(sysdcl); padline(); k = 1; } itoc(RHS_SIZE(i)); *output_ptr++ = COMMA; } *(output_ptr - 1) = '\n'; BUFFER_CHECK(sysdcl); if (java_bit) mystrcpy(" };\n"); else mystrcpy(" };\n"); *output_ptr++ = '\n'; /*****************************************************************/ /* Write CHECK table. */ /*****************************************************************/ if (byte_check_bit && (! error_maps_bit)) { if (java_bit) mystrcpy(" public final static byte check_table[] = {\n"); else mystrcpy("const unsigned char CLASS_HEADER check_table[] = {\n"); } else { if (java_bit) mystrcpy(" public final static short check_table[] = {\n"); else mystrcpy("const signed short CLASS_HEADER check_table[] = {\n"); } padline(); k = 0; for (i = 1; i <= (int) table_size; i++) { k++; if (k > 10) { *output_ptr++ = '\n'; BUFFER_CHECK(sysdcl); padline(); k = 1; } itoc(check[i]); *output_ptr++ = COMMA; } *(output_ptr - 1) = '\n'; BUFFER_CHECK(sysdcl); if (java_bit) mystrcpy(" };\n"); else mystrcpy(" };\n"); *output_ptr++ = '\n'; BUFFER_CHECK(sysdcl); if (byte_check_bit && (! error_maps_bit)) { if (java_bit) mystrcpy(" public final static byte check(int i) " "\n {\n return check_table[i - (NUM_RULES + 1)];\n }\n"); else mystrcpy("const unsigned char *CLASS_HEADER check = " "&(check_table[0]) - (NUM_RULES + 1);\n"); } else { if (java_bit) mystrcpy(" public final static short check(int i) " "\n {\n return check_table[i - (NUM_RULES + 1)];\n }\n"); else mystrcpy("const signed short *CLASS_HEADER check = " "&(check_table[0]) - (NUM_RULES + 1);\n"); } *output_ptr++ = '\n'; /*********************************************************************/ /* Write left hand side symbol of rules followed by ACTION table. */ /*********************************************************************/ if (java_bit) mystrcpy(" public final static char lhs[] = {0,\n"); else mystrcpy("const unsigned short CLASS_HEADER lhs[] = {0,\n"); padline(); k = 0; for (i = 1; i <= num_rules; i++) { itoc(symbol_map[rules[i].lhs]); *output_ptr++ = COMMA; k++; if (k == 15) { *output_ptr++ = '\n'; BUFFER_CHECK(sysdcl); padline(); k = 0; } } *output_ptr++ = '\n'; *output_ptr++ = '\n'; BUFFER_CHECK(sysdcl); padline(); k = 0; if (error_maps_bit) { int max_indx; /*************************************************************/ /* Construct a map from new state numbers into original */ /* state numbers using the array check[] */ /*************************************************************/ max_indx = accept_act - num_rules - 1; for (i = 1; i <= max_indx; i++) check[i] = OMEGA; for ALL_STATES(state_no) check[state_index[state_no]] = state_no; j = num_states + 1; for (i = max_indx; i >= 1; i--) { state_no = check[i]; if (state_no != OMEGA) { ordered_state[--j] = i + num_rules; state_list[j] = state_no; } } } for (i = 1; i <= (int) action_size; i++) { itoc(action[i]); *output_ptr++ = COMMA; k++; if (k == 10 && i != (int) action_size) { *output_ptr++ = '\n'; BUFFER_CHECK(sysdcl); padline(); k = 0; } } if (k != 0) { *(output_ptr - 1) = '\n'; BUFFER_CHECK(sysdcl); } if (java_bit) mystrcpy(" };\n"); else mystrcpy(" };\n"); *output_ptr++ = '\n'; BUFFER_CHECK(sysdcl); if (java_bit) mystrcpy(" public final static char action[] = lhs;\n"); else mystrcpy("const unsigned short *CLASS_HEADER action = lhs;\n"); *output_ptr++ = '\n'; /********************************************************************/ /* If GOTO_DEFAULT is requested, we print out the GOTODEF vector. */ /********************************************************************/ if (goto_default_bit) { short *default_map; default_map = Allocate_short_array(num_symbols + 1); if (java_bit) mystrcpy("\n public final static char default_goto[] = {0,\n"); else mystrcpy("\nconst unsigned short CLASS_HEADER default_goto[] = {0,\n"); padline(); k = 0; for (i = 0; i <= num_symbols; i++) default_map[i] = error_act; for ALL_NON_TERMINALS(symbol) { act = gotodef[symbol]; if (act < 0) result_act = -act; else if (act > 0) result_act = state_index[act] + num_rules; else result_act = error_act; default_map[symbol_map[symbol]] = result_act; } for (symbol = 1; symbol <= num_symbols; symbol++) { itoc(default_map[symbol]); *output_ptr++ = COMMA; k++; if (k == 10 && symbol != num_symbols) { *output_ptr++ = '\n'; BUFFER_CHECK(sysdcl); padline(); k = 0; } } if (k != 0) { *(output_ptr - 1) = '\n'; BUFFER_CHECK(sysdcl); } if (java_bit) mystrcpy(" };\n"); else mystrcpy(" };\n"); } ffree(next); ffree(previous); if (error_maps_bit) print_error_maps(); if (! byte_check_bit) { if (java_bit) { PRNT("\n***Warning: Base Check vector contains value " "> 127. 16-bit words used."); } else { PRNT("\n***Warning: Base Check vector contains value " "> 255. 16-bit words used."); } } if (! byte_terminal_range) { if (java_bit) { PRNT("***Warning: Terminal symbol > 127. 16-bit words used."); } else { PRNT("***Warning: Terminal symbol > 255. 16-bit words used."); } } if (java_bit) mystrcpy("}\n"); fwrite(output_buffer, sizeof(char), output_ptr - &output_buffer[0], sysdcl); return; } /*********************************************************************/ /* PRINT_SPACE_PARSER: */ /*********************************************************************/ void print_space_parser(void) { init_parser_files(); print_space_tables(); print_symbols(); print_definitions(); print_externs(); exit_parser_files(); return; } /*********************************************************************/ /* PRINT_TIME_PARSER: */ /*********************************************************************/ void print_time_parser(void) { init_parser_files(); print_time_tables(); print_symbols(); print_definitions(); print_externs(); exit_parser_files(); return; } jikespg-1.3/src/globals.c000066400000000000000000000145521167345774400154200ustar00rootroot00000000000000/* $Id: globals.c,v 1.6 2001/10/10 14:53:10 ericb Exp $ */ /* This software is subject to the terms of the IBM Jikes Compiler License Agreement available at the following URL: http://ibm.com/developerworks/opensource/jikes. Copyright (C) 1983, 1999, 2001 International Business Machines Corporation and others. All Rights Reserved. You must accept the terms of that agreement to use this software. */ static char hostfile[] = __FILE__; #include "common.h" #include "reduce.h" #include "space.h" /*******************************************************************/ /*******************************************************************/ /** The following are global variables declared in COMMON.H **/ /*******************************************************************/ /*******************************************************************/ const char HEADER_INFO[] = "IBM Research Jikes Parser Generator"; const char VERSION[] = "1.2"; const char BLANK[] = " "; const long MAX_TABLE_SIZE = MIN((long) USHRT_MAX, INT_MAX) - 1; char *timeptr; long output_line_no = 0; char grm_file[80], lis_file[80], act_file[80], hact_file[80], tab_file[80], prs_file[80] = "", sym_file[80] = "", def_file[80] = "", dcl_file[80] = "", file_prefix[80] = "", prefix[MAX_PARM_SIZE] = "", suffix[MAX_PARM_SIZE] = "", parm[256] = "", msg_line[MAX_MSG_SIZE]; FILE *sysgrm, *syslis, *sysact, *syshact, *systab, *syssym, *sysprs, *sysdcl, *sysdef; /******************************************************/ /* The variables below are global counters. */ /******************************************************/ long num_items = 0, num_states = 0, max_la_state; int num_symbols = 0, symno_size, num_names = 0, num_terminals, num_non_terminals, num_rules = 0, num_conflict_elements = 0, num_single_productions = 0, gotodom_size = 0; /*********************************************************************/ /* The variables below are used to hold information about special */ /* grammar symbols. */ /*********************************************************************/ short accept_image, eoft_image, eolt_image, empty, error_image; /* Miscellaneous counters. */ int num_first_sets, num_shift_maps = 0, page_no = 0; long string_offset = 0, string_size = 0, num_shifts = 0, num_shift_reduces = 0, num_gotos = 0, num_goto_reduces = 0, num_reductions = 0, num_sr_conflicts = 0, num_rr_conflicts = 0, num_entries; int num_scopes = 0, scope_rhs_size = 0, scope_state_size = 0, num_error_rules = 0; BOOLEAN list_bit = FALSE, slr_bit = FALSE, verbose_bit = FALSE, first_bit = FALSE, follow_bit = FALSE, action_bit = FALSE, edit_bit = FALSE, states_bit = FALSE, xref_bit = FALSE, nt_check_bit = FALSE, conflicts_bit = TRUE, read_reduce_bit = TRUE, goto_default_bit = TRUE, shift_default_bit = FALSE, byte_bit = TRUE, warnings_bit = TRUE, single_productions_bit = FALSE, error_maps_bit = FALSE, debug_bit = FALSE, deferred_bit = TRUE, c_bit = FALSE, cpp_bit = FALSE, java_bit = FALSE, jikes_bit = FALSE, scopes_bit = FALSE; int lalr_level = 1, default_opt = 5, trace_opt = TRACE_CONFLICTS, names_opt = OPTIMIZE_PHRASES, table_opt = 0, increment = 30, maximum_distance = 30, minimum_distance = 3, stack_size = 128; char escape = '%', ormark = '|', record_format = 'V'; char blockb[MAX_PARM_SIZE] = {'/', '.'}, blocke[MAX_PARM_SIZE] = {'.', '/'}, hblockb[MAX_PARM_SIZE] = {'/', ':'}, hblocke[MAX_PARM_SIZE] = {':', '/'}, errmsg[MAX_PARM_SIZE] = "errmsg", gettok[MAX_PARM_SIZE] = "gettok", smactn[MAX_PARM_SIZE] = "smactn", tkactn[MAX_PARM_SIZE] = "tkactn"; char *string_table = (char *) NULL; short *rhs_sym = NULL; struct ruletab_type *rules = NULL; struct node **closure = NULL, **clitems = NULL, **adequate_item = NULL; struct itemtab *item_table = NULL; struct symno_type *symno = NULL; BOOLEAN *null_nt = NULL; int term_set_size, non_term_set_size, state_set_size; SET_PTR nt_first = NULL, first = NULL, follow = NULL; struct shift_header_type *shift = NULL; struct reduce_header_type *reduce = NULL; short *shiftdf = NULL, *gotodef = NULL, *gd_index = NULL, *gd_range = NULL; int *name; struct statset_type *statset = NULL; struct lastats_type *lastats = NULL; struct node **in_stat = NULL; struct scope_type *scope = NULL; short *scope_right_side = NULL, *scope_state = NULL; char *output_ptr = NULL, *output_buffer = NULL; short *symbol_map = NULL, *ordered_state = NULL, *state_list = NULL; int *next = NULL, *previous = NULL, *state_index = NULL; long table_size, action_size, increment_size; short last_non_terminal = 0, last_terminal = 0; int accept_act, error_act, first_index, last_index, last_symbol, max_name_length = 0; SET_PTR naction_symbols = NULL, action_symbols = NULL; BOOLEAN byte_terminal_range = TRUE; struct node **conflict_symbols = NULL; SET_PTR la_set = NULL, read_set = NULL; int highest_level = 0; long la_top = 0; short *la_index = NULL; BOOLEAN not_lrk; struct new_state_type *new_state_element; short *shift_image = NULL, *real_shift_number = NULL; int *term_state_index = NULL, *shift_check_index = NULL; int shift_domain_count, num_terminal_states, check_size, term_check_size, term_action_size, shift_check_size; jikespg-1.3/src/header.h000066400000000000000000000076071167345774400152350ustar00rootroot00000000000000/* $Id: header.h,v 1.2 1999/11/04 14:02:22 shields Exp $ */ /* This software is subject to the terms of the IBM Jikes Compiler License Agreement available at the following URL: http://www.ibm.com/research/jikes. Copyright (C) 1983, 1999, International Business Machines Corporation and others. All Rights Reserved. You must accept the terms of that agreement to use this software. */ #ifndef HEADER_INCLUDED #define HEADER_INCLUDED /***********************************************************************/ /***********************************************************************/ /** **/ /** The following declarations are specifications for all global **/ /** procedures and functions used in the program. **/ /** **/ /***********************************************************************/ /***********************************************************************/ long temporary_space_allocated(void); long temporary_space_used(void); long global_space_allocated(void); long global_space_used(void); void reset_temporary_space(void); void free_temporary_space(void); void *talloc(long size); struct node *allocate_node(char *file, long line); BOOLEAN *allocate_boolean_array(long size, char *file, long line); int *allocate_int_array(long size, char *file, long line); short *allocate_short_array(long size, char *file, long line); struct goto_header_type allocate_goto_map(int size, char *file, long line); struct shift_header_type allocate_shift_map(int size, char *file, long line); struct reduce_header_type allocate_reduce_map(int size, char *file, long line); void cmprspa(void); void cmprtim(void); void compute_la(int state_no, int item_no, SET_PTR look_ahead); void create_lastats(void); void dump_tables(void); void exit_lalrk_process(void); void init_lalrk_process(void); void init_rmpself(SET_PTR produces); void itoc(int num); void field(int num, int len); void fill_in(char string[], int amount, char character); void free_conflict_space(void); void free_nodes(struct node *head, struct node *tail); struct node *lpgaccess(int state_no, int item_no); void mkfirst(void); void mkrdcts(void); void la_traverse(int state_no, int goto_indx, int *stack_top); void remove_single_productions(void); void mkstats(void); void mystrcpy(char *str); void padline(void); void nospace(char *, long); int number_len(int state_no); void partset(SET_PTR collection, short *element_size, short *list, short *start, short *stack, int set_size); void print_item(int item_no); void print_large_token(char *line, char *token, char *indent, int len); void print_state(int state_no); void compute_action_symbols_range(short *state_start, short *state_stack, short *state_list, short *action_symbols_range); void compute_naction_symbols_range(short *state_start, short *state_stack, short *state_list, short *naction_symbols_range); void produce(void); void process_error_maps(void); void prnt_shorts(char *title, int init, int bound, int perline, short *array); void prnt_ints(char *title, int init, int bound, int perline, int *array); void print_space_parser(void); void print_time_parser(void); void process_tables(void); void ptstats(void); void remvsp(void); void sortdes(short array[], short count[], int low, int high, int max); void reallocate(void); void resolve_conflicts(int state_no, struct node **action, short *reduce_list, int reduce_root); void restore_symbol(char *out, char *in); char *strlwr(char *string); char *strupr(char *string); #endif /* HEADER_INCLUDED */ jikespg-1.3/src/jikespg.g000066400000000000000000001040741167345774400154340ustar00rootroot00000000000000%Options nogoto-default,esc=$,os=100,action,actfile=lpgact.i,noem %Options fp=lpg,gp,nodefer,suffix=_TK,stack_size=21,hactfile=lpgact.h -- $Id: jikespg.g,v 1.2 1999/11/04 14:02:22 shields Exp $ -- This software is subject to the terms of the IBM Jikes Compiler -- License Agreement available at the following URL: -- http://www.ibm.com/research/jikes. -- Copyright (C) 1983, 1999, International Business Machines Corporation -- and others. All Rights Reserved. -- You must accept the terms of that agreement to use this software. -- This grammar has been augmented with productions that captures -- most errors that a user is likely to make. This saves the need -- to have an error recovery system. -- $Define ---------------------------------------------------------------- $offset /. ./ $location /. /* $rule_text */ #line $next_line "$input_file"./ $action /.act$rule_number, /* $rule_number */./ $null_action /.$offset null_action, /* $rule_number */./ $no_action /.$offset null_action, /* $rule_number */./ ------------------------------------------------------------------------ $Terminals DEFINE_KEY TERMINALS_KEY ALIAS_KEY START_KEY RULES_KEY NAMES_KEY END_KEY EQUIVALENCE ARROW OR EMPTY_SYMBOL ERROR_SYMBOL EOL_SYMBOL EOF_SYMBOL MACRO_NAME SYMBOL BLOCK HBLOCK EOF ------------------------------------------------------------------------ $Alias '::=' ::= EQUIVALENCE '->' ::= ARROW '|' ::= OR $EOF ::= EOF ------------------------------------------------------------------------ $Rules /:static void (*rule_action[]) (void) = {NULL,:/ /. #line $next_line "$input_file" #define SYM1 terminal[stack_top + 1] #define SYM2 terminal[stack_top + 2] #define SYM3 terminal[stack_top + 3] static void null_action(void) { return; } static void add_macro_definition(char *name, struct terminal_type *term) { if (num_defs >= (int)defelmt_size) { defelmt_size += DEFELMT_INCREMENT; defelmt = (struct defelmt_type *) (defelmt == (struct defelmt_type *) NULL ? malloc(defelmt_size * sizeof(struct defelmt_type)) : realloc(defelmt, defelmt_size * sizeof(struct defelmt_type))); if (defelmt == (struct defelmt_type *) NULL) nospace(__FILE__, __LINE__); } defelmt[num_defs].length = (*term).length; defelmt[num_defs].start_line = (*term).start_line; defelmt[num_defs].start_column = (*term).start_column; defelmt[num_defs].end_line = (*term).end_line; defelmt[num_defs].end_column = (*term).end_column; strcpy(defelmt[num_defs].name, name); num_defs++; return; } static void add_block_definition(struct terminal_type *term) { if (num_acts >= (int) actelmt_size) { actelmt_size += ACTELMT_INCREMENT; actelmt = (struct actelmt_type *) (actelmt == (struct actelmt_type *) NULL ? malloc(actelmt_size * sizeof(struct actelmt_type)) : realloc(actelmt, actelmt_size * sizeof(struct actelmt_type))); if (actelmt == (struct actelmt_type *) NULL) nospace(__FILE__, __LINE__); } actelmt[num_acts].rule_number = num_rules; actelmt[num_acts].start_line = (*term).start_line; actelmt[num_acts].start_column = (*term).start_column; actelmt[num_acts].end_line = (*term).end_line; actelmt[num_acts].end_column = (*term).end_column; actelmt[num_acts].header_block = ((*term).kind == HBLOCK_TK); num_acts++; return; } ./ LPG_INPUT ::= [define_block] [terminals_block] [alias_block] [start_block] [rules_block] [names_block] [%END] /:$no_action:/ | bad_symbol /:$no_action:/ bad_symbol ::= EQUIVALENCE /:$offset bad_first_symbol, /* $rule_number */:/ /.$location static void bad_first_symbol(void) { sprintf(msg_line, "First symbol: \"%s\" found in file is illegal. " "Line %d, column %d", SYM1.name, SYM1.start_line, SYM1.start_column); PRNTERR(msg_line); exit(12); } ./ | ARROW /:$offset bad_first_symbol, /* $rule_number */:/ | OR /:$offset bad_first_symbol, /* $rule_number */:/ | EMPTY_SYMBOL /:$offset bad_first_symbol, /* $rule_number */:/ | ERROR_SYMBOL /:$offset bad_first_symbol, /* $rule_number */:/ | MACRO_NAME /:$offset bad_first_symbol, /* $rule_number */:/ | SYMBOL /:$offset bad_first_symbol, /* $rule_number */:/ | BLOCK /:$offset $action:/ /.$location static void act$rule_number(void) { sprintf(msg_line, "Action block cannot be first object in file. " "Line %d, column %d", SYM1.start_line, SYM1.start_column); PRNTERR(msg_line); exit(12); } ./ define_block ::= DEFINE_KEY /:$no_action:/ | DEFINE_KEY macro_list /:$no_action:/ macro_list ::= macro_name_symbol macro_block /:$offset $action:/ /.$location static void act$rule_number(void) { if (action_bit) add_macro_definition(SYM1.name, &(SYM2)); return; } ./ | macro_list macro_name_symbol macro_block /:$offset $action:/ /.$location static void act$rule_number(void) { if (action_bit) add_macro_definition(SYM2.name, &(SYM3)); return; } ./ macro_name_symbol ::= MACRO_NAME /:$no_action:/ | SYMBOL -- Warning, Escape missing ! /:$offset $action:/ /.$location static void act$rule_number(void) { sprintf(msg_line, "Macro name \"%s\" does not start with the " "escape character. Line %d, column %d", SYM1.name, SYM1.start_line, SYM1.start_column); PRNTWNG(msg_line); return; } ./ | '|' -- No Good !!! /:$offset bad_macro_name, /* $rule_number */:/ /.$location static void bad_macro_name(void) { sprintf(msg_line, "Reserved symbol cannot be used as macro name. " "Line %d, column %d", SYM1.start_line, SYM1.start_column); PRNTERR(msg_line); exit(12); } ./ | EMPTY_SYMBOL -- No good !!! /:$offset bad_macro_name, /* $rule_number */:/ | ERROR_SYMBOL -- No good !!! /:$offset bad_macro_name, /* $rule_number */:/ | produces -- No good !!! /:$offset bad_macro_name, /* $rule_number */:/ | BLOCK -- No good !!! /:$offset $action:/ /.$location static void act$rule_number(void) { sprintf(msg_line, "Macro name not supplied for macro definition. " "Line %d, column %d", SYM1.start_line, SYM1.start_column); PRNTERR(msg_line); exit(12); } ./ | DEFINE_KEY -- No good !!! /:$offset $action:/ /.$location static void act$rule_number(void) { sprintf(msg_line, "Macro keyword misplaced. Line %d, column %d", SYM1.start_line, SYM1.start_column); PRNTERR(msg_line); exit(12); } ./ macro_block ::= BLOCK /:$no_action:/ | '|' -- No Good !!! /:$offset definition_expected, /* $rule_number */:/ /.$location static void definition_expected(void) { sprintf(msg_line, "Definition block expected where symbol found. " "Line %d, column %d", SYM1.start_line, SYM1.start_column); PRNTERR(msg_line); exit(12); } ./ | EMPTY_SYMBOL -- No good !!! /:$offset definition_expected, /* $rule_number */:/ | ERROR_SYMBOL -- No good !!! /:$offset definition_expected, /* $rule_number */:/ | produces -- No good !!! /:$offset definition_expected, /* $rule_number */:/ | SYMBOL -- No good !!! /:$offset definition_expected, /* $rule_number */:/ | keyword -- No good !!! /:$offset definition_expected, /* $rule_number */:/ | END_KEY -- No good ! /:$offset definition_expected, /* $rule_number */:/ terminals_block ::= TERMINALS_KEY {terminal_symbol} /:$no_action:/ terminal_symbol ::= SYMBOL /:$offset process_terminal, /* $rule_number */:/ /.$location static void process_terminal(void) { assign_symbol_no(SYM1.name, OMEGA); return; } ./ | '|' /:$offset process_terminal, /* $rule_number */:/ | produces /:$offset process_terminal, /* $rule_number */:/ | DEFINE_KEY -- No Good !!! /:$offset bad_terminal, /* $rule_number */:/ /.$location static void bad_terminal(void) { sprintf(msg_line, "Keyword has been misplaced in Terminal section." " Line %d, column %d", SYM1.start_line, SYM1.start_column); PRNTERR(msg_line); exit(12); } ./ | TERMINALS_KEY -- No Good !!! /:$offset bad_terminal, /* $rule_number */:/ | BLOCK -- No good !!! /:$offset $action:/ /.$location static void act$rule_number(void) { sprintf(msg_line, "Misplaced block found in TERMINALS section." " Line %d, column %d", SYM1.start_line, SYM1.start_column); PRNTERR(msg_line); exit(12); } ./ alias_block ::= ALIAS_KEY {alias_definition} /:$no_action:/ alias_definition ::= alias_lhs produces alias_rhs /:$offset $action:/ /.$location static void act$rule_number(void) { register int image; char tok_string[SYMBOL_SIZE + 1]; switch(SYM3.kind) { case EMPTY_SYMBOL_TK: image = empty; break; case SYMBOL_TK: assign_symbol_no(SYM3.name, OMEGA); image = symbol_image(SYM3.name); break; case ERROR_SYMBOL_TK: if (error_image > num_terminals) { restore_symbol(tok_string, kerror); sprintf(msg_line, "Illegal aliasing to %s prior to its " "definition. Line %d, column %d", tok_string, SYM3.start_line, SYM3.start_column); PRNTERR(msg_line); exit(12); } image = error_image; break; case EOF_SYMBOL_TK: if (eoft_image > num_terminals) { restore_symbol(tok_string, keoft); sprintf(msg_line, "Illegal aliasing to %s prior to its " "definition. Line %d, column %d", tok_string, SYM3.start_line, SYM3.start_column); PRNTERR(msg_line); exit(12); } image = eoft_image; break; case EOL_SYMBOL_TK: if (eolt_image == OMEGA) { sprintf(msg_line, "Illegal aliasing to EOL prior to its " "definition. Line %d, column %d", SYM3.start_line, SYM3.start_column); PRNTERR(msg_line); exit(12); } image = eolt_image; break; default: /* if SYM3.kind == symbol */ image = symbol_image(SYM3.name); break; } switch(SYM1.kind) { case SYMBOL_TK: if (symbol_image(SYM1.name) != OMEGA) { restore_symbol(tok_string, SYM1.name); sprintf(msg_line, "Symbol %s was previously defined. " "Line %d, column %d", tok_string, SYM1.start_line, SYM1.start_column); PRNTERR(msg_line); exit(12); } assign_symbol_no(SYM1.name, image); break; case ERROR_SYMBOL_TK: if (error_image > num_terminals || ! error_maps_bit) { if (image == empty || image == eolt_image || image == eoft_image || image > num_terminals) { restore_symbol(tok_string, kerror); sprintf(msg_line, "Illegal alias for symbol %s. " "Line %d, column %d.", tok_string, SYM1.start_line, SYM1.start_column); PRNTERR(msg_line); exit(12); } alias_map(kerror, image); error_image = image; } else { restore_symbol(tok_string, kerror); sprintf(msg_line, "Symbol %s was previously defined. " "Line %d, column %d", tok_string, SYM1.start_line, SYM1.start_column); PRNTERR(msg_line); exit(12); } break; case EOF_SYMBOL_TK: if (eoft_image > num_terminals) { if (image == empty || image == eolt_image || image == error_image || image > num_terminals) { restore_symbol(tok_string, keoft); sprintf(msg_line, "Illegal alias for symbol %s. " "Line %d, column %d.", tok_string, SYM1.start_line, SYM1.start_column); PRNTERR(msg_line); exit(12); } alias_map(keoft, image); eoft_image = image; } else { restore_symbol(tok_string, keoft); sprintf(msg_line, "Symbol %s was previously defined. " "Line %d, column %d", tok_string, SYM1.start_line, SYM1.start_column); PRNTERR(msg_line); exit(12); } break; default: /* if SYM1.kind == EOL_SYMBOL */ if (eolt_image == OMEGA) { if (image == empty || image == eoft_image || image == error_image || image > num_terminals) { sprintf(msg_line, "Illegal alias for symbol EOL. " "Line %d, column %d.", SYM1.start_line, SYM1.start_column); PRNTERR(msg_line); exit(12); } eolt_image = image; } else { sprintf(msg_line, "Symbol EOL was previously defined. " "Line %d, column %d", SYM1.start_line, SYM1.start_column); PRNTERR(msg_line); exit(12); } break; } return; } ./ | bad_alias_lhs /:$no_action:/ | alias_lhs bad_alias_rhs /:$no_action:/ | alias_lhs produces bad_alias_rhs /:$no_action:/ alias_lhs ::= SYMBOL /:$no_action:/ | ERROR_SYMBOL /:$no_action:/ | EOL_SYMBOL /:$no_action:/ | EOF_SYMBOL /:$no_action:/ alias_rhs ::= SYMBOL /:$no_action:/ | ERROR_SYMBOL /:$no_action:/ | EOL_SYMBOL /:$no_action:/ | EOF_SYMBOL /:$no_action:/ | EMPTY_SYMBOL /:$no_action:/ | '|' /:$no_action:/ | produces /:$no_action:/ bad_alias_rhs ::= DEFINE_KEY /:$offset bad_alias_rhs, /* $rule_number */:/ /.$location static void bad_alias_rhs(void) { sprintf(msg_line, "Misplaced keyword found in Alias section. " "Line %d, column %d", SYM1.start_line, SYM1.start_column); PRNTERR(msg_line); exit(12); } ./ | TERMINALS_KEY /:$offset bad_alias_rhs, /* $rule_number */:/ | ALIAS_KEY /:$offset bad_alias_rhs, /* $rule_number */:/ | BLOCK /:$offset $action:/ /.$location static void act$rule_number(void) { sprintf(msg_line, "Misplaced block found in Alias section. " "Line %d, column %d", SYM1.start_line, SYM1.start_column); PRNTERR(msg_line); exit(12); } ./ bad_alias_lhs ::= bad_alias_rhs /:$no_action:/ | EMPTY_SYMBOL /:$offset $action:/ /.$location static void act$rule_number(void) { sprintf(msg_line, "Empty symbol cannot be aliased. " "Line %d, column %d", SYM1.start_line, SYM1.start_column); PRNTERR(msg_line); exit(12); } ./ | produces /:$offset missing_quote, /* $rule_number */:/ /.$location static void missing_quote(void) { sprintf(msg_line, "Symbol must be quoted when used as a " "grammar symbol. Line %d, column %d", ormark, SYM1.start_line, SYM1.start_column); PRNTERR(msg_line); exit(12); } ./ | '|' /:$offset missing_quote, /* $rule_number */:/ start_block ::= START_KEY {start_symbol} /:$no_action:/ start_symbol ::= SYMBOL /:$offset $action:/ /.$location /*********************************************************************/ /*********************************************************************/ static void act$rule_number(void) { register struct node *q; assign_symbol_no(SYM1.name, OMEGA); q = Allocate_node(); q -> value = symbol_image(SYM1.name); if (start_symbol_root == NULL) q -> next = q; else { q -> next = start_symbol_root -> next; start_symbol_root -> next = q; } start_symbol_root = q; num_rules++; num_items++; SHORT_CHECK(num_items); return; } ./ | '|' -- No Good !!! /:$offset bad_start_symbol, /* $rule_number */:/ /.$location static void bad_start_symbol(void) { sprintf(msg_line, "Symbol cannot be used as Start symbol. " "Line %d, column %d", SYM1.start_line, SYM1.start_column); PRNTERR(msg_line); exit(12); } ./ | EMPTY_SYMBOL -- No good !!! /:$offset bad_start_symbol, /* $rule_number */:/ | ERROR_SYMBOL -- No good !!! /:$offset bad_start_symbol, /* $rule_number */:/ | produces -- No good !!! /:$offset bad_start_symbol, /* $rule_number */:/ | BLOCK -- No good !!! /:$offset $action:/ /.$location static void act$rule_number(void) { sprintf(msg_line, "Misplaced block found in Start section. " "Line %d, column %d", SYM1.start_line, SYM1.start_column); PRNTERR(msg_line); exit(12); } ./ | DEFINE_KEY -- No good !!! /:$offset misplaced_keyword_found_in_START_section, /* $rule_number */:/ /.$location static void misplaced_keyword_found_in_START_section(void) { sprintf(msg_line, "Misplaced keyword found in START section. " "Line %d, column %d", SYM1.start_line, SYM1.start_column); PRNTERR(msg_line); exit(12); } ./ | TERMINALS_KEY -- No good !!! /:$offset misplaced_keyword_found_in_START_section, /* $rule_number */:/ | ALIAS_KEY -- No good !!! /:$offset misplaced_keyword_found_in_START_section, /* $rule_number */:/ | START_KEY -- No good !!! /:$offset misplaced_keyword_found_in_START_section, /* $rule_number */:/ rules_block ::= RULES_KEY /:$offset $action:/ /.$location static void act$rule_number(void) { register struct node *q; if (start_symbol_root == NULL) { q = Allocate_node(); q -> value = empty; q -> next = q; start_symbol_root = q; num_rules = 0; /* One rule */ num_items = 0; /* 0 items */ } build_symno(); return; } ./ | RULES_KEY rule_list /:$offset $action:/ /.$location static void act$rule_number(void) { build_symno(); return; } ./ produces ::= '::=' /:$no_action:/ | '->' /:$no_action:/ rule_list ::= {action_block} SYMBOL produces /:$offset $action:/ /.$location static void act$rule_number(void) { register struct node *q; assign_symbol_no(SYM2.name, OMEGA); if (start_symbol_root == NULL) { q = Allocate_node(); q -> value = symbol_image(SYM2.name); q -> next = q; start_symbol_root = q; num_rules = 1; num_items = 1; } /*********************************************************************/ /* Since we don't know for sure how many start symbols we have, a */ /* "while" loop is used to increment the size of rulehdr. However, */ /* it is highly unlikely that this loop would ever execute more than */ /* once if the size of RULE_INCREMENT is reasonable. */ /*********************************************************************/ while (num_rules >= (int)rulehdr_size) { rulehdr_size += RULEHDR_INCREMENT; rulehdr = (struct rulehdr_type *) (rulehdr == (struct rulehdr_type *) NULL ? malloc(rulehdr_size * sizeof(struct rulehdr_type)) : realloc(rulehdr, rulehdr_size * sizeof(struct rulehdr_type))); if (rulehdr == (struct rulehdr_type *) NULL) nospace(__FILE__, __LINE__); } rulehdr[num_rules].sp = ((SYM3.kind == ARROW_TK) ? TRUE : FALSE); rulehdr[num_rules].lhs = symbol_image(SYM2.name); rulehdr[num_rules].rhs_root = NULL; return; } ./ | rule_list '|' /:$offset $action:/ /.$location static void act$rule_number(void) { num_rules++; if (num_rules >= (int)rulehdr_size) { rulehdr_size += RULEHDR_INCREMENT; rulehdr = (struct rulehdr_type *) (rulehdr == (struct rulehdr_type *) NULL ? malloc(rulehdr_size * sizeof(struct rulehdr_type)) : realloc(rulehdr, rulehdr_size * sizeof(struct rulehdr_type))); if (rulehdr == (struct rulehdr_type *) NULL) nospace(__FILE__, __LINE__); } rulehdr[num_rules].sp = rulehdr[num_rules - 1].sp; rulehdr[num_rules].lhs = OMEGA; rulehdr[num_rules].rhs_root = NULL; return; } ./ | rule_list SYMBOL produces /:$offset $action:/ /.$location static void act$rule_number(void) { num_rules++; if (num_rules >= (int)rulehdr_size) { rulehdr_size += RULEHDR_INCREMENT; rulehdr = (struct rulehdr_type *) (rulehdr == (struct rulehdr_type *) NULL ? malloc(rulehdr_size * sizeof(struct rulehdr_type)) : realloc(rulehdr, rulehdr_size * sizeof(struct rulehdr_type))); if (rulehdr == (struct rulehdr_type *) NULL) nospace(__FILE__, __LINE__); } rulehdr[num_rules].sp = ((SYM3.kind == ARROW_TK) ? TRUE : FALSE); assign_symbol_no(SYM2.name, OMEGA); rulehdr[num_rules].lhs = symbol_image(SYM2.name); rulehdr[num_rules].rhs_root = NULL; return; } ./ | rule_list EMPTY_SYMBOL /:$no_action:/ | rule_list action_block /:$no_action:/ | rule_list ERROR_SYMBOL /:$offset $action:/ /.$location static void act$rule_number(void) { register struct node *q; char tok_string[SYMBOL_SIZE + 1]; if (error_image == DEFAULT_SYMBOL) { restore_symbol(tok_string, kerror); sprintf(msg_line, "%s not declared or aliased to terminal " "symbol. Line %d, column %d", tok_string, SYM2.start_line, SYM2.start_column); PRNTERR(msg_line); exit(12); } q = Allocate_node(); q -> value = error_image; num_items++; SHORT_CHECK(num_items); if (rulehdr[num_rules].rhs_root == NULL) q -> next = q; else { q -> next = rulehdr[num_rules].rhs_root -> next; rulehdr[num_rules].rhs_root -> next = q; } rulehdr[num_rules].rhs_root = q; return; } ./ | rule_list SYMBOL /:$offset $action:/ /.$location static void act$rule_number(void) { register int sym; register struct node *q; assign_symbol_no(SYM2.name, OMEGA); sym = symbol_image(SYM2.name); if (sym != empty) { if (sym == eoft_image) { sprintf(msg_line, "End-of-file symbol cannot be used " "in rule. Line %d, column %d", SYM2.start_line, SYM2.start_column); PRNTERR(msg_line); exit(12); } q = Allocate_node(); q -> value = sym; num_items++; SHORT_CHECK(num_items); if (rulehdr[num_rules].rhs_root == NULL) q -> next = q; else { q -> next = rulehdr[num_rules].rhs_root -> next; rulehdr[num_rules].rhs_root -> next = q; } rulehdr[num_rules].rhs_root = q; } return; } ./ | '|' -- can't be first SYMBOL /:$offset bad_first_symbol_in_RULES_section, /* $rule_number */:/ /.$location static void bad_first_symbol_in_RULES_section(void) { sprintf(msg_line, "First symbol in Rules section is not " "a valid left-hand side.\n Line %d, column %d", SYM1.start_line, SYM1.start_column); PRNTERR(msg_line); exit(12); } ./ | EMPTY_SYMBOL -- can't be first SYMBOL /:$offset bad_first_symbol_in_RULES_section, /* $rule_number */:/ | ERROR_SYMBOL -- can't be first SYMBOL /:$offset bad_first_symbol_in_RULES_section, /* $rule_number */:/ | keyword -- keyword out of place /:$offset bad_first_symbol_in_RULES_section, /* $rule_number */:/ | rule_list '|' produces -- No good !!! /:$offset rule_without_left_hand_side, /* $rule_number */:/ /.$location static void rule_without_left_hand_side(void) { sprintf(msg_line, "Rule without left-hand-side. Line %d, column %d", SYM3.start_line, SYM3.start_column); PRNTERR(msg_line); exit(12); } ./ | rule_list action_block produces -- No good !!! /:$offset rule_without_left_hand_side, /* $rule_number */:/ | rule_list EMPTY_SYMBOL produces -- No good !!! /:$offset rule_without_left_hand_side, /* $rule_number */:/ | rule_list keyword produces -- No good !!! /:$offset $action:/ /.$location static void act$rule_number(void) { sprintf(msg_line, "Misplaced keyword found in Rules section " "Line %d, column %d", SYM2.start_line, SYM2.start_column); PRNTERR(msg_line); exit(12); } ./ action_block ::= BLOCK /:$offset $action:/ /.$location static void act$rule_number(void) { if (action_bit) add_block_definition(&(SYM1)); return; } ./ | HBLOCK /:$offset $action:/ /.$location static void act$rule_number(void) { if (action_bit) add_block_definition(&(SYM1)); return; } ./ keyword ::= DEFINE_KEY /:$offset misplaced_keyword_found_in_RULES_section, /* $rule_number */:/ /.$location static void misplaced_keyword_found_in_RULES_section(void) { sprintf(msg_line, "Misplaced keyword found in RULES section. " "Line %d, column %d", SYM1.start_line, SYM1.start_column); PRNTERR(msg_line); exit(12); } ./ | TERMINALS_KEY /:$offset misplaced_keyword_found_in_RULES_section, /* $rule_number */:/ | ALIAS_KEY /:$offset misplaced_keyword_found_in_RULES_section, /* $rule_number */:/ | START_KEY /:$offset misplaced_keyword_found_in_RULES_section, /* $rule_number */:/ | RULES_KEY /:$offset misplaced_keyword_found_in_RULES_section, /* $rule_number */:/ names_block ::= NAMES_KEY {names_definition} /:$no_action:/ names_definition ::= name produces name /:$offset $action:/ /.$location static void act$rule_number(void) { if (error_maps_bit) { int symbol; switch(SYM1.kind) { case EMPTY_SYMBOL_TK: symbol = empty; break; case ERROR_SYMBOL_TK: symbol = error_image; break; case EOL_SYMBOL_TK: symbol = eolt_image; break; case EOF_SYMBOL_TK: symbol = eoft_image; break; default: symbol = symbol_image(SYM1.name); break; } if (symbol == OMEGA) { sprintf(msg_line, "Symbol %s is undefined. Line %d, column %d", SYM1.name, SYM1.start_line, SYM1.start_column); PRNTERR(msg_line); exit(12); } if (symno[symbol].name_index != OMEGA) { sprintf(msg_line, "Symbol %s has been named more than once. " "Line %d, column %d.", SYM1.name, SYM1.start_line, SYM1.start_column); PRNTERR(msg_line); exit(12); } symno[symbol].name_index = name_map(SYM3.name); } return; } ./ | bad_name produces name /:$no_action:/ | name produces bad_name /:$no_action:/ name ::= SYMBOL /:$no_action:/ | EMPTY_SYMBOL /:$no_action:/ | ERROR_SYMBOL /:$no_action:/ | EOL_SYMBOL /:$no_action:/ | EOF_SYMBOL /:$no_action:/ | '|' /:$no_action:/ | produces /:$no_action:/ bad_name ::= DEFINE_KEY /:$offset misplaced_keyword_found_in_NAMES_section, /* $rule_number */:/ /.$location static void misplaced_keyword_found_in_NAMES_section(void) { sprintf(msg_line, "Keyword has been misplaced in NAMES section." " Line %d, column %d", SYM1.start_line, SYM1.start_column); PRNTERR(msg_line); exit(12); } ./ | TERMINALS_KEY /:$offset misplaced_keyword_found_in_NAMES_section, /* $rule_number */:/ | ALIAS_KEY /:$offset misplaced_keyword_found_in_NAMES_section, /* $rule_number */:/ | START_KEY /:$offset misplaced_keyword_found_in_NAMES_section, /* $rule_number */:/ | RULES_KEY /:$offset misplaced_keyword_found_in_NAMES_section, /* $rule_number */:/ | NAMES_KEY /:$offset misplaced_keyword_found_in_NAMES_section, /* $rule_number */:/ | BLOCK /:$offset $action:/ /.$location static void act$rule_number(void) { sprintf(msg_line, "Misplaced action block found in NAMES " "section. Line %d, column %d", SYM1.start_line, SYM1.start_column); PRNTERR(msg_line); exit(12); } ./ | MACRO_NAME /:$offset $action:/ /.$location static void act$rule_number(void) { sprintf(msg_line, "Misplaced macro name found in NAMES " "section. Line %d, column %d", SYM1.start_line, SYM1.start_column); PRNTERR(msg_line); exit(12); } ./ ------------------------------------------------------------------------ [define_block] ::= $EMPTY /:$no_action:/ | define_block /:$no_action:/ [terminals_block] ::= $EMPTY /:$offset process_TERMINALS_section, /* $rule_number */:/ /.$location static void process_TERMINALS_section(void) { num_terminals = num_symbols; assign_symbol_no(keoft, OMEGA); eoft_image = symbol_image(keoft); if (error_maps_bit) { assign_symbol_no(kerror, OMEGA); error_image = symbol_image(kerror); } else error_image = DEFAULT_SYMBOL; /* should be 0 */ assign_symbol_no(kaccept, OMEGA); accept_image = symbol_image(kaccept); return; } ./ | terminals_block /:$offset process_TERMINALS_section, /* $rule_number */:/ [alias_block] ::= $EMPTY /:$offset process_ALIAS_section, /* $rule_number */:/ /.$location static void process_ALIAS_section(void) { register int i, k; register struct hash_type *p; k = 0; if (eoft_image <= num_terminals) k++; else num_terminals++; if (error_maps_bit) { if (error_image <= num_terminals) k++; else { num_terminals++; if (k == 1) error_image--; } } if (k > 0) { for (i = 0; i < HT_SIZE; i++) { p = hash_table[i]; while(p != NULL) { if (p -> number > num_terminals) p -> number -= k; else if (p -> number < -num_terminals) p -> number += k; p = p -> link; } } num_symbols -= k; accept_image -= k; } if (eolt_image == OMEGA) eolt_image = eoft_image; if (error_image == DEFAULT_SYMBOL) alias_map(kerror, DEFAULT_SYMBOL); return; } ./ | alias_block /:$offset process_ALIAS_section, /* $rule_number */:/ [start_block] ::= $EMPTY /:$no_action:/ | start_block /:$no_action:/ [rules_block] ::= $EMPTY /:$no_action:/ | rules_block /:$no_action:/ [names_block] ::= $EMPTY /:$no_action:/ | names_block /:$no_action:/ [%END] ::= $EMPTY /:$no_action:/ | END_KEY /:$no_action:/ ------------------------------------------------------------------------ {terminal_symbol} ::= $EMPTY /:$offset $action:/ /.$location static void act$rule_number(void) { assign_symbol_no(kempty, OMEGA); empty = symbol_image(kempty); return; } ./ | {terminal_symbol} terminal_symbol /:$no_action:/ {start_symbol} ::= $EMPTY /:$no_action:/ | {start_symbol} start_symbol /:$no_action:/ {alias_definition} ::= $EMPTY /:$no_action:/ | {alias_definition} alias_definition /:$no_action:/ {names_definition} ::= $EMPTY /:$no_action:/ | {names_definition} names_definition /:$no_action:/ {action_block} ::= $EMPTY /:$no_action:/ | {action_block} action_block /:$no_action:/ /:$offset NULL};:/ $End jikespg-1.3/src/lpgact.h000066400000000000000000000114621167345774400152510ustar00rootroot00000000000000// $Id: lpgact.h,v 1.3 1999/11/08 23:22:40 shields Exp $ // // This software is subject to the terms of the IBM Jikes Compiler // License Agreement available at the following URL: // http://www.ibm.com/research/jikes. // Copyright (C) 1996, 1998, International Business Machines Corporation // and others. All Rights Reserved. // You must accept the terms of that agreement to use this software. // static void (*rule_action[]) (void) = {NULL, null_action, /* 1 */ null_action, /* 2 */ bad_first_symbol, /* 3 */ bad_first_symbol, /* 4 */ bad_first_symbol, /* 5 */ bad_first_symbol, /* 6 */ bad_first_symbol, /* 7 */ bad_first_symbol, /* 8 */ bad_first_symbol, /* 9 */ act10, /* 10 */ null_action, /* 11 */ null_action, /* 12 */ act13, /* 13 */ act14, /* 14 */ null_action, /* 15 */ act16, /* 16 */ bad_macro_name, /* 17 */ bad_macro_name, /* 18 */ bad_macro_name, /* 19 */ bad_macro_name, /* 20 */ act21, /* 21 */ act22, /* 22 */ null_action, /* 23 */ definition_expected, /* 24 */ definition_expected, /* 25 */ definition_expected, /* 26 */ definition_expected, /* 27 */ definition_expected, /* 28 */ definition_expected, /* 29 */ definition_expected, /* 30 */ null_action, /* 31 */ process_terminal, /* 32 */ process_terminal, /* 33 */ process_terminal, /* 34 */ bad_terminal, /* 35 */ bad_terminal, /* 36 */ act37, /* 37 */ null_action, /* 38 */ act39, /* 39 */ null_action, /* 40 */ null_action, /* 41 */ null_action, /* 42 */ null_action, /* 43 */ null_action, /* 44 */ null_action, /* 45 */ null_action, /* 46 */ null_action, /* 47 */ null_action, /* 48 */ null_action, /* 49 */ null_action, /* 50 */ null_action, /* 51 */ null_action, /* 52 */ null_action, /* 53 */ bad_alias_rhs, /* 54 */ bad_alias_rhs, /* 55 */ bad_alias_rhs, /* 56 */ act57, /* 57 */ null_action, /* 58 */ act59, /* 59 */ missing_quote, /* 60 */ missing_quote, /* 61 */ null_action, /* 62 */ act63, /* 63 */ bad_start_symbol, /* 64 */ bad_start_symbol, /* 65 */ bad_start_symbol, /* 66 */ bad_start_symbol, /* 67 */ act68, /* 68 */ misplaced_keyword_found_in_START_section, /* 69 */ misplaced_keyword_found_in_START_section, /* 70 */ misplaced_keyword_found_in_START_section, /* 71 */ misplaced_keyword_found_in_START_section, /* 72 */ act73, /* 73 */ act74, /* 74 */ null_action, /* 75 */ null_action, /* 76 */ act77, /* 77 */ act78, /* 78 */ act79, /* 79 */ null_action, /* 80 */ null_action, /* 81 */ act82, /* 82 */ act83, /* 83 */ bad_first_symbol_in_RULES_section, /* 84 */ bad_first_symbol_in_RULES_section, /* 85 */ bad_first_symbol_in_RULES_section, /* 86 */ bad_first_symbol_in_RULES_section, /* 87 */ rule_without_left_hand_side, /* 88 */ rule_without_left_hand_side, /* 89 */ rule_without_left_hand_side, /* 90 */ act91, /* 91 */ act92, /* 92 */ act93, /* 93 */ misplaced_keyword_found_in_RULES_section, /* 94 */ misplaced_keyword_found_in_RULES_section, /* 95 */ misplaced_keyword_found_in_RULES_section, /* 96 */ misplaced_keyword_found_in_RULES_section, /* 97 */ misplaced_keyword_found_in_RULES_section, /* 98 */ null_action, /* 99 */ act100, /* 100 */ null_action, /* 101 */ null_action, /* 102 */ null_action, /* 103 */ null_action, /* 104 */ null_action, /* 105 */ null_action, /* 106 */ null_action, /* 107 */ null_action, /* 108 */ null_action, /* 109 */ misplaced_keyword_found_in_NAMES_section, /* 110 */ misplaced_keyword_found_in_NAMES_section, /* 111 */ misplaced_keyword_found_in_NAMES_section, /* 112 */ misplaced_keyword_found_in_NAMES_section, /* 113 */ misplaced_keyword_found_in_NAMES_section, /* 114 */ misplaced_keyword_found_in_NAMES_section, /* 115 */ act116, /* 116 */ act117, /* 117 */ null_action, /* 118 */ null_action, /* 119 */ process_TERMINALS_section, /* 120 */ process_TERMINALS_section, /* 121 */ process_ALIAS_section, /* 122 */ process_ALIAS_section, /* 123 */ null_action, /* 124 */ null_action, /* 125 */ null_action, /* 126 */ null_action, /* 127 */ null_action, /* 128 */ null_action, /* 129 */ null_action, /* 130 */ null_action, /* 131 */ act132, /* 132 */ null_action, /* 133 */ null_action, /* 134 */ null_action, /* 135 */ null_action, /* 136 */ null_action, /* 137 */ null_action, /* 138 */ null_action, /* 139 */ null_action, /* 140 */ null_action, /* 141 */ NULL}; jikespg-1.3/src/lpgact.i000066400000000000000000000600431167345774400152510ustar00rootroot00000000000000// $Id: lpgact.i,v 1.2 1999/11/08 23:22:40 shields Exp $ // // This software is subject to the terms of the IBM Jikes Compiler // License Agreement available at the following URL: // http://www.ibm.com/research/jikes. // Copyright (C) 1996, 1998, International Business Machines Corporation // and others. All Rights Reserved. // You must accept the terms of that agreement to use this software. // #line 65 "jikespg.g" #define SYM1 terminal[stack_top + 1] #define SYM2 terminal[stack_top + 2] #define SYM3 terminal[stack_top + 3] static void null_action(void) { return; } static void add_macro_definition(char *name, struct terminal_type *term) { if (num_defs >= (int)defelmt_size) { defelmt_size += DEFELMT_INCREMENT; defelmt = (struct defelmt_type *) (defelmt == (struct defelmt_type *) NULL ? malloc(defelmt_size * sizeof(struct defelmt_type)) : realloc(defelmt, defelmt_size * sizeof(struct defelmt_type))); if (defelmt == (struct defelmt_type *) NULL) nospace(__FILE__, __LINE__); } defelmt[num_defs].length = (*term).length; defelmt[num_defs].start_line = (*term).start_line; defelmt[num_defs].start_column = (*term).start_column; defelmt[num_defs].end_line = (*term).end_line; defelmt[num_defs].end_column = (*term).end_column; strcpy(defelmt[num_defs].name, name); num_defs++; return; } static void add_block_definition(struct terminal_type *term) { if (num_acts >= (int) actelmt_size) { actelmt_size += ACTELMT_INCREMENT; actelmt = (struct actelmt_type *) (actelmt == (struct actelmt_type *) NULL ? malloc(actelmt_size * sizeof(struct actelmt_type)) : realloc(actelmt, actelmt_size * sizeof(struct actelmt_type))); if (actelmt == (struct actelmt_type *) NULL) nospace(__FILE__, __LINE__); } actelmt[num_acts].rule_number = num_rules; actelmt[num_acts].start_line = (*term).start_line; actelmt[num_acts].start_column = (*term).start_column; actelmt[num_acts].end_line = (*term).end_line; actelmt[num_acts].end_column = (*term).end_column; actelmt[num_acts].header_block = ((*term).kind == HBLOCK_TK); num_acts++; return; } /* bad_symbol ::= EQUIVALENCE */ #line 136 "jikespg.g" static void bad_first_symbol(void) { sprintf(msg_line, "First symbol: \"%s\" found in file is illegal. " "Line %d, column %d", SYM1.name, SYM1.start_line, SYM1.start_column); PRNTERR(msg_line); exit(12); } /* bad_symbol ::= BLOCK */ #line 162 "jikespg.g" static void act10(void) { sprintf(msg_line, "Action block cannot be first object in file. " "Line %d, column %d", SYM1.start_line, SYM1.start_column); PRNTERR(msg_line); exit(12); } /* macro_list ::= macro_name_symbol macro_block */ #line 182 "jikespg.g" static void act13(void) { if (action_bit) add_macro_definition(SYM1.name, &(SYM2)); return; } /* macro_list ::= macro_list macro_name_symbol macro_block */ #line 193 "jikespg.g" static void act14(void) { if (action_bit) add_macro_definition(SYM2.name, &(SYM3)); return; } /* macro_name_symbol ::= SYMBOL */ #line 207 "jikespg.g" static void act16(void) { sprintf(msg_line, "Macro name \"%s\" does not start with the " "escape character. Line %d, column %d", SYM1.name, SYM1.start_line, SYM1.start_column); PRNTWNG(msg_line); return; } /* macro_name_symbol ::= OR */ #line 221 "jikespg.g" static void bad_macro_name(void) { sprintf(msg_line, "Reserved symbol cannot be used as macro name. " "Line %d, column %d", SYM1.start_line, SYM1.start_column); PRNTERR(msg_line); exit(12); } /* macro_name_symbol ::= BLOCK */ #line 241 "jikespg.g" static void act21(void) { sprintf(msg_line, "Macro name not supplied for macro definition. " "Line %d, column %d", SYM1.start_line, SYM1.start_column); PRNTERR(msg_line); exit(12); } /* macro_name_symbol ::= DEFINE_KEY */ #line 255 "jikespg.g" static void act22(void) { sprintf(msg_line, "Macro keyword misplaced. Line %d, column %d", SYM1.start_line, SYM1.start_column); PRNTERR(msg_line); exit(12); } /* macro_block ::= OR */ #line 271 "jikespg.g" static void definition_expected(void) { sprintf(msg_line, "Definition block expected where symbol found. " "Line %d, column %d", SYM1.start_line, SYM1.start_column); PRNTERR(msg_line); exit(12); } /* terminal_symbol ::= SYMBOL */ #line 302 "jikespg.g" static void process_terminal(void) { assign_symbol_no(SYM1.name, OMEGA); return; } /* terminal_symbol ::= DEFINE_KEY */ #line 316 "jikespg.g" static void bad_terminal(void) { sprintf(msg_line, "Keyword has been misplaced in Terminal section." " Line %d, column %d", SYM1.start_line, SYM1.start_column); PRNTERR(msg_line); exit(12); } /* terminal_symbol ::= BLOCK */ #line 332 "jikespg.g" static void act37(void) { sprintf(msg_line, "Misplaced block found in TERMINALS section." " Line %d, column %d", SYM1.start_line, SYM1.start_column); PRNTERR(msg_line); exit(12); } /* alias_definition ::= alias_lhs produces alias_rhs */ #line 350 "jikespg.g" static void act39(void) { register int image; char tok_string[SYMBOL_SIZE + 1]; switch(SYM3.kind) { case EMPTY_SYMBOL_TK: image = empty; break; case SYMBOL_TK: assign_symbol_no(SYM3.name, OMEGA); image = symbol_image(SYM3.name); break; case ERROR_SYMBOL_TK: if (error_image > num_terminals) { restore_symbol(tok_string, kerror); sprintf(msg_line, "Illegal aliasing to %s prior to its " "definition. Line %d, column %d", tok_string, SYM3.start_line, SYM3.start_column); PRNTERR(msg_line); exit(12); } image = error_image; break; case EOF_SYMBOL_TK: if (eoft_image > num_terminals) { restore_symbol(tok_string, keoft); sprintf(msg_line, "Illegal aliasing to %s prior to its " "definition. Line %d, column %d", tok_string, SYM3.start_line, SYM3.start_column); PRNTERR(msg_line); exit(12); } image = eoft_image; break; case EOL_SYMBOL_TK: if (eolt_image == OMEGA) { sprintf(msg_line, "Illegal aliasing to EOL prior to its " "definition. Line %d, column %d", SYM3.start_line, SYM3.start_column); PRNTERR(msg_line); exit(12); } image = eolt_image; break; default: /* if SYM3.kind == symbol */ image = symbol_image(SYM3.name); break; } switch(SYM1.kind) { case SYMBOL_TK: if (symbol_image(SYM1.name) != OMEGA) { restore_symbol(tok_string, SYM1.name); sprintf(msg_line, "Symbol %s was previously defined. " "Line %d, column %d", tok_string, SYM1.start_line, SYM1.start_column); PRNTERR(msg_line); exit(12); } assign_symbol_no(SYM1.name, image); break; case ERROR_SYMBOL_TK: if (error_image > num_terminals || ! error_maps_bit) { if (image == empty || image == eolt_image || image == eoft_image || image > num_terminals) { restore_symbol(tok_string, kerror); sprintf(msg_line, "Illegal alias for symbol %s. " "Line %d, column %d.", tok_string, SYM1.start_line, SYM1.start_column); PRNTERR(msg_line); exit(12); } alias_map(kerror, image); error_image = image; } else { restore_symbol(tok_string, kerror); sprintf(msg_line, "Symbol %s was previously defined. " "Line %d, column %d", tok_string, SYM1.start_line, SYM1.start_column); PRNTERR(msg_line); exit(12); } break; case EOF_SYMBOL_TK: if (eoft_image > num_terminals) { if (image == empty || image == eolt_image || image == error_image || image > num_terminals) { restore_symbol(tok_string, keoft); sprintf(msg_line, "Illegal alias for symbol %s. " "Line %d, column %d.", tok_string, SYM1.start_line, SYM1.start_column); PRNTERR(msg_line); exit(12); } alias_map(keoft, image); eoft_image = image; } else { restore_symbol(tok_string, keoft); sprintf(msg_line, "Symbol %s was previously defined. " "Line %d, column %d", tok_string, SYM1.start_line, SYM1.start_column); PRNTERR(msg_line); exit(12); } break; default: /* if SYM1.kind == EOL_SYMBOL */ if (eolt_image == OMEGA) { if (image == empty || image == eoft_image || image == error_image || image > num_terminals) { sprintf(msg_line, "Illegal alias for symbol EOL. " "Line %d, column %d.", SYM1.start_line, SYM1.start_column); PRNTERR(msg_line); exit(12); } eolt_image = image; } else { sprintf(msg_line, "Symbol EOL was previously defined. " "Line %d, column %d", SYM1.start_line, SYM1.start_column); PRNTERR(msg_line); exit(12); } break; } return; } /* bad_alias_rhs ::= DEFINE_KEY */ #line 558 "jikespg.g" static void bad_alias_rhs(void) { sprintf(msg_line, "Misplaced keyword found in Alias section. " "Line %d, column %d", SYM1.start_line, SYM1.start_column); PRNTERR(msg_line); exit(12); } /* bad_alias_rhs ::= BLOCK */ #line 576 "jikespg.g" static void act57(void) { sprintf(msg_line, "Misplaced block found in Alias section. " "Line %d, column %d", SYM1.start_line, SYM1.start_column); PRNTERR(msg_line); exit(12); } /* bad_alias_lhs ::= EMPTY_SYMBOL */ #line 594 "jikespg.g" static void act59(void) { sprintf(msg_line, "Empty symbol cannot be aliased. " "Line %d, column %d", SYM1.start_line, SYM1.start_column); PRNTERR(msg_line); exit(12); } /* bad_alias_lhs ::= produces */ #line 608 "jikespg.g" static void missing_quote(void) { sprintf(msg_line, "Symbol must be quoted when used as a " "grammar symbol. Line %d, column %d", ormark, SYM1.start_line, SYM1.start_column); PRNTERR(msg_line); exit(12); } /* start_symbol ::= SYMBOL */ #line 630 "jikespg.g" /*********************************************************************/ /*********************************************************************/ static void act63(void) { register struct node *q; assign_symbol_no(SYM1.name, OMEGA); q = Allocate_node(); q -> value = symbol_image(SYM1.name); if (start_symbol_root == NULL) q -> next = q; else { q -> next = start_symbol_root -> next; start_symbol_root -> next = q; } start_symbol_root = q; num_rules++; num_items++; SHORT_CHECK(num_items); return; } /* start_symbol ::= OR */ #line 657 "jikespg.g" static void bad_start_symbol(void) { sprintf(msg_line, "Symbol cannot be used as Start symbol. " "Line %d, column %d", SYM1.start_line, SYM1.start_column); PRNTERR(msg_line); exit(12); } /* start_symbol ::= BLOCK */ #line 677 "jikespg.g" static void act68(void) { sprintf(msg_line, "Misplaced block found in Start section. " "Line %d, column %d", SYM1.start_line, SYM1.start_column); PRNTERR(msg_line); exit(12); } /* start_symbol ::= DEFINE_KEY */ #line 691 "jikespg.g" static void misplaced_keyword_found_in_START_section(void) { sprintf(msg_line, "Misplaced keyword found in START section. " "Line %d, column %d", SYM1.start_line, SYM1.start_column); PRNTERR(msg_line); exit(12); } /* rules_block ::= RULES_KEY */ #line 712 "jikespg.g" static void act73(void) { register struct node *q; if (start_symbol_root == NULL) { q = Allocate_node(); q -> value = empty; q -> next = q; start_symbol_root = q; num_rules = 0; /* One rule */ num_items = 0; /* 0 items */ } build_symno(); return; } /* rules_block ::= RULES_KEY rule_list */ #line 733 "jikespg.g" static void act74(void) { build_symno(); return; } /* rule_list ::= {action_block} SYMBOL produces */ #line 749 "jikespg.g" static void act77(void) { register struct node *q; assign_symbol_no(SYM2.name, OMEGA); if (start_symbol_root == NULL) { q = Allocate_node(); q -> value = symbol_image(SYM2.name); q -> next = q; start_symbol_root = q; num_rules = 1; num_items = 1; } /*********************************************************************/ /* Since we don't know for sure how many start symbols we have, a */ /* "while" loop is used to increment the size of rulehdr. However, */ /* it is highly unlikely that this loop would ever execute more than */ /* once if the size of RULE_INCREMENT is reasonable. */ /*********************************************************************/ while (num_rules >= (int)rulehdr_size) { rulehdr_size += RULEHDR_INCREMENT; rulehdr = (struct rulehdr_type *) (rulehdr == (struct rulehdr_type *) NULL ? malloc(rulehdr_size * sizeof(struct rulehdr_type)) : realloc(rulehdr, rulehdr_size * sizeof(struct rulehdr_type))); if (rulehdr == (struct rulehdr_type *) NULL) nospace(__FILE__, __LINE__); } rulehdr[num_rules].sp = ((SYM3.kind == ARROW_TK) ? TRUE : FALSE); rulehdr[num_rules].lhs = symbol_image(SYM2.name); rulehdr[num_rules].rhs_root = NULL; return; } /* rule_list ::= rule_list OR */ #line 794 "jikespg.g" static void act78(void) { num_rules++; if (num_rules >= (int)rulehdr_size) { rulehdr_size += RULEHDR_INCREMENT; rulehdr = (struct rulehdr_type *) (rulehdr == (struct rulehdr_type *) NULL ? malloc(rulehdr_size * sizeof(struct rulehdr_type)) : realloc(rulehdr, rulehdr_size * sizeof(struct rulehdr_type))); if (rulehdr == (struct rulehdr_type *) NULL) nospace(__FILE__, __LINE__); } rulehdr[num_rules].sp = rulehdr[num_rules - 1].sp; rulehdr[num_rules].lhs = OMEGA; rulehdr[num_rules].rhs_root = NULL; return; } /* rule_list ::= rule_list SYMBOL produces */ #line 817 "jikespg.g" static void act79(void) { num_rules++; if (num_rules >= (int)rulehdr_size) { rulehdr_size += RULEHDR_INCREMENT; rulehdr = (struct rulehdr_type *) (rulehdr == (struct rulehdr_type *) NULL ? malloc(rulehdr_size * sizeof(struct rulehdr_type)) : realloc(rulehdr, rulehdr_size * sizeof(struct rulehdr_type))); if (rulehdr == (struct rulehdr_type *) NULL) nospace(__FILE__, __LINE__); } rulehdr[num_rules].sp = ((SYM3.kind == ARROW_TK) ? TRUE : FALSE); assign_symbol_no(SYM2.name, OMEGA); rulehdr[num_rules].lhs = symbol_image(SYM2.name); rulehdr[num_rules].rhs_root = NULL; return; } /* rule_list ::= rule_list ERROR_SYMBOL */ #line 846 "jikespg.g" static void act82(void) { register struct node *q; char tok_string[SYMBOL_SIZE + 1]; if (error_image == DEFAULT_SYMBOL) { restore_symbol(tok_string, kerror); sprintf(msg_line, "%s not declared or aliased to terminal " "symbol. Line %d, column %d", tok_string, SYM2.start_line, SYM2.start_column); PRNTERR(msg_line); exit(12); } q = Allocate_node(); q -> value = error_image; num_items++; SHORT_CHECK(num_items); if (rulehdr[num_rules].rhs_root == NULL) q -> next = q; else { q -> next = rulehdr[num_rules].rhs_root -> next; rulehdr[num_rules].rhs_root -> next = q; } rulehdr[num_rules].rhs_root = q; return; } /* rule_list ::= rule_list SYMBOL */ #line 881 "jikespg.g" static void act83(void) { register int sym; register struct node *q; assign_symbol_no(SYM2.name, OMEGA); sym = symbol_image(SYM2.name); if (sym != empty) { if (sym == eoft_image) { sprintf(msg_line, "End-of-file symbol cannot be used " "in rule. Line %d, column %d", SYM2.start_line, SYM2.start_column); PRNTERR(msg_line); exit(12); } q = Allocate_node(); q -> value = sym; num_items++; SHORT_CHECK(num_items); if (rulehdr[num_rules].rhs_root == NULL) q -> next = q; else { q -> next = rulehdr[num_rules].rhs_root -> next; rulehdr[num_rules].rhs_root -> next = q; } rulehdr[num_rules].rhs_root = q; } return; } /* rule_list ::= OR */ #line 919 "jikespg.g" static void bad_first_symbol_in_RULES_section(void) { sprintf(msg_line, "First symbol in Rules section is not " "a valid left-hand side.\n Line %d, column %d", SYM1.start_line, SYM1.start_column); PRNTERR(msg_line); exit(12); } /* rule_list ::= rule_list OR produces */ #line 939 "jikespg.g" static void rule_without_left_hand_side(void) { sprintf(msg_line, "Rule without left-hand-side. Line %d, column %d", SYM3.start_line, SYM3.start_column); PRNTERR(msg_line); exit(12); } /* rule_list ::= rule_list keyword produces */ #line 956 "jikespg.g" static void act91(void) { sprintf(msg_line, "Misplaced keyword found in Rules section " "Line %d, column %d", SYM2.start_line, SYM2.start_column); PRNTERR(msg_line); exit(12); } /* action_block ::= BLOCK */ #line 971 "jikespg.g" static void act92(void) { if (action_bit) add_block_definition(&(SYM1)); return; } /* action_block ::= HBLOCK */ #line 982 "jikespg.g" static void act93(void) { if (action_bit) add_block_definition(&(SYM1)); return; } /* keyword ::= DEFINE_KEY */ #line 994 "jikespg.g" static void misplaced_keyword_found_in_RULES_section(void) { sprintf(msg_line, "Misplaced keyword found in RULES section. " "Line %d, column %d", SYM1.start_line, SYM1.start_column); PRNTERR(msg_line); exit(12); } /* names_definition ::= name produces name */ #line 1020 "jikespg.g" static void act100(void) { if (error_maps_bit) { int symbol; switch(SYM1.kind) { case EMPTY_SYMBOL_TK: symbol = empty; break; case ERROR_SYMBOL_TK: symbol = error_image; break; case EOL_SYMBOL_TK: symbol = eolt_image; break; case EOF_SYMBOL_TK: symbol = eoft_image; break; default: symbol = symbol_image(SYM1.name); break; } if (symbol == OMEGA) { sprintf(msg_line, "Symbol %s is undefined. Line %d, column %d", SYM1.name, SYM1.start_line, SYM1.start_column); PRNTERR(msg_line); exit(12); } if (symno[symbol].name_index != OMEGA) { sprintf(msg_line, "Symbol %s has been named more than once. " "Line %d, column %d.", SYM1.name, SYM1.start_line, SYM1.start_column); PRNTERR(msg_line); exit(12); } symno[symbol].name_index = name_map(SYM3.name); } return; } /* bad_name ::= DEFINE_KEY */ #line 1098 "jikespg.g" static void misplaced_keyword_found_in_NAMES_section(void) { sprintf(msg_line, "Keyword has been misplaced in NAMES section." " Line %d, column %d", SYM1.start_line, SYM1.start_column); PRNTERR(msg_line); exit(12); } /* bad_name ::= BLOCK */ #line 1122 "jikespg.g" static void act116(void) { sprintf(msg_line, "Misplaced action block found in NAMES " "section. Line %d, column %d", SYM1.start_line, SYM1.start_column); PRNTERR(msg_line); exit(12); } /* bad_name ::= MACRO_NAME */ #line 1136 "jikespg.g" static void act117(void) { sprintf(msg_line, "Misplaced macro name found in NAMES " "section. Line %d, column %d", SYM1.start_line, SYM1.start_column); PRNTERR(msg_line); exit(12); } /* [terminals_block] ::= */ #line 1158 "jikespg.g" static void process_TERMINALS_section(void) { num_terminals = num_symbols; assign_symbol_no(keoft, OMEGA); eoft_image = symbol_image(keoft); if (error_maps_bit) { assign_symbol_no(kerror, OMEGA); error_image = symbol_image(kerror); } else error_image = DEFAULT_SYMBOL; /* should be 0 */ assign_symbol_no(kaccept, OMEGA); accept_image = symbol_image(kaccept); return; } /* [alias_block] ::= */ #line 1183 "jikespg.g" static void process_ALIAS_section(void) { register int i, k; register struct hash_type *p; k = 0; if (eoft_image <= num_terminals) k++; else num_terminals++; if (error_maps_bit) { if (error_image <= num_terminals) k++; else { num_terminals++; if (k == 1) error_image--; } } if (k > 0) { for (i = 0; i < HT_SIZE; i++) { p = hash_table[i]; while(p != NULL) { if (p -> number > num_terminals) p -> number -= k; else if (p -> number < -num_terminals) p -> number += k; p = p -> link; } } num_symbols -= k; accept_image -= k; } if (eolt_image == OMEGA) eolt_image = eoft_image; if (error_image == DEFAULT_SYMBOL) alias_map(kerror, DEFAULT_SYMBOL); return; } /* {terminal_symbol} ::= */ #line 1260 "jikespg.g" static void act132(void) { assign_symbol_no(kempty, OMEGA); empty = symbol_image(kempty); return; } jikespg-1.3/src/lpgdcl.h000066400000000000000000000077671167345774400152610ustar00rootroot00000000000000/* $Id: lpgdcl.h,v 1.2 1999/11/04 14:02:22 shields Exp $ */ /* This software is subject to the terms of the IBM Jikes Compiler License Agreement available at the following URL: http://www.ibm.com/research/jikes. Copyright (C) 1983, 1999, International Business Machines Corporation and others. All Rights Reserved. You must accept the terms of that agreement to use this software. */ #ifndef lpgdcl_INCLUDED #define lpgdcl_INCLUDED const unsigned char rhs[] = {0, 7,1,1,1,1,1,1,1,1,1,1,2,2,3,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 2,1,1,1,1,1,1,2,3,1,2,3,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,2,1,1,1,1,1,1,1,1,1,1,1,2,1, 1,3,2,3,2,2,2,2,1,1,1,1,3,3,3, 3,1,1,1,1,1,1,1,2,3,3,3,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,0,1,0, 1,0,1,0,1,0,1,0,1,0,1,0,2,0,2, 0,2,0,2,0,2 }; const unsigned short lhs[] = {0, 9,9,17,17,17,17,17,17,17,17,18,18,19,19,5, 5,5,5,5,5,5,5,6,6,6,6,6,6,6,6, 20,22,22,22,22,22,22,23,25,25,25,25,26,26,26, 26,27,27,27,27,27,27,27,3,3,3,3,28,28,28, 28,29,31,31,31,31,31,31,31,31,31,31,32,32,1, 1,33,33,33,33,33,33,33,33,33,33,33,33,33,33, 33,7,7,2,2,2,2,2,35,37,37,37,4,4,4, 4,4,4,4,8,8,8,8,8,8,8,8,10,10,11, 11,12,12,13,13,14,14,15,15,16,16,21,21,30,30, 24,24,36,36,34,34, 54,60,129,58,175,1,109,69,53,249, 42,146,188,247,171,109,145,20,101,2, 119,172,81,251,87,137,210,251,40,251, 35,27,29,251,39,191,13,35,27,29, 18,109,139,14,100,199,193,170,102,161, 20,186,34,203,179,218,221,189,195,187, 50,99,67,49,80,204,121,202,196,149, 123,41,97,133,125,207,111,112,231,48, 251,1,251,235,193,127,141,251,142,94, 91,251,135,124,89,129,138,90,141,79, 154,88,203,94,77,94,156,94,182,251, 251,251,251,147 }; const unsigned short *base_action = lhs; const unsigned char term_check[] = {0, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14, 15,16,0,1,2,3,4,5,6,7,8,9,10,11,12, 13,14,15,16,0,1,2,3,4,5,6,7,8,9,10, 11,12,0,0,0,3,4,18,0,1,2,3,4,5,6, 7,8,9,10,17,16,13,14,0,1,2,3,4,5,6, 7,8,9,10,0,0,13,14,3,4,5,6,7,8,9, 10,11,12,0,1,2,0,17,0,1,2,3,4,5,6, 7,8,9,10,11,0,0,0,3,4,5,6,7,8,9, 10,11,12,0,1,2,0,17,0,1,2,3,4,5,6, 7,8,0,1,2,0,1,2,15,0,1,2,3,4,5, 6,7,8,0,1,2,0,0,0,15,0,1,2,3,4, 5,6,7,8,0,0,1,2,3,0,15,6,7,8,10, 0,0,0,13,14,0,1,2,3,4,5,6,0,19,9, 0,1,2,0,4,5,9,0,0,9,10,0,0,0,11, 0,0,0,0,12,0,0,0,0,0,0,18,0 }; const unsigned short term_action[] = {0, 99,326,327,354,367,361,359,355,356,362, 363,364,365,357,358,368,366,251,326,327, 354,367,361,359,355,356,362,363,364,365, 357,358,368,366,251,326,327,279,274,345, 275,276,277,346,347,348,349,251,132,128, 245,343,281,38,326,327,294,308,305,312, 310,295,306,307,344,219,296,297,251,326, 327,298,308,305,303,302,299,306,307,136, 73,300,301,140,140,345,335,336,337,346, 347,348,349,251,326,327,134,140,62,326, 327,314,319,320,315,316,317,321,322,323, 74,138,251,240,343,345,242,238,333,346, 347,348,349,81,326,327,251,344,118,254, 255,260,261,158,256,257,258,80,326,327, 83,326,327,259,11,326,327,267,272,273, 268,269,270,78,326,327,251,251,251,266, 12,326,327,267,272,273,268,269,270,122, 251,326,327,354,251,266,359,355,356,206, 251,251,251,357,358,31,326,327,283,288, 286,284,120,250,287,251,326,327,124,308, 305,205,126,130,306,307,251,251,251,214, 251,251,251,251,164,251,251,251,251,251, 251,382 }; #endif /* lpgdcl_INCLUDED */ jikespg-1.3/src/lpgdef.h000066400000000000000000000020041167345774400152300ustar00rootroot00000000000000/* $Id: lpgdef.h,v 1.2 1999/11/04 14:02:22 shields Exp $ */ /* This software is subject to the terms of the IBM Jikes Compiler License Agreement available at the following URL: http://www.ibm.com/research/jikes. Copyright (C) 1983, 1999, International Business Machines Corporation and others. All Rights Reserved. You must accept the terms of that agreement to use this software. */ #ifndef lpgdef_INCLUDED #define lpgdef_INCLUDED enum { NT_OFFSET = 19, BUFF_UBOUND = 30, BUFF_SIZE = 31, STACK_UBOUND = 20, STACK_SIZE = 21, SCOPE_UBOUND = -1, SCOPE_SIZE = 0, LA_STATE_OFFSET = 392, MAX_LA = 1, NUM_RULES = 141, NUM_TERMINALS = 19, NUM_NON_TERMINALS = 38, NUM_SYMBOLS = 57, START_STATE = 144, EOFT_SYMBOL = 19, EOLT_SYMBOL = 20, ACCEPT_ACTION = 250, ERROR_ACTION = 251 }; #endif /* lpgdef_INCLUDED */ jikespg-1.3/src/lpgparse.c000066400000000000000000003611711167345774400156140ustar00rootroot00000000000000/* $Id: lpgparse.c,v 1.4 2001/10/10 14:53:10 ericb Exp $ */ /* This software is subject to the terms of the IBM Jikes Compiler License Agreement available at the following URL: http://ibm.com/developerworks/opensource/jikes. Copyright (C) 1983, 1999, 2001 International Business Machines Corporation and others. All Rights Reserved. You must accept the terms of that agreement to use this software. */ static char hostfile[] = __FILE__; #include #include #include #include "common.h" #undef scope_state #undef SCOPE_UBOUND #undef SCOPE_SIZE #include "header.h" #include "lpgsym.h" #include "lpgdef.h" #include "lpgdcl.h" #include "lpgparse.h" #define SPACE_CODE 1 #define DIGIT_CODE 2 #define ALPHA_CODE 3 #define IsSpace(c) (code[c] == SPACE_CODE) #define IsDigit(c) (code[c] == DIGIT_CODE) #define IsAlpha(c) (code[c] == ALPHA_CODE) static char code[256] = {0}; static int output_size = 80, line_no = 0; /****************************************************************************/ /* PROCESS_INPUT: */ /****************************************************************************/ /* This procedures opens all relevant files and processes the input grammar.*/ /****************************************************************************/ void process_input(void) { time_t ltime; unsigned c; /****************************************************************************/ /* Open input grammar file. If the file cannot be opened and that file name */ /* did not have an extension, then the extension ".g" is added to the file */ /* name and we try again. If no file can be found an error message is */ /* issued and the program halts. */ /****************************************************************************/ if ((sysgrm = fopen(grm_file, "r")) == (FILE *) NULL) { register int i; for (i = strlen(grm_file); i > 0 && grm_file[i] != '.' && grm_file[i] != '/' && /* Unix */ grm_file[i] != '\\'; /* Dos */ i--); if (grm_file[i] != '.') { strcat(grm_file, ".g"); if ((sysgrm = fopen(grm_file, "r")) == (FILE *) NULL) { fprintf(stderr, "***ERROR: Input file %s containing grammar " "is empty, undefined, or invalid\n",grm_file); exit(12); } } else { fprintf(stderr, "***ERROR: Input file %s containing grammar " "is empty, undefined, or invalid\n",grm_file); exit(12); } } #if !defined(C370) && !defined(CW) else { if (strrchr(grm_file, '.') == NULL) { sprintf(msg_line, "A file named \"%s\" with no extension " "is being opened", grm_file); PRNTWNG(msg_line); } } #endif /****************************************************************************/ /* Assign timeptr to the local time. */ /****************************************************************************/ time(<ime); timeptr = ctime(<ime); /****************************************************************************/ /* Open listing file for output. */ /****************************************************************************/ #if defined(C370) && !defined(CW) syslis = fopen(lis_file, "w, lrecl=85, recfm=VBA"); #else syslis = fopen(lis_file, "w"); #endif if (syslis == (FILE *) NULL) { fprintf(stderr, "***ERROR: Listing file \"%s\" cannot be openned.\n", lis_file); exit(12); } /****************************************************************************/ /* Complete the initialization of the code array used to replace the */ /* builtin functions isalpha, isdigit and isspace. */ /****************************************************************************/ for (c = 'a'; c <= 'z'; c++) { if (isalpha(c)) code[c] = ALPHA_CODE; } for (c = 'A'; c <= 'Z'; c++) { if (isalpha(c)) code[c] = ALPHA_CODE; } for (c = '0'; c <= '9'; c++) { if (isdigit(c)) code[c] = DIGIT_CODE; } code[' '] = SPACE_CODE; code['\n'] = SPACE_CODE; code['\t'] = SPACE_CODE; code['\r'] = SPACE_CODE; code['\v'] = SPACE_CODE; code['\f'] = SPACE_CODE; /****************************************************************************/ /* Print heading on terminal and in listing file */ /****************************************************************************/ printf("\n %s %35.24s\n", HEADER_INFO, timeptr); PR_HEADING; init_process(); process_grammar(); exit_process(); return; } /********************************************************************/ /* READ_INPUT: */ /********************************************************************/ /* READ_INPUT fills the buffer from p1 to the end. */ /********************************************************************/ static void read_input(void) { long num_read; num_read = input_buffer + IOBUFFER_SIZE - bufend; if ((num_read = fread(bufend, 1, num_read, sysgrm)) == 0) { if (ferror(sysgrm) != 0) { fprintf(stderr, "*** Error reading input file \"%s\".\n", grm_file); exit(12); } } bufend += num_read; *bufend = '\0'; return; } /*****************************************************************************/ /* INIT_PROCESS: */ /*****************************************************************************/ /* This routine is invoked to allocate space for the global structures */ /* needed to process the input grammar. */ /*****************************************************************************/ static void init_process(void) { /******************************************************************/ /* Set up a a pool of temporary space. */ /******************************************************************/ reset_temporary_space(); terminal = (struct terminal_type *) calloc(STACK_SIZE, sizeof(struct terminal_type)); if (terminal == (struct terminal_type *) NULL) nospace(__FILE__, __LINE__); hash_table = (struct hash_type **) calloc(HT_SIZE, sizeof(struct hash_type *)); if (hash_table == (struct hash_type **) NULL) nospace(__FILE__, __LINE__); /***********************************************************************/ /* Allocate space for input buffer and read in initial data in input */ /* file. Next, invoke PROCESS_OPTION_LINES to process all lines in */ /* input file that are options line. */ /***********************************************************************/ input_buffer = (char *) calloc(IOBUFFER_SIZE + 1 + MAX_LINE_SIZE, sizeof(char)); if (input_buffer == (char *) NULL) nospace(__FILE__, __LINE__); bufend = &input_buffer[0]; read_input(); p2 = &input_buffer[0]; linestart = p2 - 1; p1 = p2; line_no++; if (*p2 == '\0') { fprintf(stderr, "Input file \"%s\" containing grammar is " "empty, undefined, or invalid\n", grm_file); exit(12); } process_options_lines(); eolt_image = OMEGA; blockb_len = strlen(blockb); blocke_len = strlen(blocke); hblockb_len = strlen(hblockb); hblocke_len = strlen(hblocke); /*****************************************************/ /* Keywords, Reserved symbols, and predefined macros */ /*****************************************************/ kdefine[0] = escape; /*Set empty first space to the default */ kterminals[0] = escape; /* escape symbol. */ kalias[0] = escape; kstart[0] = escape; krules[0] = escape; knames[0] = escape; kend[0] = escape; krule_number[0] = escape; krule_text[0] = escape; krule_size[0] = escape; knum_rules[0] = escape; knum_terminals[0] = escape; knum_non_terminals[0] = escape; knum_symbols[0] = escape; kinput_file[0] = escape; kcurrent_line[0] = escape; knext_line[0] = escape; kstart_nt[0] = escape; keolt[0] = escape; return; } /*****************************************************************************/ /* EXIT_PROCESS: */ /*****************************************************************************/ /* This routine is invoked to free all space used to process the input that */ /* is no longer needed. Note that for the string_table, only the unused */ /* space is released. */ /*****************************************************************************/ static void exit_process(void) { if (string_offset > 0) { string_table = (char *) (string_table == (char *) NULL ? malloc((string_offset) * sizeof(char)) : realloc(string_table, (string_offset) * sizeof(char))); if (string_table == (char *) NULL) nospace(__FILE__, __LINE__); } ffree(terminal); ffree(hash_table); ffree(input_buffer); ffree(rulehdr); /* allocated in action LPGACT when grammar is not empty */ return; } /*****************************************************************************/ /* VERIFY: */ /*****************************************************************************/ /* VERIFY takes as argument a character string and checks whether or not each*/ /* character is a digit. If all are digits, then 1 is returned; if not, then */ /* 0 is returned. */ /*****************************************************************************/ static BOOLEAN verify(char *item) { while (IsDigit(*item)) item++; return (*item == '\0'); } /*****************************************************************************/ /* TRANSLATE: */ /*****************************************************************************/ /* TRANSLATE takes as arguments a character array, which it folds to upper */ /* to uppercase and returns. */ /*****************************************************************************/ static char *translate(char *str, int len) { register int i; for (i = 0; i < len; i++) str[i] = TOUPPER(str[i]); return(str); } /* end translate */ /**********************************************************************/ /* STRXEQ: */ /**********************************************************************/ /* Compare two character strings s1 and s2 to check whether or not s2 */ /* is a substring of s1. The string s2 is assumed to be in lowercase */ /* and NULL terminated. However, s1 does not have to (indeed, may not)*/ /* be NULL terminated. */ /* */ /* The test below may look awkward. For example, why not use: */ /* if (tolower(s1[i]) != s2[i]) ? */ /* because tolower(ch) is sometimes implemented as (ch-'A'+'a') which */ /* does not work when "ch" is already a lower case character. */ /* */ /**********************************************************************/ static BOOLEAN strxeq(char *s1, char *s2) { for (; *s2 != '\0'; s1++, s2++) { if (*s1 != *s2 && *s1 != toupper(*s2)) return FALSE; } return TRUE; } /*****************************************************************************/ /* OPTIONS: */ /*****************************************************************************/ /* OPTION handles the decoding of options passed by the user and resets */ /* them appropriately. "options" may be called twice: when a parameter line */ /* is passed to the main program and when the user codes an %OPTIONS line in */ /* his grammar. */ /* Basically, there are two kinds of options: switches which indicate a */ /* certain setting just by their appearance, and valued options which are */ /* followed by an equal sign and the value to be assigned to them. */ /*****************************************************************************/ static void options(void) { char *c, token[MAX_PARM_SIZE+1], temp [MAX_PARM_SIZE+1], delim; register int i, j, len; BOOLEAN flag; /*******************************************************************/ /* If we scan the comment sign, we stop processing the rest of the */ /* parameter string. */ /*******************************************************************/ for (c = parm; *c != '\0'; c++) { if (*c == '-' && *(c+1) == '-') break; } *c = '\0'; i = 0; while ((parm[i] != '\0') && /* Clean front of string */ ((parm[i] == ',') || (parm[i] == '/') || (parm[i] == ' '))) i++; while (parm[i] != '\0') /* Repeat until parm line is exhausted */ { strcpy(parm, parm + i); /* Remove garbage in front */ i = 0; while ((parm[i] != '\0')&& /* Search for delimiter */ ((parm[i] != ',') && (parm[i] != '/') && (parm[i] != '=') && (parm[i] != ' '))) i++; for (j = 0; j < i; j++) /* Fold actual parameter */ { token[j] = TOUPPER(parm[j]); temp[j] = parm[j]; } token[i] = '\0'; temp[i] = '\0'; /***********************************/ /* find first non-blank after parm */ /***********************************/ while (parm[i] != '\0' && parm[i] == ' ') i++; if (parm[i] != '\0') /* not end of parameter line */ delim = parm[i]; else delim = ' '; len = strlen(token); if (len > MAX_PARM_SIZE) token[MAX_PARM_SIZE] = '\0'; /*****************************************************************************/ /* We check whether we have a switch or a value parameter. */ /* Each category is checked separately. A match is made whenever */ /* a minimum unambiguous prefix of the token in question matches an */ /* option... */ /* */ /* At this stage, TEMP contains the value of the switch as specified */ /* and TOKEN contains the upper-case folded value of TEMP. */ /*****************************************************************************/ if (delim != '=') /* if switch parameter then process */ { if ((len > 2) && (memcmp(token, "NO", 2) == 0)) /* option has "NO" */ { /* prefix? */ flag = FALSE; len = len-2; strcpy(token, token + 2); /* get rid of "NO" prefix */ } else flag = TRUE; if (memcmp(oaction, token, len) == 0) action_bit = flag; else if (memcmp(obyte, token, len) == 0) byte_bit = flag; else if (memcmp(oconflicts, token, len) == 0) conflicts_bit = flag; else if (len >=4 && memcmp(odefault, token, len) == 0) { if (flag) default_opt = 5; else default_opt = 0; } else if (len >= 3 && memcmp(odebug, token, len) == 0) debug_bit = flag; else if (len >= 4 && memcmp(odeferred, token, len) == 0) deferred_bit = flag; else if (len >= 2 && memcmp(oedit, token, len) == 0) edit_bit = flag; else if ((len >= 2) && ((memcmp(oerrormaps,token, len) == 0) || (strcmp("EM", token) == 0) || (memcmp(oerrormaps2, token, len) == 0) || (memcmp(oerrormaps3, token, len) == 0))) error_maps_bit = flag; else if ((len >= 2) && (memcmp(ofirst, token, len) == 0)) first_bit = flag; else if ((len >= 2) && (memcmp(ofollow, token, len) == 0)) follow_bit = flag; else if (len >= 2 && ((strcmp(token, "GP") == 0) || (memcmp(ogenprsr, token, len) == 0) || (memcmp(ogenprsr2, token, len) == 0) || (memcmp(ogenprsr3, token, len) == 0))) { c_bit = flag; cpp_bit = FALSE; java_bit = FALSE; } else if (len >= 2 && ((strcmp(token, "GD") == 0) || (memcmp(ogotodefault, token, len) == 0) || (memcmp(ogotodefault2, token, len) == 0) || (memcmp(ogotodefault3, token, len) == 0))) goto_default_bit = flag; else if ((strcmp(token, "HW") == 0) || (memcmp(ohalfword, token, len) == 0) || (memcmp(ohalfword2, token, len) == 0) || (memcmp(ohalfword3, token, len) == 0)) byte_bit = NOT(flag); else if ((strcmp(token, "JI") == 0) || (memcmp(ojikes, token, len) == 0)) jikes_bit = 1; else if (len >= 2 && memcmp(olalr, token, len) == 0) { slr_bit = NOT(flag); lalr_level = 1; } else if (len >= 2 && memcmp(olist, token, len) == 0) list_bit = flag; else if ((strcmp(token, "NC") == 0) || (memcmp(ontcheck, token, len) == 0) || (memcmp(ontcheck2, token, len) == 0) || (memcmp(ontcheck3, token, len) == 0)) nt_check_bit = flag; else if ((strcmp(token, "RR") == 0) || (memcmp(oreadreduce, token, len) == 0) || (memcmp(oreadreduce2, token, len) == 0) || (memcmp(oreadreduce3, token, len) == 0)) read_reduce_bit = flag; else if (len >=2 && memcmp(oscopes, token, len) == 0) scopes_bit = flag; else if ((len >= 2) && ((strcmp(token, "SD") == 0) || (memcmp(oshiftdefault, token, len) == 0) || (memcmp(oshiftdefault2, token, len) == 0) || (memcmp(oshiftdefault3, token, len) == 0))) shift_default_bit = flag; else if ((len >= 2) && ((strcmp(token, "SP") == 0) || (memcmp(osingleproductions, token, len) == 0) || (memcmp(osingleproductions2, token, len) == 0) || (memcmp(osingleproductions3, token, len) == 0))) single_productions_bit = flag; else if (len >= 2 && memcmp(oslr, token, len) == 0) { slr_bit = flag; lalr_level = 1; } else if (len >= 2 && memcmp(ostates, token, len) == 0) states_bit = flag; else if (len >= 2 && memcmp(otable, token, len) == 0) { if (flag) table_opt = OPTIMIZE_SPACE; else table_opt = 0; } else if (len >= 2 && memcmp(otrace, token, len) == 0) { if (flag) trace_opt = TRACE_CONFLICTS; else trace_opt = NOTRACE; } else if (memcmp(overbose, token, len) == 0) verbose_bit = flag; else if (memcmp(owarnings, token, len) == 0) warnings_bit = flag; else if (memcmp(oxref, token, len) == 0) xref_bit = flag; else if ((strcmp(token, "D") == 0) || (strcmp(token, "DE") == 0)) { sprintf(msg_line, "\"%s\" is an ambiguous option: " "DEBUG, DEFAULT, DEFERRED ?", temp); PRNTERR(msg_line); } else if (strcmp(token, "DEF") == 0) { PRNTERR("\"DEF\" is an ambiguous option: " "DEFAULT, DEFERRED ?"); } else if (strcmp(token, "E") == 0) { PRNTERR("\"E\" is an ambiguous option: " "EDIT, ERROR-MAPS ?"); } else if (strcmp(token, "F") == 0) { PRNTERR("\"F\" is an ambiguous option: FOLLOW, FIRST ?"); } else if (strcmp(token, "G") == 0) { PRNTERR("\"G\" is an ambiguous option: " "GENERATE-PARSER, GOTO-DEFAULT ?"); } else if (strcmp(token, "L") == 0) { PRNTERR("\"L\" is an ambiguous option: LALR, LIST ?"); } else if (strcmp(token, "S") == 0) { PRNTERR("\"S\" is an ambiguous option:\n " "SCOPES, SEARCH, STATES, SLR, " "SHIFT-DEFAULT, SINGLE-PRODUCTIONS ?"); } else if (strcmp(token, "T") == 0) { PRNTERR("\"T\" is an ambiguous option: TABLE, TRACE ?"); } else { sprintf(msg_line, "\"%s\" is an invalid option", temp); PRNTERR(msg_line); } } /****************************************/ /* We now process the valued-parameter. */ /****************************************/ else /* value parameter. pick value after "=" and process */ { i++; if (IsSpace(parm[i]) || parm[i] == '\0')/* no value specified */ { sprintf(msg_line, "Null string or blank is invalid for parameter %s", token); PRNTERR(msg_line); continue; } j = i; while ((parm[i] != '\0')&& /* find next delimeter */ ((parm[i] != ',') && (parm[i] != '/') && (parm[i] != ' '))) i++; memcpy(temp, parm+j, i - j); /* copy into TEMP */ temp[i - j] = '\0'; #if (defined(C370) || defined(CW)) && (!defined(MVS)) if ((strcmp(token, "AN") == 0) || ((len >= 9) && ((memcmp(token, oactfile_name, len) == 0) || (memcmp(token, oactfile_name2, len) == 0) || (memcmp(token, oactfile_name3, len) == 0)))) { memcpy(an, temp, 8); pn[MIN(strlen(temp), 8)] = '\0'; strupr(an); } else if ((strcmp(token, "AT") == 0) || ((len >= 9) && ((memcmp(token, oactfile_type, len) == 0) || (memcmp(token, oactfile_type2, len) == 0) || (memcmp(token, oactfile_type3, len) == 0)))) { memcpy(at, temp, 8); at[MIN(strlen(temp), 8)] = '\0'; strupr(at); } else if ((strcmp(token, "AM") == 0) || ((len >= 9) && ((memcmp(token, oactfile_mode, len) == 0) || (memcmp(token, oactfile_mode2, len) == 0) || (memcmp(token, oactfile_mode3, len) == 0)))) { memcpy(am, temp, 2); am[MIN(strlen(temp), 2)] = '\0'; strupr(am); } #else if ((strcmp(token, "AN") == 0) || (memcmp(token, oactfile_name, len) == 0) || (memcmp(token, oactfile_name2, len) == 0) || (memcmp(token, oactfile_name3, len) == 0)) strcpy(act_file, temp); #endif else if (strcmp(token, oblockb) == 0) strcpy(blockb, temp); else if (strcmp(token, oblocke) == 0) strcpy(blocke, temp); else if (memcmp(odefault, token, len) == 0) { if (verify(temp)) default_opt = MIN(atoi(temp), 5); else { sprintf(msg_line, "\"%s\" is an invalid value for %s", temp, token); PRNTERR(msg_line); } } else if (len >= 2 && memcmp(token, oescape, len) == 0) escape = temp[0]; else if (((strcmp(token, "FP") == 0) || (memcmp(token, ofile_prefix, len) == 0) || (memcmp(token, ofile_prefix2, len) == 0) || (memcmp(token, ofile_prefix3, len) == 0))) { memcpy(file_prefix, temp, 5); file_prefix[MIN(5, strlen(temp))] = '\0'; } else if ((strcmp(token, "GP") == 0) || (memcmp(ogenprsr, token, len) == 0) || (memcmp(ogenprsr2, token, len) == 0) || (memcmp(ogenprsr3, token, len) == 0)) { BOOLEAN invalid_language = TRUE; if (temp[0] == 'c' || temp[0] == 'C') { if (temp[1] == '\0') { c_bit = TRUE; cpp_bit = FALSE; java_bit = FALSE; invalid_language = FALSE; } else if (((temp[1] == '+' && temp[2] == '+') || ((temp[1] == 'p' || temp[1] == 'P') && (temp[2] == 'p' || temp[2] == 'P'))) && temp[3] == '\0') { c_bit = FALSE; cpp_bit = TRUE; java_bit = FALSE; invalid_language = FALSE; } } else if ((len == 1 && (*temp == 'j' || *temp == 'J')) || (len == 2 && strxeq(temp, "ja")) || (len == 3 && strxeq(temp, "jav")) || (len == 4 && strxeq(temp, "java"))) { c_bit = FALSE; cpp_bit = FALSE; java_bit = TRUE; invalid_language = FALSE; } if (invalid_language) { sprintf(msg_line, "\"%s\" is an invalid value for %s", temp, token); PRNTERR(msg_line); } } #if (defined(C370) || defined(CW)) && (!defined(MVS)) else if ((strcmp(token, "HN") == 0) || ((len >= 9) && ((memcmp(token, ohactfile_name, len) == 0) || (memcmp(token, ohactfile_name2, len) == 0) || (memcmp(token, ohactfile_name3, len) == 0)))) { memcpy(han, temp, 8); pn[MIN(strlen(temp), 8)] = '\0'; strupr(han); } else if ((strcmp(token, "HT") == 0) || ((len >= 9) && ((memcmp(token, ohactfile_type, len) == 0) || (memcmp(token, ohactfile_type2, len) == 0) || (memcmp(token, ohactfile_type3, len) == 0)))) { memcpy(hat, temp, 8); hat[MIN(strlen(temp), 8)] = '\0'; strupr(hat); } else if ((strcmp(token, "HM") == 0) || ((len >= 9) && ((memcmp(token, ohactfile_mode, len) == 0) || (memcmp(token, ohactfile_mode2, len) == 0) || (memcmp(token, ohactfile_mode3, len) == 0)))) { memcpy(ham, temp, 2); ham[MIN(strlen(temp), 2)] = '\0'; strupr(ham); } #else else if ((strcmp(token, "HN") == 0) || ((len >= 2) && ((memcmp(token, ohactfile_name, len) == 0) || (memcmp(token, ohactfile_name2, len) == 0) || (memcmp(token, ohactfile_name3, len) == 0)))) strcpy(hact_file, temp); #endif else if (len >= 2 && strcmp(token, ohblockb) == 0) strcpy(hblockb, temp); else if (len >= 2 && strcmp(token, ohblocke) == 0) strcpy(hblocke, temp); else if (memcmp (olalr, token, len) == 0) { len = strlen(temp); if (len > MAX_PARM_SIZE) temp[MAX_PARM_SIZE - 1] = '\0'; if ((! verify(temp)) && (memcmp(translate(temp, len), omax, len) != 0)) { sprintf(msg_line, "\"%s\" is an invalid value for %s", temp, token); PRNTERR(msg_line); } else { slr_bit = FALSE; if (memcmp(omax, translate(temp, len), len) == 0) lalr_level = MAXIMUM_LA_LEVEL; else { lalr_level = atoi(temp); if (lalr_level > MAXIMUM_LA_LEVEL) { sprintf(msg_line, "\"%s\" exceeds maximum value " "of %d allowed for %s", temp, MAXIMUM_LA_LEVEL, token); PRNTWNG(msg_line); lalr_level = MAXIMUM_LA_LEVEL; } } } } else if ((len >= 2) && ((memcmp(token, omaximum_distance,len) == 0) || (memcmp(token, omaximum_distance2, len) == 0) || (memcmp(token, omaximum_distance3, len) == 0))) { if (verify(temp)) maximum_distance = atoi(temp); else { sprintf(msg_line, "\"%s\" is an invalid value for %s", temp, token); PRNTERR(msg_line); } } else if ((len >= 2) && ((memcmp(token, ominimum_distance,len) == 0) || (memcmp(token, ominimum_distance2, len) == 0) || (memcmp(token, ominimum_distance3, len) == 0))) { if (verify(temp)) minimum_distance = atoi(temp); else { sprintf(msg_line, "\"%s\" is an invalid value for %s", temp, token); PRNTERR(msg_line); } } else if ((memcmp(onames, token, len) == 0)) { len = strlen(temp); if (len >= 2 && memcmp(omax, translate(temp, len), len) == 0) names_opt = MAXIMUM_NAMES; else if (len >= 2 && memcmp(omin, translate(temp, len), len) == 0) names_opt = MINIMUM_NAMES; else if (memcmp(translate(temp, len), ooptimized, len) == 0) names_opt = OPTIMIZE_PHRASES; else if ((temp[0] == 'm' || temp[0] == 'M') && temp[1] != '\0') { sprintf(msg_line, "\"M\" is an ambiguous value for %s: " "MAXIMUM, MINIMUM?", token); PRNTERR(msg_line); } else { sprintf(msg_line, "\"%s\" is an invalid value for %s", temp, token); PRNTERR(msg_line); } } else if (len >= 2 && memcmp(token, oormark, len) == 0) ormark = temp[0]; else if ((len >= 2) && ((strcmp(token, "OS") == 0) || (memcmp(token, ooutputsize, len) == 0) || (memcmp(token, ooutputsize2, len) == 0) || (memcmp(token, ooutputsize3, len) == 0))) { if (verify(temp)) { int tmpval; tmpval = atoi(temp); if (tmpval > MAX_LINE_SIZE) { sprintf(msg_line, "OUTPUT_SIZE cannot exceed %d", MAX_LINE_SIZE); PRNTERR(msg_line); } else output_size = tmpval; } else { sprintf(msg_line, "\"%s\" is an invalid value for %s", temp, token); PRNTERR(msg_line); } } else if (memcmp(token, oprefix, len) == 0) strcpy(prefix,temp); #if defined(C370) || defined(CW) else if ((strcmp(token, "RF") == 0) || (strcmp(token, "RECFM") == 0) || (memcmp(token, orecordformat, len) == 0) || (memcmp(token, orecordformat2, len) == 0) || (memcmp(token, orecordformat3, len) == 0)) { len = strlen(temp); if (len > MAX_PARM_SIZE) temp[MAX_PARM_SIZE-1] = '\0'; if (memcmp(ofixed, translate(temp, len), len) == 0) record_format = 'F'; else if (memcmp(translate(temp, len), ovariable,len) == 0) record_format = 'V'; else { sprintf(msg_line, "\"%s\" is an invalid value for %s", temp, token); PRNTERR(msg_line); } } #endif else if (strcmp(token, "SS") == 0 || ((memcmp(token, ostack_size,len) == 0) || (memcmp(token, ostack_size2, len) == 0) || (memcmp(token, ostack_size3, len) == 0))) { if (verify(temp)) stack_size = atoi(temp); else { sprintf(msg_line, "\"%s\" is an invalid value for %s", temp, token); PRNTERR(msg_line); } } else if (len >= 2 && memcmp(token, osuffix, len) == 0) strcpy(suffix,temp); else if (len >= 2 && memcmp(token,otable, len) == 0) { len = strlen(temp); if (len > MAX_PARM_SIZE) temp[MAX_PARM_SIZE - 1] = '\0'; if (memcmp(ospace, translate(temp, len), len) == 0) table_opt = OPTIMIZE_SPACE; else if (memcmp(translate(temp, len), otime, len) == 0) table_opt = OPTIMIZE_TIME; else { sprintf(msg_line, "\"%s\" is an invalid value for %s", temp, token); PRNTERR(msg_line); } } else if (len >= 2 && memcmp(token, otrace, len) == 0) { len = strlen(temp); if (len > MAX_PARM_SIZE) temp[MAX_PARM_SIZE-1] = '\0'; if (memcmp(oconflicts, translate(temp, len), len) == 0) trace_opt = TRACE_CONFLICTS; else if (memcmp(translate(temp, len), ofull, len) == 0) trace_opt = TRACE_FULL; else { sprintf(msg_line, "\"%s\" is an invalid value for %s", temp, token); PRNTERR(msg_line); } } #if (defined(C370) || defined(CW)) && (!defined(MVS)) else if (memcmp(token, oactfile_name2, len) == 0 || memcmp(token, oactfile_name3, len) == 0) { sprintf(msg_line, "Option \"%s\" is ambiguous: " "ACTFILE-NAME, ACTFILE-TYPE, ACTFILE-MODE?", token); PRNTERR(msg_line); } #endif else if (strcmp(token, "BLOCK") == 0) { PRNTERR("Option \"BLOCK\" is ambiguous: BLOCKB, BLOCKE ?"); } else if (strcmp("E",token) == 0) { PRNTERR("Option \"E\" is ambiguous: " "ERROR-PROC, ERROR-MAPS ?"); } else if (strcmp(token, "H") == 0) { PRNTERR("Option \"H\" is ambiguous: HBLOCKB, HBLOCKE ?"); } #if (defined(C370) || defined(CW)) && (!defined(MVS)) else if (memcmp(token, ohactfile_name2, len) == 0 || memcmp(token, ohactfile_name3, len) == 0) { sprintf(msg_line, "Option \"%s\" is ambiguous: " "HACTFILE-NAME, HACTFILE-TYPE, HACTFILE-MODE?", token); PRNTERR(msg_line); } #endif else if (strcmp(token, "HBLOCK") == 0) { PRNTERR("Option \"HBLOCK\" is ambiguous: HBLOCKB, HBLOCKE ?"); } else if (strcmp("M",token) == 0 || strcmp("MD",token) == 0) { sprintf(msg_line, "Option \"%s\" is ambiguous: " "MAX-DISTANCE, MIN-DISTANCE?", token); PRNTERR(msg_line); } else if (strcmp("O",token) == 0) { PRNTERR("Option \"O\" is ambiguous: OUTPUT-SIZE, ORMARK ?"); } else if (strcmp("T", token) == 0) { PRNTERR("Option \"T\" is ambiguous: TABLE, TRACE?"); } else { sprintf(msg_line, "\"%s\" is an invalid option", token); PRNTERR(msg_line); } } while ((parm[i] != '\0')&& /* clean after paramter */ ((parm[i] == ',') || (parm[i] == '/') || (parm[i] == ' '))) i++; } return; } /****************************************************************************/ /* PROCESS_OPTIONS_LINES: */ /****************************************************************************/ /* In this function, we read the first line(s) of the input text to see */ /* if they are (it is an) "options" line(s). If so, the options are */ /* processed. Then, we process user-supplied options if there are any. In */ /* any case, the options in effect are printed. */ /****************************************************************************/ static void process_options_lines(void) { char old_parm[MAX_LINE_SIZE + 1], output_line[PRINT_LINE_SIZE + 1], opt_string[60][OUTPUT_PARM_SIZE + 1], *line_end, temp[SYMBOL_SIZE + 1]; static char ooptions[9] = " OPTIONS"; int top = 0, i; strcpy(old_parm, parm); /* Save new options passed to program */ ooptions[0] = escape; /* "ooptions" always uses default escape symbol */ while (p1 != '\0') /* Until end-of-file is reached, process */ { /* all comment and %options lines. */ while(IsSpace(*p2)) /* skip all space symbols */ { if (*p2 == '\n') { line_no++; linestart = p2; p1 = p2 + 1; } p2++; } line_end = strchr(p2, '\n'); /* find end-of-line */ /*********************************************************************/ /* First, check if line is a comment line. If so, skip it. Next, */ /* check if line is an options line. If so, process it. Otherwise, */ /* break out of the loop. */ /* Note that no length check is necessary before checking for "--" */ /* or "%options" since the buffer is always extended by */ /* MAX_LINE_SIZE elements past its required length. (see read_input) */ /*********************************************************************/ if (*p2 == '-' && *(p2 + 1) == '-') /* skip comment line */ ; else if (memcmp(ooptions, translate(p2, 8), 8) == 0) { *line_end = '\0'; PRNT(p2); /* Print options line */ strcpy(parm, p2 + strlen(ooptions)); options(); /* Process hard-coded options */ } else { p2 = p1; /* make p2 point to first character */ break; } /*********************************************************************/ /* If the line was a comment or an option line, check the following */ /* line. If we are at the end of the buffer, read in more data... */ /*********************************************************************/ p1 = line_end + 1; if (bufend == input_buffer + IOBUFFER_SIZE) { i = bufend - p1; if (i < MAX_LINE_SIZE) { strcpy(input_buffer, p1); bufend = &input_buffer[i]; read_input(); p1 = &input_buffer[0]; } } line_no++; linestart = p1 - 1; p2 = p1; } fprintf(syslis, "\n"); strcpy(parm, old_parm); options(); /* Process new options passed directly to program */ if (! error_maps_bit) /* Deferred parsing without error maps is useless*/ deferred_bit = FALSE; #if (defined(C370) || defined(CW)) && (!defined(MVS)) strupr(file_prefix); if (pn[0] == '\0') { strcpy(pn,file_prefix); strcat(pn, "PRS"); } if (sn[0] == '\0') { strcpy(sn,file_prefix); strcat(sn, "SYM"); } if (an[0] == '\0') { strcpy(an,file_prefix); strcat(an, "ACT"); } if (han[0] == '\0') { strcpy(han,file_prefix); strcat(han, "HDR"); } sprintf(act_file, "%s.%s.%s", an, at, am); sprintf(hact_file, "%s.%s.%s", han, hat, ham); sprintf(sym_file, "%s.%s.%s", sn, st, sm); sprintf(def_file, "%sDEF.%s.%s", file_prefix, (java_bit ? "JAVA" : "H"), sm); sprintf(prs_file, "%s.%s.%s", pn, pt, pm); sprintf(dcl_file, "%sDCL.%s.%s", file_prefix, (java_bit ? "JAVA" : "H"), sm); #else #if defined(MVS) if (act_file[0] == '\0') sprintf(act_file, "%sACT.%s", file_prefix, (java_bit ? "JAVA" : "H")); if (hact_file[0] == '\0') sprintf(hact_file, "%sHDR.%s", file_prefix, (java_bit ? "JAVA" : "H")); sprintf(sym_file, "%sSYM.%s", file_prefix, (java_bit ? "JAVA" : "H")); sprintf(def_file, "%sDEF.%s", file_prefix, (java_bit ? "JAVA" : "H")); sprintf(prs_file, "%sPRS.%s", file_prefix, (java_bit ? "JAVA" : "H")); sprintf(dcl_file, "%sDCL.%s", file_prefix, (java_bit ? "JAVA" : "H")); #else if (act_file[0] == '\0') sprintf(act_file, "%sact.%s", file_prefix, (java_bit ? "java" : "h")); if (hact_file[0] == '\0') sprintf(hact_file, "%shdr.%s", file_prefix, (java_bit ? "java" : "h")); sprintf(sym_file, "%ssym.%s", file_prefix, (java_bit ? "java" : "h")); sprintf(def_file, "%sdef.%s", file_prefix, (java_bit ? "java" : "h")); sprintf(prs_file, "%sprs.%s", file_prefix, (java_bit ? "java" : "h")); sprintf(dcl_file, "%sdcl.%s", file_prefix, (java_bit ? "java" : "h")); #endif #endif if (verbose_bit) /* turn everything on */ { first_bit = TRUE; follow_bit = TRUE; list_bit = TRUE; states_bit = TRUE; xref_bit = TRUE; warnings_bit = TRUE; } /*****************************************************************************/ /* PRINT OPTIONS: */ /*****************************************************************************/ /* Here we print all options set by the user. As of now, only about 48 */ /* different options and related aliases are allowed. In case that number */ /* goes up, the bound of the array, opt_string, should be changed. */ /* BLOCKB, BLOCKE, HBLOCKB and HBLOCKE can generate the longest strings */ /* since their value can be up to MAX_PARM_SIZE characters long. */ /*****************************************************************************/ if (action_bit) strcpy(opt_string[++top], "ACTION"); else strcpy(opt_string[++top], "NOACTION"); #if (defined(C370) || defined(CW)) && (!defined(MVS)) sprintf(opt_string[++top], "ACTFILE-NAME=%s",an); sprintf(opt_string[++top], "ACTFILE-TYPE=%s",at); sprintf(opt_string[++top], "ACTFILE-MODE=%s",am); #else sprintf(opt_string[++top], "ACTFILE-NAME=%s",act_file); #endif sprintf(opt_string[++top], "BLOCKB=%s",blockb); sprintf(opt_string[++top], "BLOCKE=%s", blocke); if (byte_bit) strcpy(opt_string[++top], "BYTE"); if (conflicts_bit) strcpy(opt_string[++top], "CONFLICTS"); else strcpy(opt_string[++top], "NOCONFLICTS"); if (default_opt == 0) strcpy(opt_string[++top], "NODEFAULT"); else sprintf(opt_string[++top], "DEFAULT=%d",default_opt); if (debug_bit) strcpy(opt_string[++top], "DEBUG"); else strcpy(opt_string[++top], "NODEBUG"); if (deferred_bit) strcpy(opt_string[++top], "DEFERRED"); else strcpy(opt_string[++top], "NODEFERRED"); if (edit_bit) strcpy(opt_string[++top], "EDIT"); else strcpy(opt_string[++top], "NOEDIT"); if (error_maps_bit) strcpy(opt_string[++top], "ERROR-MAPS"); else strcpy(opt_string[++top], "NOERROR-MAPS"); sprintf(opt_string[++top], "ESCAPE=%c", escape); sprintf(opt_string[++top], "FILE-PREFIX=%s", file_prefix); if (first_bit) strcpy(opt_string[++top], "FIRST"); else strcpy(opt_string[++top], "NOFIRST"); if (follow_bit) strcpy(opt_string[++top], "FOLLOW"); else strcpy(opt_string[++top], "NOFOLLOW"); if (c_bit) sprintf(opt_string[++top], "GENERATE-PARSER=C"); else if (cpp_bit) sprintf(opt_string[++top], "GENERATE-PARSER=C++"); else if (java_bit) sprintf(opt_string[++top], "GENERATE-PARSER=JAVA"); else strcpy(opt_string[++top], "NOGENERATE-PARSER"); if (goto_default_bit) strcpy(opt_string[++top], "GOTO-DEFAULT"); else strcpy(opt_string[++top], "NOGOTO-DEFAULT"); #if defined(C370) || defined(CW) sprintf(opt_string[++top], "HACTFILE-NAME=%s", han); sprintf(opt_string[++top], "HACTFILE-TYPE=%s", hat); sprintf(opt_string[++top], "HACTFILE-MODE=%s", ham); #else sprintf(opt_string[++top], "HACTFILE-NAME=%s", hact_file); #endif if (! byte_bit) strcpy(opt_string[++top], "HALF-WORD"); sprintf(opt_string[++top], "HBLOCKB=%s", hblockb); sprintf(opt_string[++top], "HBLOCKE=%s", hblocke); if (! slr_bit) sprintf(opt_string[++top], "LALR=%d", lalr_level); if (list_bit) strcpy(opt_string[++top], "LIST"); else strcpy(opt_string[++top], "NOLIST"); sprintf(opt_string[++top], "MAX-DISTANCE=%d",maximum_distance); sprintf(opt_string[++top], "MIN-DISTANCE=%d",minimum_distance); if (names_opt == MAXIMUM_NAMES) strcpy(opt_string[++top], "NAMES=MAXIMUM"); else if (names_opt == MINIMUM_NAMES) strcpy(opt_string[++top], "NAMES=MINIMUM"); else strcpy(opt_string[++top], "NAMES=OPTIMIZED"); if (nt_check_bit) strcpy(opt_string[++top], "NT-CHECK"); else strcpy(opt_string[++top], "NONT-CHECK"); sprintf(opt_string[++top], "ORMARK=%c", ormark); sprintf(opt_string[++top], "OUTPUT-SIZE=%d", output_size); sprintf(opt_string[++top], "PREFIX=%s",prefix); if (read_reduce_bit) strcpy(opt_string[++top], "READ-REDUCE"); else strcpy(opt_string[++top], "NOREAD-REDUCE"); #if defined(C370) || defined(CW) if (record_format == 'F') strcpy(opt_string[++top], "RECORD-FORMAT=F"); else strcpy(opt_string[++top], "RECORD-FORMAT=V"); #endif if (scopes_bit) strcpy(opt_string[++top], "SCOPES"); else strcpy(opt_string[++top], "NOSCOPES"); if (shift_default_bit) strcpy(opt_string[++top], "SHIFT-DEFAULT"); else strcpy(opt_string[++top], "NOSHIFT-DEFAULT"); if (single_productions_bit) strcpy(opt_string[++top], "SINGLE-PRODUCTIONS"); else strcpy(opt_string[++top], "NOSINGLE-PRODUCTIONS"); if (slr_bit) strcpy(opt_string[++top], "SLR"); sprintf(opt_string[++top], "STACK-SIZE=%d",stack_size); if (states_bit) strcpy(opt_string[++top], "STATES"); else strcpy(opt_string[++top], "NOSTATES"); sprintf(opt_string[++top], "SUFFIX=%s",suffix); if (table_opt == 0) strcpy(opt_string[++top], "NOTABLE"); else if (table_opt == OPTIMIZE_SPACE) strcpy(opt_string[++top], "TABLE=SPACE"); else strcpy(opt_string[++top], "TABLE=TIME"); if (trace_opt == NOTRACE) strcpy(opt_string[++top], "NOTRACE"); else if (trace_opt == TRACE_CONFLICTS) strcpy(opt_string[++top], "TRACE=CONFLICTS"); else strcpy(opt_string[++top], "TRACE=FULL"); if (verbose_bit) strcpy(opt_string[++top], "VERBOSE"); else strcpy(opt_string[++top], "NOVERBOSE"); if (warnings_bit) strcpy(opt_string[++top], "WARNINGS"); else strcpy(opt_string[++top], "NOWARNINGS"); if (xref_bit) strcpy(opt_string[++top], "XREF"); else strcpy(opt_string[++top], "NOXREF"); PRNT("Options in effect:"); strcpy(output_line, " "); for (i = 1; i <= top; i++) { if (strlen(output_line) + strlen(opt_string[i]) > PRINT_LINE_SIZE-1) { PRNT(output_line); strcpy(output_line, " "); } strcat(output_line, opt_string[i]); if (strlen(output_line) + 2 < PRINT_LINE_SIZE-1) strcat(output_line, " "); } PRNT(output_line); PRNT(""); if (warnings_bit) { if (table_opt == OPTIMIZE_SPACE) { if (default_opt < 4) { PRNTWNG("DEFAULT_OPTion requested must be >= 4"); } } else if (shift_default_bit) { PRNTWNG("SHIFT-DEFAULT option is only valid for Space tables") } } /*********************************************************************/ /* Check if there are any conflicts in the options. */ /*********************************************************************/ temp[0] = '\0'; if (minimum_distance <= 1) { PRNT("MIN_DISTANCE must be > 1"); exit(12); } if (maximum_distance <= minimum_distance + 1) { PRNT("MAX_DISTANCE must be > MIN_DISTANCE + 1"); exit(12); } if (strcmp(blockb, blocke) == 0) strcpy(temp, "BLOCKB and BLOCKE"); else if (strlen(blockb) == 1 && blockb[0] == escape) strcpy(temp, "BLOCKB and ESCAPE"); else if (strlen(blockb) == 1 && blockb[0] == ormark) strcpy(temp, "BLOCKB and ORMARK"); else if (strlen(blocke) == 1 && blocke[0] == escape) strcpy(temp, "ESCAPE and BLOCKE"); else if (strlen(blocke) == 1 && blocke[0] == ormark) strcpy(temp, "ORMARK and BLOCKE"); else if (strcmp(hblockb, hblocke) == 0) strcpy(temp, "HBLOCKB and HBLOCKE"); else if (strlen(hblockb) == 1 && hblockb[0] == escape) strcpy(temp, "HBLOCKB and ESCAPE"); else if (strlen(hblockb) == 1 && hblockb[0] == ormark) strcpy(temp, "HBLOCKB and ORMARK"); else if (strlen(hblocke) == 1 && hblocke[0] == escape) strcpy(temp, "ESCAPE and HBLOCKE"); else if (strlen(hblocke) == 1 && hblocke[0] == ormark) strcpy(temp, "ORMARK and HBLOCKE"); else if (ormark == escape) strcpy(temp, "ORMARK and ESCAPE"); if (temp[0] != '\0') { sprintf(msg_line, "The options %s cannot have the same value", temp); PRNTERR(msg_line); sprintf(msg_line, "Input process aborted at line %d ...", line_no); PRNT(msg_line); exit(12); } if (strlen(hblockb) <= strlen(blockb) && memcmp(hblockb, blockb, strlen(hblockb)) == 0) { sprintf(msg_line, "Hblockb value, %s, cannot be a suffix of blockb: %s", hblockb, blockb); PRNTERR(msg_line); sprintf(msg_line, "Input process aborted at line %d ...", line_no); PRNT(msg_line); exit(12); } return; } /* end process_options_lines */ /*****************************************************************************/ /* HASH: */ /*****************************************************************************/ /* HASH takes as argument a symbol and hashes it into a location in */ /* HASH_TABLE. */ /*****************************************************************************/ static int hash(char *symb) { register unsigned short k; register unsigned long hash_value = 0; for (; *symb != '\0'; symb++) { k = *symb; symb++; hash_value += ((k << 7) + *symb); if (*symb == '\0') break; } return hash_value % HT_SIZE; } /*****************************************************************************/ /* INSERT_STRING: */ /*****************************************************************************/ /* INSERT_STRING takes as an argument a pointer to a ht_elemt structure and*/ /* a character string. It inserts the string into the string table and sets */ /* the value of node to the index into the string table. */ /*****************************************************************************/ static void insert_string(struct hash_type *q, char *string) { if (string_offset + strlen(string) >= string_size) { string_size += STRING_BUFFER_SIZE; INT_CHECK(string_size); string_table = (char *) (string_table == (char *) NULL ? malloc(string_size * sizeof(char)) : realloc(string_table, string_size * sizeof(char))); if (string_table == (char *) NULL) nospace(__FILE__, __LINE__); } q -> st_ptr = string_offset; while(string_table[string_offset++] = *string++); /* Copy until NULL */ /* is copied. */ return; } /*****************************************************************************/ /* ASSIGN_SYMBOL_NO: */ /*****************************************************************************/ /* PROCESS_SYMBOL takes as an argument a pointer to the most recent token */ /* which would be either a symbol or a macro name and then processes it. If */ /* the token is a a macro name then a check is made to see if it is a pre- */ /* defined macro. If it is then an error message is printed and the program */ /* is halted. If not, or if the token is a symbol then it is hashed into the */ /* hash_table and its string is copied into the string table. A struct is */ /* created for the token. The ST_PTR field contains the index into the string*/ /* table and the NUMBER field is set to zero. Later on if the token is a */ /* symbol, the value of the NUMBER field is changed to the appropriate symbol*/ /* number. However, if the token is a macro name, its value will remain zero.*/ /* The NAME_INDEX field is set to OMEGA and will be assigned a value later. */ /*****************************************************************************/ /* ASSIGN_SYMBOL_NO takes as arguments a pointer to a node and an image */ /* number and assigns a symbol number to the symbol pointed to by the node. */ /*****************************************************************************/ static void assign_symbol_no(char *string_ptr, int image) { register int i; register struct hash_type *p; i = hash(string_ptr); for (p = hash_table[i]; p != NULL; p = p -> link) { if (EQUAL_STRING(string_ptr, p)) /* Are they the same */ return; } p = (struct hash_type *) talloc(sizeof(struct hash_type)); if (p == (struct hash_type *) NULL) nospace(__FILE__, __LINE__); if (image == OMEGA) { num_symbols++; p -> number = num_symbols; } else p -> number = -image; p -> name_index = OMEGA; insert_string(p, string_ptr); p -> link = hash_table[i]; hash_table[i] = p; return; } /*****************************************************************************/ /* ALIAS_MAP: */ /*****************************************************************************/ /* ALIAS_MAP takes as input a symbol and an image. It searcheds the hash */ /* table for stringptr and if it finds it, it turns it into an alias of the */ /* symbol whose number is IMAGE. Otherwise, it invokes PROCESS_SYMBOL and */ /* ASSIGN SYMBOL_NO to enter stringptr into the table and then we alias it. */ /*****************************************************************************/ static void alias_map(char *stringptr, int image) { register struct hash_type *q; for (q = hash_table[hash(stringptr)]; q != NULL; q = q -> link) { if (EQUAL_STRING(stringptr, q)) { q -> number = -image; /* Mark alias of image */ return; } } assign_symbol_no(stringptr, image); return; } /*****************************************************************************/ /* SYMBOL_IMAGE: */ /*****************************************************************************/ /* SYMBOL_IMAGE takes as argument a symbol. It searches for that symbol */ /* in the HASH_TABLE, and if found, it returns its image; otherwise, it */ /* returns OMEGA. */ /*****************************************************************************/ static int symbol_image(char *item) { register struct hash_type *q; for (q = hash_table[hash(item)]; q != NULL; q = q -> link) { if (EQUAL_STRING(item, q)) return ABS(q -> number); } return(OMEGA); } /*****************************************************************************/ /* NAME_MAP: */ /*****************************************************************************/ /* NAME_MAP takes as input a symbol and inserts it into the HASH_TABLE if it */ /* is not yet in the table. If it was already in the table then it is */ /* assigned a NAME_INDEX number if it did not yet have one. The name index */ /* assigned is returned. */ /*****************************************************************************/ static int name_map(char *symb) { register int i; register struct hash_type *p; i = hash(symb); for (p = hash_table[i]; p != NULL; p = p -> link) { if (EQUAL_STRING(symb, p)) { if (p -> name_index != OMEGA) return(p -> name_index); else { num_names++; p -> name_index = num_names; return(num_names); } } } p = (struct hash_type *) talloc(sizeof(struct hash_type)); if (p == (struct hash_type *) NULL) nospace(__FILE__, __LINE__); p -> number = 0; insert_string(p, symb); p -> link = hash_table[i]; hash_table[i] = p; num_names++; p -> name_index = num_names; return num_names; } /*****************************************************************************/ /* PROCESS_GRAMMAR: */ /*****************************************************************************/ /* PROCESS_GRAMMAR is invoked to process the source input. It uses an */ /* LALR(1) parser table generated by LPG to recognize the grammar which it */ /* places in the rulehdr structure. */ /*****************************************************************************/ #include "lpgact.i" #include "lpgact.h" #include "lpgprs.h" static void process_grammar(void) { short state_stack[STACK_SIZE]; register int act; scanner(); /* Get first token */ act = START_STATE; process_terminal: /******************************************************************/ /* Note that this driver assumes that the tables are LPG SPACE */ /* tables with no GOTO-DEFAULTS. */ /******************************************************************/ state_stack[++stack_top] = act; act = t_action(act, ct, ?); if (act <= NUM_RULES) /* Reduce */ stack_top--; else if ((act > ERROR_ACTION) || /* Shift_reduce */ (act < ACCEPT_ACTION)) /* Shift */ { token_action(); scanner(); if (act < ACCEPT_ACTION) goto process_terminal; act -= ERROR_ACTION; } else if (act == ACCEPT_ACTION) { accept_action(); return; } else error_action(); process_non_terminal: do { register int lhs_sym = lhs[act]; /* to bypass IBMC12 bug */ stack_top -= (rhs[act] - 1); rule_action[act](); act = nt_action(state_stack[stack_top], lhs_sym); } while(act <= NUM_RULES); goto process_terminal; } /*****************************************************************************/ /* SCANNER: */ /*****************************************************************************/ /* SCANNER scans the input stream and returns the next input token. */ /*****************************************************************************/ static void scanner(void) { register int i; register char *p3; char tok_string[SYMBOL_SIZE + 1]; scan_token: /*****************************************************************/ /* Skip "blank" spaces. */ /*****************************************************************/ p1 = p2; while(IsSpace(*p1)) { if (*(p1++) == '\n') { if (bufend == input_buffer + IOBUFFER_SIZE) { i = bufend - p1; if (i < MAX_LINE_SIZE) { strcpy(input_buffer, p1); bufend = &input_buffer[i]; read_input(); p1 = &input_buffer[0]; } } line_no++; linestart = p1 - 1; } } if (strncmp(p1, hblockb, hblockb_len) == 0) /* check block opener */ { p1 = p1 + hblockb_len; ct_length = 0; ct_ptr = p1; if (*p1 == '\n') { ct_ptr++; ct_length--; ct_start_line = line_no + 1; ct_start_col = 1; } else { ct_start_line = line_no; ct_start_col = p1 - linestart; } while(strncmp(p1, hblocke, hblocke_len) != 0) { if (*p1 == '\0') { sprintf(msg_line, "End of file encountered while " "scanning header action block in rule %d", num_rules); PRNTERR(msg_line); exit(12); } if (*(p1++) == '\n') { if (bufend == input_buffer + IOBUFFER_SIZE) { i = bufend - p1; if (i < MAX_LINE_SIZE) { strcpy(input_buffer, p1); bufend = &input_buffer[i]; read_input(); p1 = &input_buffer[0]; } } line_no++; linestart = p1 - 1; } ct_length++; } ct = HBLOCK_TK; ct_end_line = line_no; ct_end_col = p1 - linestart - 1; p2 = p1 + hblocke_len; return; } else if (strncmp(p1, blockb, blockb_len) == 0) /* check block */ { p1 = p1 + blockb_len; ct_length = 0; ct_ptr = p1; if (*p1 == '\n') { ct_ptr++; ct_length--; ct_start_line = line_no + 1; ct_start_col = 1; } else { ct_start_line = line_no; ct_start_col = p1 - linestart; } while(strncmp(p1, blocke, blocke_len) != 0) { if (*p1 == '\0') { sprintf(msg_line, "End of file encountered while " "scanning action block in rule %d", num_rules); PRNTERR(msg_line); exit(12); } if (*(p1++) == '\n') { if (bufend == input_buffer + IOBUFFER_SIZE) { i = bufend - p1; if (i < MAX_LINE_SIZE) { strcpy(input_buffer, p1); bufend = &input_buffer[i]; read_input(); p1 = &input_buffer[0]; } } line_no++; linestart = p1 - 1; } ct_length++; } ct = BLOCK_TK; ct_end_line = line_no; ct_end_col = p1 - linestart - 1; p2 = p1 + blocke_len; return; } /*********************************************************************/ /* Scan the next token. */ /*********************************************************************/ ct_ptr = p1; ct_start_line = line_no; ct_start_col = p1 - linestart; p2 = p1 + 1; switch(*p1) { case '<': if (IsAlpha(*p2)) { p2++; while(*p2 != '\n') { if (*(p2++) == '>') { ct = SYMBOL_TK; ct_length = p2 - p1; goto check_symbol_length; } } i = min(SYMBOL_SIZE, p2 - p1); memcpy(tok_string, p1, i); tok_string[i] = '\0'; sprintf(msg_line, "Symbol \"%s\"" " has been referenced in line %d " " without the closing \">\"", tok_string, ct_start_line); PRNTERR(msg_line); exit(12); } break; case '\'': ct_ptr = p2; ct = SYMBOL_TK; while(*p2 != '\n') { if (*p2 == '\'') { p2++; if (*p2 != '\'') { ct_length = p2 - p1 - 2; goto remove_quotes; } } p2++; } ct_length = p2 - p1 - 1; if (warnings_bit) { memcpy(tok_string, p1, ct_length); tok_string[ct_length] = '\0'; sprintf(msg_line, "Symbol \"%s\" referenced in line %d" " requires a closing quote", tok_string, ct_start_line); PRNTWNG(msg_line); } remove_quotes: if (ct_length == 0) /* Empty symbol? disregard it */ goto scan_token; i = 0; p1 = ct_ptr; do { *(p1++) = ct_ptr[i++]; if (ct_ptr[i] == '\'') i++; /* skip next quote */ } while(i < ct_length); ct_length = p1 - ct_ptr; goto check_symbol_length; case '-': /* scan possible comment */ if (*p2 == '-') { p2++; while(*p2 != '\n') p2++; goto scan_token; } else if (*p2 == '>' && IsSpace(*(p2+1))) { ct = ARROW_TK; ct_length = 2; p2++; return; } break; case ':': if (*p2 == ':' && *(p2+1) == '=' && IsSpace(*(p2+2))) { ct = EQUIVALENCE_TK; ct_length = 3; p2 = p1 + 3; return; } break; case '\0': case CTL_Z: /* END-OF-FILE? */ ct = EOF_TK; ct_length = 0; p2 = p1; return; default: if (*p1 == ormark && IsSpace(*p2)) { ct = OR_TK; ct_length = 1; return; } else if (*p1 == escape) /* escape character? */ { p3 = p2 + 1; switch(*p2) { case 't': case 'T': if (strxeq(p3, "erminals") && IsSpace(*(p1+10))) { ct = TERMINALS_KEY_TK; ct_length = 10; p2 = p1 + 10; return; } break; case 'd': case 'D': if (strxeq(p3, "efine") && IsSpace(*(p1+7))) { ct = DEFINE_KEY_TK; ct_length = 7; p2 = p1 + 7; return; } break; case 'e': case 'E': if (strxeq(p3, "mpty") && IsSpace(*(p1+6))) { ct = EMPTY_SYMBOL_TK; ct_length = 6; p2 = p1 + 6; return; } if (strxeq(p3, "rror") && IsSpace(*(p1+6))) { ct = ERROR_SYMBOL_TK; ct_length = 6; p2 = p1 + 6; return; } if (strxeq(p3, "ol") && IsSpace(*(p1+4))) { ct = EOL_SYMBOL_TK; ct_length = 4; p2 = p1 + 4; return; } if (strxeq(p3, "of") && IsSpace(*(p1+4))) { ct = EOF_SYMBOL_TK; ct_length = 4; p2 = p1 + 4; return; } if (strxeq(p3, "nd") && IsSpace(*(p1+4))) { ct = END_KEY_TK; ct_length = 4; p2 = p1 + 4; return; } break; case 'r': case 'R': if (strxeq(p3, "ules") && IsSpace(*(p1+6))) { ct = RULES_KEY_TK; ct_length = 6; p2 = p1 + 6; return; } break; case 'a': case 'A': if (strxeq(p3, "lias") && IsSpace(*(p1+6))) { ct = ALIAS_KEY_TK; ct_length = 6; p2 = p1 + 6; return; } break; case 's': case 'S': if (strxeq(p3, "tart") && IsSpace(*(p1+6))) { ct = START_KEY_TK; ct_length = 6; p2 = p1 + 6; return; } break; case 'n': case 'N': if (strxeq(p3, "ames") && IsSpace(*(p1+6))) { ct = NAMES_KEY_TK; ct_length = 6; p2 = p1 + 6; return; } break; default: break; } ct = MACRO_NAME_TK; while(! IsSpace(*p2)) p2++; ct_length = p2 - p1; goto check_symbol_length; } } ct = SYMBOL_TK; while(! IsSpace(*p2)) p2++; ct_length = p2 - p1; check_symbol_length: if (ct_length > SYMBOL_SIZE) { ct_length = SYMBOL_SIZE; memcpy(tok_string, p1, ct_length); tok_string[ct_length] = '\0'; if (warnings_bit) { if (symbol_image(tok_string) == OMEGA) { sprintf(msg_line, "Length of Symbol \"%s\"" " in line %d exceeds maximum of ", tok_string, line_no); PRNTWNG(msg_line); } } } return; } /****************************************************************************/ /* TOKEN_ACTION: */ /****************************************************************************/ /* This function, TOKEN_ACTION, pushes the current token onto the */ /* parse stack called TERMINAL. Note that in case of a BLOCK_, the name of */ /* the token is not copied since blocks are processed separately on a */ /* second pass. */ /****************************************************************************/ static void token_action(void) { register int top = stack_top + 1; terminal[top].kind = ct; terminal[top].start_line = ct_start_line; terminal[top].start_column = ct_start_col; terminal[top].end_line = ct_end_line; terminal[top].end_column = ct_end_col; terminal[top].length = ct_length; if (ct != BLOCK_TK) { memcpy(terminal[top].name, ct_ptr, ct_length); terminal[top].name[ct_length] = '\0'; } else terminal[top].name[0] = '\0'; return; } /****************************************************************************/ /* ERROR_ACTION: */ /****************************************************************************/ /* Error messages to be printed if an error is encountered during parsing. */ /****************************************************************************/ static void error_action(void) { char tok_string[SYMBOL_SIZE + 1]; ct_ptr[ct_length] = '\0'; if (ct == EOF_TK) sprintf(msg_line, "End-of file reached prematurely"); else if (ct == MACRO_NAME_TK) { sprintf(msg_line, "Misplaced macro name \"%s\" found " "in line %d, column %d", ct_ptr, line_no, ct_start_col); } else if (ct == SYMBOL_TK) { restore_symbol(tok_string, ct_ptr); sprintf(msg_line, "Misplaced symbol \"%s\" found " "in line %d, column %d", tok_string, line_no, ct_start_col); } else { sprintf(msg_line, "Misplaced keyword \"%s\" found " "in line %d, column %d", ct_ptr, line_no, ct_start_col); } PRNTERR(msg_line); exit(12); } /****************************************************************************/ /* ACCEPT_ACTION: */ /****************************************************************************/ /* Actions to be taken if grammar is successfully parsed. */ /****************************************************************************/ static void accept_action(void) { if (rulehdr == NULL) { printf("Informative: Empty grammar read in. " "Processing stopped.\n"); fprintf(syslis, "***Informative: Empty grammar read in. " "Processing stopped.\n"); fclose(sysgrm); fclose(syslis); exit(12); } num_non_terminals = num_symbols - num_terminals; if (error_maps_bit) make_names_map(); if (list_bit) process_aliases(); make_rules_map(); /* Construct rule table */ fclose(sysgrm); /* Close grammar input file. */ if (action_bit) process_actions(); else if (list_bit) display_input(); return; } /*****************************************************************************/ /* BUILD_SYMNO: */ /*****************************************************************************/ /* BUILD_SYMNO constructs the SYMNO table which is a mapping from each */ /* symbol number into that symbol. */ /*****************************************************************************/ static void build_symno(void) { register int i, symbol; register struct hash_type *p; symno_size = num_symbols + 1; symno = (struct symno_type *) calloc(symno_size, sizeof(struct symno_type)); if (symno == (struct symno_type *) NULL) nospace(__FILE__, __LINE__); /***********************************************************************/ /* Go thru entire hash table. For each non_empty bucket, go through */ /* linked list in that bucket. */ /***********************************************************************/ for (i = 0; i < HT_SIZE; ++i) { for (p = hash_table[i]; p != NULL; p = p -> link) { symbol = p -> number; if (symbol >= 0) /* Not an alias */ { symno[symbol].name_index = OMEGA; symno[symbol].ptr = p -> st_ptr; } } } return; } /****************************************************************************/ /* PROCESS_ACTIONS: */ /****************************************************************************/ /* Process all semantic actions and generate action file. */ /****************************************************************************/ static void process_actions(void) { register int i, j, k, len; register char *p; char line[MAX_LINE_SIZE + 1]; #if defined(C370) && !defined(CW) sprintf(msg_line, "w, recfm=%cB, lrecl=%d", record_format, output_size); if (record_format != 'F') output_size -= 4; sysact = fopen(act_file, msg_line); syshact = fopen(hact_file, msg_line); #else sysact = fopen(act_file, "w"); syshact = fopen(hact_file, "w"); #endif if (sysact == (FILE *) NULL) { fprintf(stderr, "***ERROR: Action file \"%s\" cannot be opened.\n", act_file); exit(12); } if (syshact == (FILE *) NULL) { fprintf(stderr, "***ERROR: Header Action file " "\"%s\" cannot be opened.\n", hact_file); exit(12); } if ((sysgrm = fopen(grm_file, "r")) == (FILE *) NULL) { fprintf(stderr, "***ERROR: Input file %s containing grammar " "is empty, undefined, or invalid\n",grm_file); exit(12); } macro_table = Allocate_short_array(HT_SIZE); for (i = 0; i < HT_SIZE; i++) macro_table[i] = NIL; bufend = &input_buffer[0]; read_input(); p2 = &input_buffer[0]; linestart = p2 - 1; p1 = p2; line_no = 1; /***********************************************************************/ /* Read in all the macro definitions and insert them into macro_table. */ /***********************************************************************/ for (i = 0; i < num_defs; i++) { defelmt[i].macro = (char *) calloc(defelmt[i].length + 2, sizeof(char)); if (defelmt[i].macro == (char *) NULL) nospace(__FILE__, __LINE__); for (; line_no < defelmt[i].start_line; line_no++) { while (*p1 != '\n') p1++; p1++; if (bufend == input_buffer + IOBUFFER_SIZE) { k = bufend - p1; if (k < MAX_LINE_SIZE) { strcpy(input_buffer, p1); bufend = &input_buffer[k]; read_input(); p1 = &input_buffer[0]; } } linestart = p1 - 1; } p1 = linestart + defelmt[i].start_column; for (j = 0; j < defelmt[i].length; j++) { defelmt[i].macro[j] = *p1; if (*(p1++) == '\n') { if (bufend == input_buffer + IOBUFFER_SIZE) { k = bufend - p1; if (k < MAX_LINE_SIZE) { strcpy(input_buffer, p1); bufend = &input_buffer[k]; read_input(); p1 = &input_buffer[0]; } } line_no++; linestart = p1 - 1; } } defelmt[i].macro[defelmt[i].length] = '\n'; defelmt[i].macro[defelmt[i].length + 1] = '\0'; for (p = defelmt[i].name; *p != '\0'; p++) { *p = (isupper(*p) ? tolower(*p) : *p); } mapmacro(i); } /****************************************************************************/ /* If LISTING was requested, invoke listing procedure. */ /****************************************************************************/ if (list_bit) display_input(); /****************************************************************************/ /* Read in all the action blocks and process them. */ /****************************************************************************/ for (i = 0; i < num_acts; i++) { for (; line_no < actelmt[i].start_line; line_no++) { while (*p1 != '\n') p1++; p1++; if (bufend == input_buffer + IOBUFFER_SIZE) { k = bufend - p1; if (k < MAX_LINE_SIZE) { strcpy(input_buffer, p1); bufend = &input_buffer[k]; read_input(); p1 = &input_buffer[0]; } } linestart = p1 - 1; } if (actelmt[i].start_line == actelmt[i].end_line) { len = actelmt[i].end_column - actelmt[i].start_column + 1; memcpy(line, linestart + actelmt[i].start_column, len); line[len] = '\0'; while (*p1 != '\n') p1++; } else { p = line; p1 = linestart + actelmt[i].start_column; while (*p1 != '\n') *(p++) = *(p1++); *p = '\0'; } if (actelmt[i].header_block) process_action_line(syshact, line, line_no, actelmt[i].rule_number); else process_action_line(sysact, line, line_no, actelmt[i].rule_number); if (line_no != actelmt[i].end_line) { while (line_no < actelmt[i].end_line) { p1++; if (bufend == input_buffer + IOBUFFER_SIZE) { k = bufend - p1; if (k < MAX_LINE_SIZE) { strcpy(input_buffer, p1); bufend = &input_buffer[k]; read_input(); p1 = &input_buffer[0]; } } line_no++; linestart = p1 - 1; if (line_no < actelmt[i].end_line) { p = line; while (*p1 != '\n') *(p++) = *(p1++); *p = '\0'; if (actelmt[i].header_block) process_action_line(syshact, line, line_no, actelmt[i].rule_number); else process_action_line(sysact, line, line_no, actelmt[i].rule_number); } } if (actelmt[i].end_column != 0) { len = actelmt[i].end_column; memcpy(line, p1, len); line[len] = '\0'; if (actelmt[i].header_block) process_action_line(syshact, line, line_no, actelmt[i].rule_number); else process_action_line(sysact, line, line_no, actelmt[i].rule_number); } } } for (i = 0; i < num_defs; i++) { ffree(defelmt[i].macro); } ffree(defelmt); ffree(actelmt); fclose(sysgrm); /* Close grammar file and reopen it. */ fclose(sysact); fclose(syshact); return; } /************************************************************************/ /* MAKE_NAMES_MAP: */ /************************************************************************/ /* Construct the NAME map, and update the elements of SYMNO with their */ /* names. */ /************************************************************************/ static void make_names_map(void) { register int i, symbol; register struct hash_type *p; symno[accept_image].name_index = name_map(""); if (error_image == DEFAULT_SYMBOL) symno[DEFAULT_SYMBOL].name_index = symno[accept_image].name_index; for ALL_TERMINALS(symbol) { if (symno[symbol].name_index == OMEGA) symno[symbol].name_index = name_map(RETRIEVE_STRING(symbol)); } for ALL_NON_TERMINALS(symbol) { if (symno[symbol].name_index == OMEGA) { if (names_opt == MAXIMUM_NAMES) symno[symbol].name_index = name_map(RETRIEVE_STRING(symbol)); else if (names_opt == OPTIMIZE_PHRASES) symno[symbol].name_index = - name_map(RETRIEVE_STRING(symbol)); else symno[symbol].name_index = symno[error_image].name_index; } } /************************/ /* Allocate NAME table. */ /************************/ name = (int *) calloc(num_names + 1, sizeof(int)); if (name == (int *) NULL) nospace(__FILE__, __LINE__); for (i = 0; i < HT_SIZE; i++) { for (p = hash_table[i]; p != NULL; p = p -> link) { if (p -> name_index != OMEGA) name[p -> name_index] = p -> st_ptr; } } return; } /*****************************************************************************/ /* MAKE_RULES_MAP: */ /*****************************************************************************/ /* Construct the rule table. At this stage, NUM_ITEMS is equal to the sum */ /* of the right-hand side lists of symbols. It is used in the declaration of*/ /* RULE_TAB. After RULE_TAB is allocated, we increase NUM_ITEMS to its */ /* correct value. Recall that the first rule is numbered 0; therefore we */ /* increase the number of items by 1 to reflect this numbering. */ /*****************************************************************************/ static void make_rules_map(void) { register struct node *ptr, *q; char temp[SYMBOL_SIZE + 1]; register int i = 0, rhs_ct = 0; rules = (struct ruletab_type *) calloc(num_rules + 2, sizeof(struct ruletab_type)); if (rules == (struct ruletab_type *) NULL) nospace(__FILE__, __LINE__); rhs_sym = Allocate_short_array(num_items + 1); num_items += (num_rules + 1); SHORT_CHECK(num_items); /*****************************************************************************/ /* Put starting rules from start symbol linked list in rule and rhs table */ /*****************************************************************************/ if (start_symbol_root != NULL) { /* Turn circular list into linear */ q = start_symbol_root; start_symbol_root = q -> next; q -> next = NULL; for (ptr = start_symbol_root; ptr != NULL; ptr = ptr -> next) { rules[i].lhs = accept_image; rules[i].sp = 0; rules[i++].rhs = rhs_ct; if (ptr -> value != empty) rhs_sym[rhs_ct++] = ptr -> value; } free_nodes(start_symbol_root, q); } /*****************************************************************************/ /* In this loop, the grammar is placed in the rule table structure and the */ /* right-hand sides are placed in the RHS table. A check is made to prevent */ /* terminals from being used as left hand sides. */ /*****************************************************************************/ for (i = i; i <= num_rules; i++) { rules[i].rhs = rhs_ct; ptr = rulehdr[i].rhs_root; if (ptr != NULL) /* not am empty right-hand side? */ { do { ptr = ptr -> next; rhs_sym[rhs_ct++] = ptr -> value; } while (ptr != rulehdr[i].rhs_root); ptr = ptr -> next; /* point to 1st element */ rules[i].sp = (rulehdr[i].sp && ptr == rulehdr[i].rhs_root); if (rules[i].sp) num_single_productions++; free_nodes(ptr, rulehdr[i].rhs_root); } else rules[i].sp = FALSE; if (rulehdr[i].lhs == OMEGA) { if (list_bit) /* Proper LHS will be updated after printing */ rules[i].lhs = OMEGA; else rules[i].lhs = rules[i - 1].lhs; } else if (rulehdr[i].lhs IS_A_TERMINAL) { restore_symbol(temp, RETRIEVE_STRING(rulehdr[i].lhs)); sprintf(msg_line, "In rule %d: terminal \"%s\" used as left hand side", i, temp); PRNTERR(msg_line); PRNTERR("Processing terminated due to input errors."); exit(12); } else rules[i].lhs = rulehdr[i].lhs; } rules[num_rules + 1].rhs = rhs_ct; /* Fence !! */ return; } /****************************************************************************/ /* ALLOC_LINE: */ /****************************************************************************/ /* This function allocates a line_elemt structure and returns a pointer */ /* to it. */ /****************************************************************************/ static struct line_elemt *alloc_line(void) { register struct line_elemt *p; p = line_pool_root; if (p != NULL) line_pool_root = p -> link; else { p = (struct line_elemt *) talloc(sizeof(struct line_elemt)); if (p == (struct line_elemt *) NULL) nospace(__FILE__, __LINE__); } return(p); } /****************************************************************************/ /* FREE_LINE: */ /****************************************************************************/ /* This function frees a line_elemt structure which is returned to a free */ /* pool. */ /****************************************************************************/ static void free_line(struct line_elemt *p) { p -> link = line_pool_root; line_pool_root = p; return; } /*****************************************************************************/ /* PROCESS_ACTION_LINE: */ /*****************************************************************************/ /* PROCESS_ACTION_LINE takes as arguments a line of text from an action */ /* block and the rule number with which thwe block is associated. */ /* It first scans the text for predefined macro names and then for */ /* user defined macro names. If one is found, the macro definition is sub- */ /* stituted for the name. The modified action text is then printed out in */ /* the action file. */ /*****************************************************************************/ static void process_action_line(FILE *sysout, char *text, int line_no, int rule_no) { register int j, k, text_len; char temp1[MAX_LINE_SIZE + 1]; char temp2[MAX_LINE_SIZE + 1]; char suffix[MAX_LINE_SIZE + 1]; char symbol[SYMBOL_SIZE + 1]; struct line_elemt *q; struct line_elemt *root = NULL; struct line_elemt *input_line_root = NULL; next_line: text_len = strlen(text); k = 0; /* k is the cursor */ while (k < text_len) { if (text[k] == escape) /* all macro names begin with the ESCAPE */ { /* character */ if (k + 12 <= text_len) /* 12 is length of %rule_number and */ /* %num_symbols. */ { if (strxeq(text + k, krule_number)) { strcpy(temp1, text + k + 12); if (k + 12 != text_len) sprintf(text + k, "%d%s", rule_no, temp1); else sprintf(text + k, "%d", rule_no); goto proceed; } if (strxeq(text + k, knum_symbols)) { strcpy(temp1, text + k + 12); if (k + 12 != text_len) sprintf(text + k, "%d%s", num_symbols, temp1); else sprintf(text + k, "%d", num_symbols); goto proceed; } } if (k + 11 <= text_len) /* 11 is the length of %input_file */ { if (strxeq(text + k, kinput_file)) { strcpy(temp1, text + k + 11); if (k + 11 != text_len) sprintf(text + k, "%s%s", grm_file, temp1); else sprintf(text + k, "%s", grm_file); goto proceed; } } if (k + 10 <= text_len) /* 10 is the length of %rule_size and */ /* %rule_text, %num_rules and %next_line */ { if (strxeq(text + k, krule_text)) { register int max_len; if (k + 10 != text_len) { strcpy(temp1, text + k + 10); /* Remove trailing blanks */ for (j = strlen(temp1) - 1; j >= 0 && temp1[j] == ' '; j--); if (j != 0) /* if not a string of blanks */ temp1[++j] = '\0'; else temp1[0] = '\0'; } else { temp1[0] = '\0'; j = 0; } max_len = output_size - k - j; restore_symbol(temp2, RETRIEVE_STRING(rules[rule_no].lhs)); if (rules[rule_no].sp) /* if a single production */ strcat(temp2, " ->"); else strcat(temp2, " ::="); if (strlen(temp2) > max_len) strcpy(temp2, " ... "); else /* Copy right-hand-side symbols to temp2 */ { for ENTIRE_RHS(j, rule_no) { restore_symbol(symbol, RETRIEVE_STRING(rhs_sym[j])); if (strlen(temp2) + strlen(symbol) + 1 < max_len) { strcat(temp2, BLANK); strcat(temp2, symbol); } else { if (strlen(temp2) + 3 < max_len) strcat(temp2, "..."); break; } } } text[k] = '\0'; strcat(text, temp2); strcat(text, temp1); k = k - 1 + strlen(temp2); /* Adjust cursor */ goto proceed; } if (strxeq(text + k, krule_size)) { strcpy(temp1, text + k + 10); if (k + 10 != text_len) sprintf(text + k, "%d%s", RHS_SIZE(rule_no), temp1); else sprintf(text + k, "%d", RHS_SIZE(rule_no)); goto proceed; } if (strxeq(text + k, knext_line)) { strcpy(temp1, text + k + 10); if (k + 10 != text_len) sprintf(text + k, "%d%s", line_no + 1, temp1); else sprintf(text + k, "%d", line_no + 1); goto proceed; } if (strxeq(text + k, knum_rules)) { strcpy(temp1, text + k + 10); if (k + 10 != text_len) sprintf(text + k, "%d%s", num_rules, temp1); else sprintf(text + k, "%d", num_rules); goto proceed; } } if (k + 13 <= text_len) /* 13 is length of %current_line */ { if (strxeq(text + k, kcurrent_line)) { strcpy(temp1, text + k + 13); if (k + 13 != text_len) sprintf(text + k, "%d%s", line_no, temp1); else sprintf(text + k, "%d", line_no); goto proceed; } } if (k + 14 <= text_len) /* 14 is length of %num_terminals */ { if (strxeq(text + k, knum_terminals)) { strcpy(temp1, text + k + 14); if (k + 14 != text_len) sprintf(text + k, "%d%s", num_terminals, temp1); else sprintf(text + k, "%d", num_terminals); goto proceed; } } if (k + 18 <= text_len) /* 18 is length of %num_non_terminals */ { if (strxeq(text + k, knum_non_terminals)) { strcpy(temp1, text + k + 18); if (k + 18 != text_len) sprintf(text + k, "%d%s", num_non_terminals, temp1); else sprintf(text + k, "%d", num_non_terminals); goto proceed; } } /*****************************************************************************/ /* Macro in question is not one of the predefined macros. Try user-defined */ /* macro list. */ /*****************************************************************************/ /* find next delimeter */ for (j = k + 1; j < text_len && !IsSpace(text[j]); ++j) ; memcpy(symbol, text + k, j - k); /* copy macro name into symbol */ symbol[j - k] = '\0'; if (j < text_len) /* Is there any text after macro ? */ strcpy(suffix, text + j); /* Copy rest of text into "suffix". */ else suffix[0] = '\0'; text[k] = '\0'; /* prefix before macro */ root = find_macro(symbol); /* "root" points to a circular */ /* linked list of line_elemt(s) */ /* containing macro definition. */ if (root != NULL) /* if macro name was found */ { struct line_elemt *tail; q = root; root = root -> link; if (suffix[0] != '\0') { /**********************************************/ /* If there is room to add the suffix to the */ /* last macro line then do it. Or else */ /* allocate a new line_elemt, copy the suffix */ /* into it and add it to the list of lines to */ /* be processed. */ /**********************************************/ if (strlen(q -> line) + strlen(suffix) < output_size) { strcat(q -> line, suffix); tail = q; } else { tail = alloc_line(); strcpy(tail -> line, suffix); q -> link = tail; } } else tail = q; tail -> link = NULL; /* make circular list linear */ /****************************************************/ /* If there is space for the first macro line to be */ /* added to the prefix then do it. */ /****************************************************/ if (strlen(text) + strlen(root -> line) < output_size) { strcat(text, root -> line); q = root; root = root -> link; free_line(q); } /*********************************************/ /* if there are more macro lines to process, */ /* add list to list headed by INPUT_LINE_ROOT*/ /*********************************************/ if (root != NULL) { tail -> link = input_line_root; input_line_root = root; } k--; } else /* If macro name is not found then rebuild line.*/ { strcat(text, symbol); if (suffix[0] != '\0') strcat(text, suffix); k = j; } proceed: text_len = strlen(text); } ++k; } /*****************************************************************************/ /* If text is greater than output size, print error message and truncate */ /* line. */ /*****************************************************************************/ if (strlen(text) > output_size) { for (j = strlen(text) - 1; j >= output_size; j--) { if (text[j] != ' ') { sprintf(msg_line, "Size of output line \"%s\"" " is greater than OUTPUT_SIZE", text); PRNTERR(msg_line); break; } } text[output_size] = '\0'; } fprintf(sysout, "%s\n", text); /* If there is another macro line copy it to TEXT and then process it. */ if (input_line_root != NULL) { strcpy(text, input_line_root -> line); q = input_line_root; input_line_root = input_line_root -> link; free_line(q); goto next_line; } return; } /****************************************************************************/ /* MAPMACRO: */ /****************************************************************************/ /* This procedure takes as argument a macro definition. If the name of the */ /* macro is one of the predefined names, it issues an error. Otherwise, it */ /* inserts the macro definition into the table headed by MACRO_TABLE. */ /****************************************************************************/ static void mapmacro(int def_index) { register int i, j; if (strcmp(defelmt[def_index].name, krule_text) == 0 || strcmp(defelmt[def_index].name, krule_number) == 0 || strcmp(defelmt[def_index].name, knum_rules) == 0 || strcmp(defelmt[def_index].name, krule_size) == 0 || strcmp(defelmt[def_index].name, knum_terminals) == 0 || strcmp(defelmt[def_index].name, knum_non_terminals) == 0 || strcmp(defelmt[def_index].name, knum_symbols) == 0 || strcmp(defelmt[def_index].name, kinput_file) == 0 || strcmp(defelmt[def_index].name, kcurrent_line) == 0 || strcmp(defelmt[def_index].name, knext_line) == 0) { sprintf(msg_line, "predefined macro \"%s\"" " cannot be redefined. Line %d", defelmt[def_index].name, defelmt[def_index].start_line); PRNTWNG(msg_line); return; } i = hash(defelmt[def_index].name); for (j = macro_table[i]; j != NIL; j = defelmt[j].next) { if (strcmp(defelmt[j].name, defelmt[def_index].name) == 0) { if (warnings_bit) { sprintf(msg_line, "Redefinition of macro \"%s\"" " in line %d", defelmt[def_index].name, defelmt[def_index].start_line); PRNTWNG(msg_line); break; } } } defelmt[def_index].next = macro_table[i]; macro_table[i] = def_index; return; } /*****************************************************************************/ /* FIND_MACRO: */ /*****************************************************************************/ /* FIND_MACRO takes as argument a pointer to a macro name. It searches for */ /* the macro name in the hash table based on MACRO_TABLE. If the macro name */ /* is found then the macro definition associated with it is returned. */ /* If the name is not found, then a message is printed, a new definition is */ /* entered so as to avoid more messages and NULL is returned. */ /*****************************************************************************/ static struct line_elemt *find_macro(char *name) { register int i, j; register char *ptr, *s; register struct line_elemt *q, *root = NULL; char macro_name[MAX_LINE_SIZE + 1]; s = macro_name; for (ptr = name; *ptr != '\0'; ptr++) { *(s++) = (isupper(*ptr) ? tolower(*ptr) : *ptr); } *s = '\0'; i = hash(macro_name); for (j = macro_table[i]; j != NIL; j = defelmt[j].next) { if (strcmp(macro_name, defelmt[j].name) == 0) { ptr = defelmt[j].macro; if (ptr) /* undefined macro? */ { while(*ptr != '\0') { q = alloc_line(); s = q -> line; while(*ptr != '\n') *(s++) = *(ptr++); *s = '\0'; ptr++; /* skip newline marker */ if (root == NULL) q -> link = q; /* make circular */ else { q -> link = root -> link; root -> link = q; } root = q; } } return root; } } /**********************************************************/ /* Make phony definition for macro so as to avoid future */ /* errors. */ /**********************************************************/ if (num_defs >= (int)defelmt_size) { defelmt_size += DEFELMT_INCREMENT; defelmt = (struct defelmt_type *) (defelmt == (struct defelmt_type *) NULL ? malloc(defelmt_size * sizeof(struct defelmt_type)) : realloc(defelmt, defelmt_size*sizeof(struct defelmt_type))); if (defelmt == (struct defelmt_type *) NULL) nospace(__FILE__, __LINE__); } strcpy(defelmt[num_defs].name, macro_name); defelmt[num_defs].length = 0; defelmt[num_defs].macro = NULL; defelmt[num_defs].next = macro_table[i]; macro_table[i] = num_defs; num_defs++; return NULL; } /*************************************************************************/ /* PROCESS_ALIASES: */ /*************************************************************************/ /* Aliases are placed in a separate linked list. NOTE!! After execution */ /* of this loop the hash_table is destroyed because the LINK field of */ /* alias symbols is used to construct a list of the alias symbols. */ /*************************************************************************/ static void process_aliases(void) { register int i; register struct hash_type *p, *tail; for (i = 0; i < HT_SIZE; i++) { tail = hash_table[i]; for (p = tail; p != NULL; p = tail) { tail = p -> link; if (p -> number < 0) { p -> link = alias_root; alias_root = p; } } } return; } /*****************************************************************************/ /* DISPLAY_INPUT: */ /*****************************************************************************/ /* If a listing is requested, this prints all the macros(if any), followed */ /* by the aliases(if any), followed by the terminal symbols, followed by the */ /* rules. */ /* This grammar information is printed on lines no longer than */ /* PRINT_LINE_SIZE characters long. If all the symbols in a rule cannot fit */ /* on one line, it is continued on a subsequent line beginning at the */ /* position after the equivalence symbol (::= or ->) or the middle of the */ /* print_line, whichever is smaller. If a symbol cannot fit on a line */ /* beginning at the proper offset, it is laid out on successive lines, */ /* beginning at the proper offset. */ /*****************************************************************************/ static void display_input(void) { register int j, len, offset, symb, rule_no; char line[PRINT_LINE_SIZE + 1], temp[SYMBOL_SIZE + 1]; /******************************************/ /* Print the Macro definitions, if any. */ /******************************************/ if (num_defs > 0) { PR_HEADING; fprintf(syslis, "\nDefined Symbols:\n\n"); output_line_no += 3; for (j = 0; j < num_defs; j++) { char *ptr; fill_in(line, (PRINT_LINE_SIZE - (strlen(blockb)+1)), '-'); fprintf(syslis, "\n\n%s\n%s%s\n", defelmt[j].name, blockb, line); output_line_no += 4; for (ptr = defelmt[j].macro; *ptr != '\0'; ptr++) { for (; *ptr != '\n'; ptr++) { putc(*ptr, syslis); } putc(*ptr, syslis); ENDPAGE_CHECK; } fill_in(line, (PRINT_LINE_SIZE - (strlen(blocke) + 1)), '-'); fprintf(syslis, "%s%s\n", blocke, line); ENDPAGE_CHECK; } } /**********************************/ /* Print the Aliases, if any. */ /**********************************/ if (alias_root != NULL) { struct hash_type *p; PR_HEADING; if (alias_root -> link == NULL) { fprintf(syslis, "\nAlias:\n\n"); output_line_no += 3; } else { fprintf(syslis, "\nAliases:\n\n"); output_line_no += 3; } for (p = alias_root; p != NULL; p = p -> link) { restore_symbol(temp, EXTRACT_STRING(p -> st_ptr)); len = PRINT_LINE_SIZE - 5; print_large_token(line, temp, "", len); strcat(line, " ::= "); symb = -(p -> number); restore_symbol(temp, RETRIEVE_STRING(symb)); if (strlen(line) + strlen(temp) > PRINT_LINE_SIZE) { fprintf(syslis, "%s\n", line); ENDPAGE_CHECK; len = PRINT_LINE_SIZE - 4; print_large_token(line, temp, " ", len); } else strcat(line, temp); fprintf(syslis, "%s\n", line); ENDPAGE_CHECK; } } /***************************************************************************/ /* Print the terminals. */ /* The first symbol (#1) represents the empty string. The last terminal */ /* declared by the user is followed by EOFT which may be followed by the */ /* ERROR symbol. See LPG GRAMMAR for more details. */ /***************************************************************************/ PR_HEADING; fprintf(syslis, "\nTerminals:\n\n"); output_line_no += 3; strcpy(line, " "); /* 8 spaces */ len = PRINT_LINE_SIZE - 4; for (symb = 2; symb <= num_terminals; symb++) { restore_symbol(temp, RETRIEVE_STRING(symb)); if (strlen(line) + strlen(temp) > PRINT_LINE_SIZE) { fprintf(syslis, "\n%s", line); ENDPAGE_CHECK; print_large_token(line, temp, " ", len); } else strcat(line, temp); strcat(line, BLANK); } fprintf(syslis, "\n%s", line); ENDPAGE_CHECK; /**************************/ /* Print the Rules */ /**************************/ PR_HEADING; fprintf(syslis, "\nRules:\n\n"); output_line_no += 3; for (rule_no = 0; rule_no <= num_rules; rule_no++) { register int i; symb = rules[rule_no].lhs; sprintf(line, "%-4d ", rule_no); if (symb != OMEGA) { restore_symbol(temp, RETRIEVE_STRING(symb)); if (strlen(temp) > PRINT_LINE_SIZE - 12) { strncat(line, temp, PRINT_LINE_SIZE - 12); fprintf(syslis, "\n%s", line); ENDPAGE_CHECK; strcpy(temp, temp + (PRINT_LINE_SIZE - 12)); i = PRINT_LINE_SIZE - 12; print_large_token(line, temp, " ", i); } else strcat(line, temp); if (rules[rule_no].sp) strcat(line, " -> "); else strcat(line, " ::= "); i = (PRINT_LINE_SIZE / 2) + 1; offset = MIN(strlen(line) - 1, i); len = PRINT_LINE_SIZE - offset - 1; } else { symb = rules[rule_no - 1].lhs; rules[rule_no].lhs = symb; /* update rules map */ if (rules[rule_no].sp) { restore_symbol(temp, RETRIEVE_STRING(symb)); if (strlen(temp) > PRINT_LINE_SIZE - 12) { strncat(line, temp, PRINT_LINE_SIZE - 12); fprintf(syslis, "\n%s", line); ENDPAGE_CHECK; strcpy(temp, temp + (PRINT_LINE_SIZE - 12)); i = PRINT_LINE_SIZE - 12; print_large_token(line, temp, " ", i); } else strcat(line, temp); strcat(line, " -> "); } else { for (i = 1; i <= offset - 7; i++) strcat(line, BLANK); strcat(line, "| "); } } for ENTIRE_RHS(i, rule_no) { restore_symbol(temp, RETRIEVE_STRING(rhs_sym[i])); if (strlen(temp) + strlen(line) > PRINT_LINE_SIZE - 1) { char tempbuffer1[SYMBOL_SIZE + 1]; fprintf(syslis, "\n%s", line); ENDPAGE_CHECK; strcpy(tempbuffer1, BLANK); for (j = 1; j < offset + 1; j++) strcat(tempbuffer1, BLANK); print_large_token(line, temp, tempbuffer1, len); } else strcat(line, temp); strcat(line, BLANK); } fprintf(syslis, "\n%s", line); ENDPAGE_CHECK; } return; } jikespg-1.3/src/lpgparse.h000066400000000000000000000343531167345774400156200ustar00rootroot00000000000000/* $Id: lpgparse.h,v 1.4 2001/10/10 14:53:10 ericb Exp $ */ /* This software is subject to the terms of the IBM Jikes Compiler License Agreement available at the following URL: http://ibm.com/developerworks/opensource/jikes. Copyright (C) 1983, 1999, 2001 International Business Machines Corporation and others. All Rights Reserved. You must accept the terms of that agreement to use this software. */ /*******************************************************************/ /*******************************************************************/ /** **/ /** OPTIONS DECLARATIONS **/ /** **/ /*******************************************************************/ /*******************************************************************/ /* The following static variables are used only in processing the */ /* options. */ /*******************************************************************/ #define OUTPUT_PARM_SIZE MAX_PARM_SIZE + 7 #define MAXIMUM_LA_LEVEL 15 #define STRING_BUFFER_SIZE 8192 #if defined(VM) || defined(CW) static char han[9] = "", hat[9] = "INCLUDE", ham[3] = "A", an[9] = "", at[9] = "ACTION", am[3] = "A", pn[9] = "", pt[9] = "H", pm[3] = "A", sn[9] = "", st[9] = "H", sm[3] = "A"; #endif static const char *oaction = "ACTION", *oactfile_name = "ACTFILENAME", *oactfile_name2 = "ACTFILE-NAME", *oactfile_name3 = "ACTFILE_NAME", #if defined(VM) || defined(CW) *oactfile_type = "ACTFILETYPE", *oactfile_type2 = "ACTFILE-TYPE", *oactfile_type3 = "ACTFILE_TYPE", *oactfile_mode = "ACTFILEMODE", *oactfile_mode2 = "ACTFILE-MODE", *oactfile_mode3 = "ACTFILE_MODE", #endif *oblockb = "BLOCKB", *oblocke = "BLOCKE", *obyte = "BYTE", *oconflicts = "CONFLICTS", *odebug = "DEBUG", *odefault = "DEFAULT", *odeferred = "DEFERRED", *oedit = "EDIT", /* Option no longer used ... *oerrproc3 = "ERROR-PROC", *oerrproc2 = "ERROR_PROC", *oerrproc = "ERRORPROC", */ *oerrormaps2 = "ERROR_MAPS", *oerrormaps3 = "ERROR-MAPS", *oerrormaps = "ERRORMAPS", *oescape = "ESCAPE", *ofile_prefix2 = "FILE_PREFIX", *ofile_prefix3 = "FILE-PREFIX", *ofile_prefix = "FILEPREFIX", *ofirst = "FIRST", *ofixed = "FIXED", *ofollow = "FOLLOW", *ofull = "FULL", *ogenprsr3 = "GENERATE-PARSER", *ogenprsr2 = "GENERATE_PARSER", *ogenprsr = "GENERATEPARSER", *ogotodefault2 = "GOTO_DEFAULT", *ogotodefault3 = "GOTO-DEFAULT", *ogotodefault = "GOTODEFAULT", *ohactfile_name = "HACTFILENAME", *ohactfile_name2 = "HACTFILE-NAME", *ohactfile_name3 = "HACTFILE_NAME", #if defined(VM) || defined(CW) *ohactfile_type = "HACTFILETYPE", *ohactfile_type2 = "HACTFILE-TYPE", *ohactfile_type3 = "HACTFILE_TYPE", *ohactfile_mode = "HACTFILEMODE", *ohactfile_mode2 = "HACTFILE-MODE", *ohactfile_mode3 = "HACTFILE_MODE", #endif *ohalfword2 = "HALF_WORD", *ohalfword3 = "HALF-WORD", *ohalfword = "HALFWORD", *ohblockb = "HBLOCKB", *ohblocke = "HBLOCKE", *ojikes = "JIKES", *olalr = "LALR", *olist = "LIST", *omax = "MAXIMUM", *omaximum_distance2 = "MAX_DISTANCE", *omaximum_distance3 = "MAX-DISTANCE", *omaximum_distance = "MAXDISTANCE", *omin = "MINIMUM", *ominimum_distance2 = "MIN_DISTANCE", *ominimum_distance3 = "MIN-DISTANCE", *ominimum_distance = "MINDISTANCE", *onames = "NAMES", *ontcheck2 = "NT_CHECK", *ontcheck3 = "NT-CHECK", *ontcheck = "NTCHECK", *ooptimized = "OPTIMIZED", *oormark = "ORMARK", *ooutputsize2 = "OUTPUT-SIZE", *ooutputsize3 = "OUTPUT_SIZE", *ooutputsize = "OUTPUTSIZE", *oprefix = "PREFIX", *oreadreduce2 = "READ_REDUCE", *oreadreduce3 = "READ-REDUCE", *oreadreduce = "READREDUCE", #if defined(VM) || defined(CW) *orecordformat2 = "RECORD_FORMAT", *orecordformat3 = "RECORD-FORMAT", *orecordformat = "RECORDFORMAT", #endif /* Option no longer used ... *ogettok = "SCANNER_PROC", *ogettok2 = "SCANNER-PROC", *ogettok3 = "SCANNERPROC", */ *oscopes = "SCOPES", *oshiftdefault2 = "SHIFT-DEFAULT", *oshiftdefault3 = "SHIFT_DEFAULT", *oshiftdefault = "SHIFTDEFAULT", *osingleproductions2 = "SINGLE-PRODUCTIONS", *osingleproductions3 = "SINGLE_PRODUCTIONS", *osingleproductions = "SINGLEPRODUCTIONS", *oslr = "SLR", /* Option no longer used ... *osmactn2 = "SEMANTIC-PROC", *osmactn3 = "SEMANTIC_PROC", *osmactn = "SEMANTICPROC", */ *ospace = "SPACE", *ostack_size2 = "STACK_SIZE", *ostack_size3 = "STACK-SIZE", *ostack_size = "STACKSIZE", *ostates = "STATES", *osuffix = "SUFFIX", *otable = "TABLE", *otime = "TIME", /* Option no longer used ... *otkactn3 = "TERMINAL-PROC", *otkactn2 = "TERMINAL_PROC", *otkactn = "TERMINALPROC", */ *otrace = "TRACE", *ovariable = "VARIABLE", *overbose = "VERBOSE", *owarnings = "WARNINGS", *oxref = "XREF"; /*******************************************************************/ /*******************************************************************/ /** **/ /** PARSING DECLARATIONS **/ /** **/ /*******************************************************************/ /*******************************************************************/ /* The following static variables are used only in processing the */ /* the input source. */ /*******************************************************************/ #define CTL_Z '\x1a' #undef min #define min(x, y) ((x) < (y) ? (x) : (y)) /*******************************************************************/ /* */ /* IO variables */ /* */ /* The two character pointer variables, P1 and P2, are used in */ /* processing the io buffer, INPUT_BUFFER. */ /*******************************************************************/ static char *p1, *p2, *input_buffer; static char *linestart, *bufend, *ct_ptr; static short ct = 0, /* current token & related variables */ ct_start_col = 0, ct_end_col = 0, ct_length = 0; static long ct_start_line = 0, ct_end_line = 0; static int num_acts = 0, /* macro definition & action variables */ num_defs = 0; static long defelmt_size = 0, /* macro definition & action vars */ actelmt_size = 0, rulehdr_size = 0; struct rulehdr_type /* structure to store rule in first pass */ { struct node *rhs_root; short lhs; BOOLEAN sp; }; struct defelmt_type /* structure to store location of macro def. */ { short next, length, start_column, end_column; char *macro; long start_line, end_line; char name[SYMBOL_SIZE + 1]; }; struct actelmt_type /* structure to store location of action */ { long start_line, end_line; short rule_number, start_column, end_column; BOOLEAN header_block; }; struct hash_type /* structure used to hash grammar symbols */ { struct hash_type *link; short number, name_index; int st_ptr; }; struct terminal_type /* structure used to hold token information */ { long start_line, end_line; short start_column, end_column, length, kind; char name[SYMBOL_SIZE + 1]; }; static struct rulehdr_type *rulehdr = NULL; static struct defelmt_type *defelmt = NULL; static struct actelmt_type *actelmt = NULL; static struct node *start_symbol_root; static struct hash_type **hash_table; static struct terminal_type *terminal; /******************************************/ /* The following variables hold the names */ /* of keywords and predefined macros. */ /******************************************/ static char kdefine[8] = " define", kterminals[11] = " terminals", kalias[7] = " alias", kstart[7] = " start", krules[7] = " rules", knames[7] = " names", kend[5] = " end", krule_text[11] = " rule_text", krule_number[13] = " rule_number", knum_rules[11] = " num_rules", krule_size[11] = " rule_size", knum_terminals[15] = " num_terminals", knum_non_terminals[19] = " num_non_terminals", knum_symbols[13] = " num_symbols", kinput_file[12] = " input_file", kcurrent_line[14] = " current_line", knext_line[11] = " next_line", /*****************************************************************/ /* Note that the next four keywords start with \n instead of */ /* the escape character. This is to prevent the user from */ /* declaring a grammar symbol with the same name. The */ /* end-of-line character was chosen since that character can */ /* never appear in the input without being interpreted as */ /* marking the end of an input line. When printing such a */ /* keyword, the \n is properly replaced by the escape character. */ /* See RESTORE_SYMBOL in the file LPGUTIL.C. */ /*****************************************************************/ kempty[7] = "\nempty", kerror[7] = "\nerror", keoft[5] = "\neof", kaccept[5] = "\nacc", kstart_nt[7] = " start", keolt[5] = " eol"; static struct line_elemt { struct line_elemt *link; char line[MAX_LINE_SIZE + 1]; } *line_pool_root = NULL; static int blockb_len, blocke_len, hblockb_len, hblocke_len; static int stack_top = -1; static void init_process(void); static void exit_process(void); static BOOLEAN verify(char *item); static char *translate(char *str, int len); static void options(void); static void process_options_lines(void); static int hash(char *symbl); static void insert_string(struct hash_type *q, char *string); static void assign_symbol_no(char *string_ptr, int image); static void alias_map(char *stringptr, int image); static int symbol_image(char *item); static int name_map(char *symb); static void process_grammar(void); static void scanner(void); static void token_action(void); static void error_action(void); static void accept_action(void); static void build_symno(void); static struct hash_type *alias_root = NULL; static short *macro_table; static void make_rules_map(void); static void make_names_map(void); static void process_actions(void); static void process_action_line(FILE *sysout, char *text, int line_no, int rule_no); static struct line_elemt *alloc_line(void); static void free_line(struct line_elemt *p); static void mapmacro(int def_index); static struct line_elemt *find_macro(char *name); static void process_aliases(void); static void display_input(void); jikespg-1.3/src/lpgprs.h000066400000000000000000000022641167345774400153060ustar00rootroot00000000000000/* $Id: lpgprs.h,v 1.2 1999/11/04 14:02:22 shields Exp $ */ /* This software is subject to the terms of the IBM Jikes Compiler License Agreement available at the following URL: http://www.ibm.com/research/jikes. Copyright (C) 1983, 1999, International Business Machines Corporation and others. All Rights Reserved. You must accept the terms of that agreement to use this software. */ #ifndef lpgprs_INCLUDED #define lpgprs_INCLUDED #undef SCOPE_REPAIR #undef DEFERRED_RECOVERY #undef FULL_DIAGNOSIS #define SPACE_TABLES #define original_state(state) (-base_check[state]) #define asi(state) asb[original_state(state)] #define nasi(state) nasb[original_state(state)] #define in_symbol(state) in_symb[original_state(state)] extern const unsigned char rhs[]; extern const unsigned short lhs[]; extern const unsigned short *base_action; extern const unsigned char term_check[]; extern const unsigned short term_action[]; #define nt_action(state, sym) base_action[state + sym] #define t_action(state, sym, next_tok) \ term_action[term_check[base_action[state]+sym] == sym ? \ base_action[state] + sym : base_action[state]] #endif /* lpgprs_INCLUDED */ jikespg-1.3/src/lpgsym.h000066400000000000000000000016511167345774400153110ustar00rootroot00000000000000/* $Id: lpgsym.h,v 1.2 1999/11/04 14:02:22 shields Exp $ */ /* This software is subject to the terms of the IBM Jikes Compiler License Agreement available at the following URL: http://www.ibm.com/research/jikes. Copyright (C) 1983, 1999, International Business Machines Corporation and others. All Rights Reserved. You must accept the terms of that agreement to use this software. */ #ifndef lpgsym_INCLUDED #define lpgsym_INCLUDED enum { DEFINE_KEY_TK = 5, TERMINALS_KEY_TK = 9, ALIAS_KEY_TK = 10, START_KEY_TK = 11, RULES_KEY_TK = 12, NAMES_KEY_TK = 16, END_KEY_TK = 18, EQUIVALENCE_TK = 1, ARROW_TK = 2, OR_TK = 6, EMPTY_SYMBOL_TK = 7, ERROR_SYMBOL_TK = 8, EOL_SYMBOL_TK = 13, EOF_SYMBOL_TK = 14, MACRO_NAME_TK = 15, SYMBOL_TK = 3, BLOCK_TK = 4, HBLOCK_TK = 17, EOF_TK = 19 }; #endif /* lpgsym_INCLUDED */ jikespg-1.3/src/lpgutil.c000066400000000000000000001133131167345774400154500ustar00rootroot00000000000000/* $Id: lpgutil.c,v 1.2 1999/11/04 14:02:22 shields Exp $ */ /* This software is subject to the terms of the IBM Jikes Compiler License Agreement available at the following URL: http://www.ibm.com/research/jikes. Copyright (C) 1983, 1999, International Business Machines Corporation and others. All Rights Reserved. You must accept the terms of that agreement to use this software. */ static char hostfile[] = __FILE__; #include #include #include #include "common.h" #include "header.h" /**********************************************************************/ /* The following are global variables and constants used to manage a */ /* pool of temporary space. Externally, the user invokes the function */ /* "talloc" just as he would invoke "malloc". */ /**********************************************************************/ #ifdef DOS #define LOG_BLKSIZE 12 #else #define LOG_BLKSIZE 14 #endif #define BLKSIZE (1 << LOG_BLKSIZE) #define BASE_INCREMENT 64 typedef long cell; static cell **temp_base = NULL; static long temp_top = 0, temp_size = 0, temp_base_size = 0; /**********************************************************************/ /* ALLOCATE_MORE_SPACE: */ /**********************************************************************/ /* This procedure obtains more TEMPORARY space. */ /**********************************************************************/ static BOOLEAN allocate_more_space(cell ***base, long *size, long *base_size) { int k; /**********************************************************************/ /* The variable size always indicates the maximum number of cells */ /* that has been allocated and reserved for the storage pool. */ /* Initially, size should be set to 0 to indicate that no space has */ /* yet been allocated. The pool of cells available is divided into */ /* segments of size 2**LOG_BLKSIZE each and each segment is pointer */ /* to by a slot in the array base. */ /* */ /* By dividing "size" by the size of the segment we obtain the */ /* index for the next segment in base. If base is already full, it is */ /* reallocated. */ /* */ /**********************************************************************/ k = (*size) >> LOG_BLKSIZE; /* which segment? */ if (k == (*base_size)) /* base overflow? reallocate */ { register int i = (*base_size); (*base_size) += BASE_INCREMENT; (*base) = (cell **) ((*base) == NULL ? malloc(sizeof(cell *) * (*base_size)) : realloc((*base), sizeof(cell *) * (*base_size))); if ((*base) == (cell **) NULL) return FALSE; for (i = i; i < (*base_size); i++) (*base)[i] = NULL; } /**********************************************************************/ /* If the Ast slot "k" does not already contain a segment, We try to */ /* allocate one and place its address in (*base)[k]. */ /* If the allocation was not successful, we terminate; */ /* otherwise, we adjust the address in (*base)[k] so as to allow us */ /* to index the segment directly, instead of having to perform a */ /* subtraction for each reference. Finally, we update size. */ /* */ /* Finally, we set the block to zeros. */ /**********************************************************************/ if ((*base)[k] == NULL) { (*base)[k] = (cell *) malloc(sizeof(cell) << LOG_BLKSIZE); if ((*base)[k] == (cell *) NULL) return FALSE; (*base)[k] -= (*size); } memset((void *)((*base)[k] + (*size)), 0, sizeof(cell) << LOG_BLKSIZE); (*size) += BLKSIZE; return TRUE; } /**********************************************************************/ /* RESET_TEMPORARY_SPACE: */ /**********************************************************************/ /* This procedure resets the temporary space already allocated so */ /* that it can be reused before new blocks are allocated. */ /**********************************************************************/ void reset_temporary_space(void) { temp_top = 0; /* index of next usable elemt */ temp_size = 0; return; } /**********************************************************************/ /* FREE_TEMPORARY_SPACE: */ /**********************************************************************/ /* This procedure frees all allocated temporary space. */ /**********************************************************************/ void free_temporary_space(void) { int k; for (k = 0; k < temp_base_size && temp_base[k] != NULL; k++) { temp_base[k] += (k * BLKSIZE); ffree(temp_base[k]); } if (temp_base != NULL) { ffree(temp_base); temp_base = NULL; } temp_base_size = 0; temp_top = 0; temp_size = 0; return; } /**********************************************************************/ /* TALLOC: */ /**********************************************************************/ /* talloc allocates an object of size "size" in temporary space and */ /* returns a pointer to it. */ /**********************************************************************/ void *talloc(long size) { long i; i = temp_top; temp_top += ((size + sizeof(cell) - 1) / sizeof(cell)); if (temp_top > temp_size) { i = temp_size; temp_top = temp_size + ((size + sizeof(cell) - 1) / sizeof(cell)); if (! allocate_more_space(&temp_base, &temp_size, &temp_base_size)) { temp_top = temp_size; return NULL; } } return ((void *) &(temp_base[i >> LOG_BLKSIZE] [i])); } /**********************************************************************/ /* TEMPORARY_SPACE_ALLOCATED: */ /**********************************************************************/ /* Return the total size of temporary space allocated. */ /**********************************************************************/ long temporary_space_allocated(void) { return ((temp_base_size * sizeof(cell **)) + (temp_size * sizeof(cell))); } /**********************************************************************/ /* TEMPORARY_SPACE_USED: */ /**********************************************************************/ /* Return the total size of temporary space used. */ /**********************************************************************/ long temporary_space_used(void) { return (((temp_size >> LOG_BLKSIZE) * sizeof(cell **)) + (temp_top * sizeof(cell))); } /**********************************************************************/ /* */ /* The following are global variables and constants used to manage a */ /* pool of global space. Externally, the user invokes one of the */ /* functions: */ /* */ /* ALLOCATE_NODE */ /* ALLOCATE_GOTO_MAP */ /* ALLOCATE_SHIFT_MAP */ /* ALLOCATE_REDUCE_MAP */ /* */ /* These functions allocate space from the global pool in the same */ /* using the function "galloc" below. */ /* */ /**********************************************************************/ static cell **global_base = NULL; static long global_top = 0, global_size = 0, global_base_size = 0; static struct node *node_pool = NULL; /**********************************************************************/ /* PROCESS_GLOBAL_WASTE: */ /**********************************************************************/ /* This function is invoked when the space left in a segment is not */ /* enough for GALLOC to allocate a requested object. Rather than */ /* waste the space, as many NODE structures as possible are allocated */ /* in that space and stacked up in the NODE_POOL list. */ /**********************************************************************/ static void process_global_waste(long top) { struct node *p; long i; while (TRUE) { i = top; top += ((sizeof(struct node) + sizeof(cell) - 1) / sizeof(cell)); if (top > global_size) break; p = (struct node *) &(global_base[i >> LOG_BLKSIZE] [i]); p -> next = node_pool; node_pool = p; } return; } /**********************************************************************/ /* GALLOC: */ /**********************************************************************/ /* galloc allocates an object of size "size" in global space and */ /* returns a pointer to it. It is analoguous to "talloc", but it */ /* is a local (static) routine that is only invoked in this file by */ /* other more specialized routines. */ /**********************************************************************/ static void *galloc(long size) { long i; i = global_top; global_top += ((size + sizeof(cell) - 1) / sizeof(cell)); if (global_top > global_size) { process_global_waste(i); i = global_size; global_top = global_size + ((size + sizeof(cell) - 1) / sizeof(cell)); if (! allocate_more_space(&global_base, &global_size, &global_base_size)) { global_top = global_size; return NULL; } } return ((void *) &(global_base[i >> LOG_BLKSIZE] [i])); } /****************************************************************************/ /* ALLOCATE_NODE: */ /****************************************************************************/ /* This function allocates a node structure and returns a pointer to it. */ /* it there are nodes in the free pool, one of them is returned. Otherwise, */ /* a new node is allocated from the global storage pool. */ /****************************************************************************/ struct node *allocate_node(char *file, long line) { struct node *p; p = node_pool; if (p != NULL) /* is free list not empty? */ node_pool = p -> next; else { p = (struct node *) galloc(sizeof(struct node)); if (p == NULL) nospace(file, line); } return(p); } /****************************************************************************/ /* FREE_NODES: */ /****************************************************************************/ /* This function frees a linked list of nodes by adding them to the free */ /* list. Head points to head of linked list and tail to the end. */ /****************************************************************************/ void free_nodes(struct node *head, struct node *tail) { tail -> next = node_pool; node_pool = head; return; } /****************************************************************************/ /* ALLOCATE_GOTO_MAP: */ /****************************************************************************/ /* This function allocates space for a goto map with "size" elements, */ /* initializes and returns a goto header for that map. NOTE that after the */ /* map is successfully allocated, it is offset by one element. This is */ /* to allow the array in question to be indexed from 1..size instead of */ /* 0..(size-1). */ /****************************************************************************/ struct goto_header_type allocate_goto_map(int size, char *file, long line) { struct goto_header_type go_to; go_to.size = size; go_to.map = (struct goto_type *) galloc(size * sizeof(struct goto_type)); if (go_to.map == NULL) nospace(file, line); go_to.map--; /* map will be indexed in range 1..size */ return(go_to); } /****************************************************************************/ /* ALLOCATE_SHIFT_MAP: */ /****************************************************************************/ /* This function allocates space for a shift map with "size" elements, */ /* initializes and returns a shift header for that map. NOTE that after the */ /* map is successfully allocated, it is offset by one element. This is */ /* to allow the array in question to be indexed from 1..size instead of */ /* 0..(size-1). */ /****************************************************************************/ struct shift_header_type allocate_shift_map(int size, char *file, long line) { struct shift_header_type sh; sh.size = size; sh.map = (struct shift_type *) galloc(size * sizeof(struct shift_type)); if (sh.map == NULL) nospace(file, line); sh.map--; /* map will be indexed in range 1..size */ return(sh); } /****************************************************************************/ /* ALLOCATE_REDUCE_MAP: */ /****************************************************************************/ /* This function allocates space for a REDUCE map with "size"+1 elements, */ /* initializes and returns a REDUCE header for that map. The 0th element of */ /* a reduce map is used for the default reduction. */ /****************************************************************************/ struct reduce_header_type allocate_reduce_map(int size, char *file, long line) { struct reduce_header_type red; red.map = (struct reduce_type *) galloc((size + 1) * sizeof(struct reduce_type)); if (red.map == NULL) nospace(file, line); red.size = size; return(red); } /**********************************************************************/ /* GLOBAL_SPACE_ALLOCATED: */ /**********************************************************************/ /* Return the total size of global space allocated. */ /**********************************************************************/ long global_space_allocated(void) { return ((global_base_size * sizeof(cell **)) + (global_size * sizeof(cell))); } /**********************************************************************/ /* GLOBAL_SPACE_USED: */ /**********************************************************************/ /* Return the total size of global space used. */ /**********************************************************************/ long global_space_used(void) { return (((global_size >> LOG_BLKSIZE) * sizeof(cell **)) + (global_top * sizeof(cell))); } /****************************************************************************/ /* ALLOCATE_INT_ARRAY: */ /****************************************************************************/ /* This function allocates an array of size "size" of int integers. */ /****************************************************************************/ int *allocate_int_array(long size, char *file, long line) { int *p; p = (int *) calloc(size, sizeof(int)); if (p == (int *) NULL) nospace(file, line); return(&p[0]); } /****************************************************************************/ /* ALLOCATE_SHORT_ARRAY: */ /****************************************************************************/ /* This function allocates an array of size "size" of short integers. */ /****************************************************************************/ short *allocate_short_array(long size, char *file, long line) { short *p; p = (short *) calloc(size, sizeof(short)); if (p == (short *) NULL) nospace(file, line); return(&p[0]); } /****************************************************************************/ /* ALLOCATE_BOOLEAN_ARRAY: */ /****************************************************************************/ /* This function allocates an array of size "size" of type boolean. */ /****************************************************************************/ BOOLEAN *allocate_boolean_array(long size, char *file, long line) { BOOLEAN *p; p = (BOOLEAN *) calloc(size, sizeof(BOOLEAN)); if (p == (BOOLEAN *) 0) nospace(file, line); return(&p[0]); } /*****************************************************************************/ /* FILL_IN: */ /*****************************************************************************/ /* FILL_IN is a subroutine that pads a buffer, STRING, with CHARACTER a */ /* certain AMOUNT of times. */ /*****************************************************************************/ void fill_in(char string[], int amount, char character) { int i; for (i = 0; i <= amount; i++) string[i] = character; string[i] = '\0'; return; } /*****************************************************************************/ /* QCKSRT: */ /*****************************************************************************/ /* QCKSRT is a quicksort algorithm that takes as arguments an array of */ /* integers, two numbers L and H that indicate the lower and upper bound */ /* positions in ARRAY to be sorted. */ /*****************************************************************************/ static void qcksrt(short array[], int l, int h) { int lower, upper, top, i, j, pivot, lostack[14], /* A stack of size 14 can sort an array of up to */ histack[14]; /* 2 ** 15 - 1 elements */ top = 1; lostack[top] = l; histack[top] = h; while (top != 0) { lower = lostack[top]; upper = histack[top--]; while (upper > lower) { i = lower; pivot = array[lower]; for (j = lower + 1; j <= upper; j++) { if (array[j] < pivot) { array[i] = array[j]; i++; array[j] = array[i]; } } array[i] = pivot; top++; if (i - lower < upper - i) { lostack[top] = i + 1; histack[top] = upper; upper = i - 1; } else { histack[top] = i - 1; lostack[top] = lower; lower = i + 1; } } } return; } /*****************************************************************************/ /* NUMBER_LEN: */ /*****************************************************************************/ /* NUMBER_LEN takes a state number and returns the number of digits in that */ /* number. */ /*****************************************************************************/ int number_len(int state_no) { int num = 0; do { state_no /= 10; num++; } while (state_no != 0); return num; } /*************************************************************************/ /* RESTORE_SYMBOL: */ /*************************************************************************/ /* This procedure takes two character strings as arguments: IN and OUT. */ /* IN identifies a grammar symbol or name that is checked as to whether */ /* or not it needs to be quoted. If so, the necessary quotes are added */ /* as IN is copied into the space identified by OUT. */ /* NOTE that it is assumed that IN and OUT do not overlap each other. */ /*************************************************************************/ void restore_symbol(char *out, char *in) { int len; len = strlen(in); if (len > 0) { if ((len == 1 && in[0] == ormark) || (in[0] == escape) || (in[0] == '\'') || (in[len - 1] == '\'') || (strchr(in, ' ') != NULL && (in[0] != '<' || in[len - 1] != '>'))) { *(out++) = '\''; while(*in != '\0') { if (*in == '\'') *(out++) = *in; *(out++) = *(in++); } *(out++) = '\''; *out = '\0'; return; } } strcpy(out, in); if (out[0] == '\n') /* one of the special grammar symbols? */ out[0] = escape; return; } /*****************************************************************************/ /* PRINT_LARGE_TOKEN: */ /*****************************************************************************/ /* PRINT_LARGE_TOKEN generates code to print a token that may exceed the */ /* limit of its field. The argument are LINE which is the symbol a varying */ /* length character string, TOKEN which is the symbol to be printed, INDENT */ /* which is a character string to be used as an initial prefix to indent the */ /* output line, and LEN which indicates the maximum number of characters that*/ /* can be printed on a given line. At the end of this process, LINE will */ /* have the value of the remaining substring that can fit on the output line.*/ /* If a TOKEN is too large to be indented in a line, but not too large for */ /* the whole line, we forget the indentation, and printed it. Otherwise, it */ /* is "chapped up" and printed in pieces that are each indented. */ /*****************************************************************************/ void print_large_token(char *line, char *token, char *indent, int len) { int toklen; char temp[SYMBOL_SIZE + 1]; toklen = strlen(token); if (toklen > len && toklen <= PRINT_LINE_SIZE-1) { fprintf(syslis, "\n%s", token); ENDPAGE_CHECK; token = ""; strcpy(line,indent); } else { for (; toklen > len; toklen = strlen(temp)) { memcpy(temp, token, len); temp[len] = '\0'; fprintf(syslis, "\n%s",temp); ENDPAGE_CHECK; strcpy(temp, token+len + 1); token = temp; } strcpy(line,indent); strcat(line,token); } return; } /*****************************************************************************/ /* PRINT_ITEM: */ /*****************************************************************************/ /* PRINT_ITEM takes as parameter an ITEM_NO which it prints. */ /*****************************************************************************/ void print_item(int item_no) { int rule_no, symbol, len, offset, i, k; char tempstr[PRINT_LINE_SIZE + 1], line[PRINT_LINE_SIZE + 1], tok[SYMBOL_SIZE + 1]; /*********************************************************************/ /* We first print the left hand side of the rule, leaving at least */ /* 5 spaces in the output line to accomodate the equivalence symbol */ /* "::=" surrounded by blanks on both sides. Then, we print all the */ /* terminal symbols in the right hand side up to but not including */ /* the dot symbol. */ /*********************************************************************/ rule_no = item_table[item_no].rule_number; symbol = rules[rule_no].lhs; restore_symbol(tok, RETRIEVE_STRING(symbol)); len = PRINT_LINE_SIZE - 5; print_large_token(line, tok, "", len); strcat(line, " ::= "); i = (PRINT_LINE_SIZE / 2) - 1; offset = MIN(strlen(line)-1, i); len = PRINT_LINE_SIZE - (offset + 4); i = rules[rule_no].rhs; /* symbols before dot */ k = ((rules[rule_no].rhs + item_table[item_no].dot) - 1); for (; i <= k; i++) { symbol = rhs_sym[i]; restore_symbol(tok, RETRIEVE_STRING(symbol)); if (strlen(tok) + strlen(line) > PRINT_LINE_SIZE - 4) { fprintf(syslis,"\n%s", line); ENDPAGE_CHECK; fill_in(tempstr, offset, SPACE); print_large_token(line, tok, tempstr, len); } else strcat(line, tok); strcat(line, BLANK); } /*********************************************************************/ /* We now add a DOT "." to the output line and print the remaining */ /* symbols in the right hand side. If ITEM_NO is a complete item, */ /* we also print the rule number. */ /*********************************************************************/ if (item_table[item_no].dot == 0 || item_table[item_no].symbol == empty) strcpy(tok, "."); else strcpy(tok, " ."); strcat(line, tok); len = PRINT_LINE_SIZE - (offset + 1); for (i = rules[rule_no].rhs + item_table[item_no].dot;/* symbols after dot*/ i <= rules[rule_no + 1].rhs - 1; i++) { symbol = rhs_sym[i]; restore_symbol(tok, RETRIEVE_STRING(symbol)); if (strlen(tok) + strlen(line) > PRINT_LINE_SIZE -1) { fprintf(syslis, "\n%s", line); ENDPAGE_CHECK; fill_in(tempstr, offset, SPACE); print_large_token(line, tok, tempstr, len); } else strcat(line, tok); strcat(line, BLANK); } if (item_table[item_no].symbol == empty) /* complete item */ { sprintf(tok, " (%d)", rule_no); if (strlen(tok) + strlen(line) > PRINT_LINE_SIZE - 1) { fprintf(syslis, "\n%s", line); ENDPAGE_CHECK; fill_in(line,offset, SPACE); } strcat(line,tok); } fprintf(syslis, "\n%s", line); ENDPAGE_CHECK; return; } /*****************************************************************************/ /* PRINT_STATE: */ /*****************************************************************************/ /* PRINT_STATE prints all the items in a state. NOTE that when single */ /* productions are eliminated, certain items that were added in a state by */ /* CLOSURE, will no longer show up in the output. Example: If we have the */ /* item [A ::= .B] in a state, and the GOTO_REDUCE generated on B has been */ /* replaced by say the GOTO or GOTO_REDUCE of A, the item above can no longer*/ /* be retrieved, since transitions in a given state are reconstructed from */ /* the KERNEL and ADEQUATE items of the actions in the GOTO and SHIFT maps. */ /*****************************************************************************/ void print_state(int state_no) { struct shift_header_type sh; struct goto_header_type go_to; short *item_list; int kernel_size, i, n, item_no, next_state; BOOLEAN end_node, *state_seen, *item_seen; struct node *q; char buffer[PRINT_LINE_SIZE + 1], line[PRINT_LINE_SIZE + 1]; /*********************************************************************/ /* ITEM_SEEN is used to construct sets of items, to help avoid */ /* adding duplicates in a list. Duplicates can occur because an */ /* item from the kernel set will either be shifted on if it is not a */ /* complete item, or it will be a member of the Complete_items set. */ /* Duplicates can also occur because of the elimination of single */ /* productions. */ /*********************************************************************/ state_seen = Allocate_boolean_array(max_la_state + 1); item_seen = Allocate_boolean_array(num_items + 1); item_list = Allocate_short_array(num_items + 1); /* INITIALIZATION -----------------------------------------------------------*/ for ALL_STATES(i) state_seen[i] = FALSE; for ALL_ITEMS(i) item_seen[i] = FALSE; kernel_size = 0; /* END OF INITIALIZATION ----------------------------------------------------*/ i = number_len(state_no) + 8; /* 8 = length("STATE") + 2 spaces + newline*/ fill_in(buffer, (PRINT_LINE_SIZE - i) ,'-'); fprintf(syslis, "\n\n\nSTATE %d %s",state_no, buffer); output_line_no +=3; /*********************************************************************/ /* Print the set of states that have transitions to STATE_NO. */ /*********************************************************************/ n = 0; strcpy(line, "( "); for (end_node = ((q = in_stat[state_no]) == NULL); ! end_node; end_node = (q == in_stat[state_no])) {/* copy list of IN_STAT into array */ q = q -> next; if (! state_seen[q -> value]) { state_seen[q -> value] = TRUE; if (strlen(line) + number_len(q -> value) > PRINT_LINE_SIZE-2) { fprintf(syslis,"\n%s",line); ENDPAGE_CHECK; strcpy(line, " "); } if (q -> value != 0) { sprintf(buffer, "%d ", q -> value); strcat(line, buffer); } } } strcat(line, ")"); fprintf(syslis,"\n%s\n", line); output_line_no++; ENDPAGE_CHECK; /*********************************************************************/ /* Add the set of kernel items to the array ITEM_LIST, and mark all */ /* items seen to avoid duplicates. */ /*********************************************************************/ for (q = statset[state_no].kernel_items; q != NULL; q = q -> next) { kernel_size++; item_no = q -> value; item_list[kernel_size] = item_no; /* add to array */ item_seen[item_no] = TRUE; /* Mark as "seen" */ } /*********************************************************************/ /* Add the Complete Items to the array ITEM_LIST, and mark used. */ /*********************************************************************/ n = kernel_size; for (q = statset[state_no].complete_items; q != NULL; q = q -> next) { item_no = q -> value; if (! item_seen[item_no]) { item_seen[item_no] = TRUE; /* Mark as "seen" */ item_list[++n] = item_no; } } /*********************************************************************/ /* Iterate over the shift map. Shift-Reduce actions are identified */ /* by a negative integer that indicates the rule in question , and */ /* the associated item can be retrieved by indexing the array */ /* ADEQUATE_ITEMS at the location of the rule. For shift-actions, we*/ /* simply take the predecessor-items of all the items in the kernel */ /* of the following state. */ /* If the shift-action is a look-ahead shift, we check to see if the */ /* look-ahead state contains shift actions, and retrieve the next */ /* state from one of those shift actions. */ /*********************************************************************/ sh = shift[statset[state_no].shift_number]; for (i = 1; i <= sh.size; i++) { next_state = SHIFT_ACTION(sh, i); while (next_state > (int) num_states) { struct shift_header_type next_sh; next_sh = shift[lastats[next_state].shift_number]; if (next_sh.size > 0) next_state = SHIFT_ACTION(next_sh, 1); else next_state = 0; } if (next_state == 0) q = NULL; else if (next_state < 0) q = adequate_item[-next_state]; else { q = statset[next_state].kernel_items; if (q == NULL) /* single production state? */ q = statset[next_state].complete_items; } for (; q != NULL; q = q -> next) { item_no = q -> value - 1; if (! item_seen[item_no]) { item_seen[item_no] = TRUE; item_list[++n] = item_no; } } } /*********************************************************************/ /* GOTOS and GOTO-REDUCES are analogous to SHIFTS and SHIFT-REDUCES. */ /*********************************************************************/ go_to = statset[state_no].go_to; for (i = 1; i <= go_to.size; i++) { if (GOTO_ACTION(go_to, i) > 0) { q = statset[GOTO_ACTION(go_to, i)].kernel_items; if (q == NULL) /* single production state? */ q = statset[GOTO_ACTION(go_to, i)].complete_items; } else q = adequate_item[- GOTO_ACTION(go_to, i)]; for (; q != NULL; q = q -> next) { item_no = q -> value - 1; if (! item_seen[item_no]) { item_seen[item_no] = TRUE; item_list[++n] = item_no; } } } /*********************************************************************/ /* Print the Kernel items. If there are any closure items, skip a */ /* line, sort then, then print them. The kernel items are in sorted */ /* order. */ /*********************************************************************/ for (item_no = 1; item_no <= kernel_size; item_no++) print_item(item_list[item_no]); if (kernel_size < n) { fprintf(syslis, "\n"); ENDPAGE_CHECK; qcksrt(item_list, kernel_size + 1, n); for (item_no = kernel_size + 1; item_no <= n; item_no++) print_item(item_list[item_no]); } ffree(item_list); ffree(item_seen); ffree(state_seen); return; } /*****************************************************************************/ /* NOSPACE: */ /*****************************************************************************/ /* This procedure is invoked when a call to MALLOC, CALLOC or REALLOC fails. */ /*****************************************************************************/ void nospace(char *file_name, long line_number) { fprintf(stderr, "*** Cannot allocate space ... LPG terminated in " "file %s at line %d\n", file_name, line_number); exit(12); } /************************************************************************/ /* STRUPR: */ /************************************************************************/ /* StrUpr and StrLwr. */ /* These routines set all characters in a string to upper case and lower*/ /* case (respectively.) These are library routines in DOS, but */ /* are defined here for the 370 compiler. */ /************************************************************************/ char *strupr(char *string) { char *s; /*********************************************************************/ /* While not at end of string, change all lower case to upper case. */ /*********************************************************************/ for (s = string; *s != '\0'; s++) *s = (islower((int) *s) ? toupper((int) *s) : *s); return string; } /************************************************************************/ /* STRLWR: */ /************************************************************************/ char *strlwr(char *string) { char *s; /*********************************************************************/ /* While not at end of string, change all upper case to lower case. */ /*********************************************************************/ for (s = string; *s != '\0'; s++) *s = (isupper((int) *s) ? tolower((int) *s) : *s); return string; } jikespg-1.3/src/main.c000066400000000000000000000520721167345774400147200ustar00rootroot00000000000000/* $Id: main.c,v 1.2 1999/11/04 14:02:22 shields Exp $ */ /* This software is subject to the terms of the IBM Jikes Compiler License Agreement available at the following URL: http://www.ibm.com/research/jikes. Copyright (C) 1983, 1999, International Business Machines Corporation and others. All Rights Reserved. You must accept the terms of that agreement to use this software. */ static char hostfile[] = __FILE__; #include #include "common.h" #include "header.h" static void print_opts(void); void process_input(void); void mkfirst(void); void mkstats(void); void mkrdcts(void); void ptstats(void); void process_tables(void); /*********************************************************************/ /* Jikes PG is a parser generator capable of generating LALR(k) and */ /* SLR(1) tables. It is organized as a main routine: MAIN, which */ /* invokes five other major subroutines which are: */ /* */ /* 1) PROCESS_INPUT - inputs and structures the grammar. */ /* 2) MKFIRST - builds basic maps such as FIRST, */ /* FOLLOW, CLOSURE, CLITEMS, ITEM_TABLE, */ /* ADEQUATE_ITEMS. */ /* 3) MKSTATS - constructs the LR(0) automaton. */ /* 4) MKRDCTS - constructs reduction map. */ /* 5) One of the following three procedures: */ /* a) CMPRSPA - Space Table generation */ /* b) CMPRTIM - Time Table generation */ /* c) BASETAB - Write out Base Table */ /* */ /* The following files are used: */ /* */ /* 1) SYSGRM - Input file containing grammar */ /* 2) SYSLIS - Output file used for listings, statistics*/ /* and diagnostics. */ /* 3) SYSACT - Output file used for semantic actions. */ /* 4) SYSTAB - Output file used for Parsing tables. */ /* */ /*********************************************************************/ /****************************************************************************/ /****************************************************************************/ /* MAIN PROGRAM MAIN: */ /****************************************************************************/ /****************************************************************************/ int main(int argc, char *argv[]) { int i, op_start, j = 0; char *dot, *slash, tmpbuf[20]; /*********************************************************************/ /* If only "jikespg" or "jikespg ?*" is typed, we display the help */ /* screen. */ /* */ /* NOTE that because of some bug (feature?) in AIX, when two or more */ /* consecutive "?" is passed as argument to a program, the behaviour */ /* of the system becomes unpredictable. 1/4/94 */ /* You may test this by invoking the "echo" program with "???". */ /*********************************************************************/ if (argc == 1 || argv[1][0] == '?') { print_opts(); return 4; } /**********************************************************************/ /* If options are passed to the program, copy them into "parm". */ /**********************************************************************/ #if defined(C370) || defined(CW) if (argc > 1) { char *p; for (i = 1; i < argc; i++) { /* Search for '(' which would indicate that options are listed. */ if ((p = strchr(argv[i], '(')) != NULL) break; /* if found then exit from loop */ } op_start = i; if (i != argc) /* if there are options */ { if (*(p+1) != '\0') /* first option is concatenated to '(' ? */ strcpy(parm, p+1); /* Copy from next char till end */ else if (i != argc - 1) strcpy(parm, argv[++i]); /* Next argument is first option */ while (i < argc - 1) /* Process remaining options */ { strcat(parm, BLANK); strcat(parm, argv[++i]); } if (p != argv[op_start]) /* is '(' concatenated to some string?*/ { op_start++; *p = '\0'; } } } #else if (argc > 2) { parm[0] = '\0'; while (j < argc - 2) { if (*(argv[++j]) == '-') strcat(parm, argv[j]+1); else { strcat(parm, argv[j]); printf("***WARNING: Option \"%s\" is missing preceding '-'.\n", argv[j]); } strcat(parm, BLANK); } } #endif /****************************************************************************/ /* Create file names for output files */ /****************************************************************************/ #if defined(C370) || defined(CW) strupr(argv[1]); #if defined(MVS) if (argv[1][0] == '\'') { int n; strcpy(grm_file, argv[1]); dot = strchr(grm_file, '.'); j = 1+(int)(dot-grm_file); n = strlen(grm_file) - 1; for (i = j; i < n; i++) file_prefix[i-j] = grm_file[i]; i = i - j; file_prefix[i] = '\0'; sprintf(lis_file, "%s.LISTING", file_prefix); sprintf(tab_file, "%s.TABLE", file_prefix); file_prefix[i] = '.'; file_prefix[i+1] = '\0'; } else { sprintf(grm_file, "%s.GRAMMAR", argv[1]); sprintf(lis_file, "%s.LISTING", argv[1]); sprintf(tab_file, "%s.TABLE", argv[1]); strcpy(file_prefix, argv[1]); } #else switch(op_start - 1) { case 1: sprintf(grm_file, "%s.GRAMMAR.*", argv[1]); sprintf(lis_file, "%s.LISTING.A", argv[1]); sprintf(tab_file, "%s.TABLE.A", argv[1]); break; case 2: sprintf(grm_file, "%s.%s.*", argv[1], strupr(argv[2])); sprintf(lis_file, "%s.LISTING.A", argv[1]); sprintf(tab_file, "%s.TABLE.A", argv[1]); break; case 3: strupr(argv[2]); strupr(argv[3]); sprintf(grm_file, "%s.%s.%s", argv[1], argv[2], argv[3]); sprintf(lis_file, "%s.LISTING.%s", argv[1], argv[3]); sprintf(tab_file, "%s.TABLE.%s", argv[1], argv[3]); break; default: break; } #endif i = strlen(argv[1]); for (i = MIN(i, 5) - 1; i >= 0; i--) file_prefix[i] = argv[1][i]; file_prefix[i] = '\0'; strupr(file_prefix); #else strcpy(grm_file, argv[argc - 1]); #if defined(DOS) || defined(OS2) slash = strrchr(grm_file, '\\'); #else slash = strrchr(grm_file, '/'); #endif if (slash != NULL) strcpy(tmpbuf, slash + 1); else strcpy(tmpbuf, grm_file); dot = strrchr(tmpbuf, '.'); if (dot == NULL) /* if filename has no extension, copy it. */ { strcpy(lis_file, tmpbuf); strcpy(tab_file, tmpbuf); for (i = 0; i < 5; i++) file_prefix[i] = tmpbuf[i]; file_prefix[i] = '\0'; } else /* if file name contains an extension copy up to the dot */ { for (i = 0; i < 5 && tmpbuf + i != dot; i++) file_prefix[i] = tmpbuf[i]; file_prefix[i] = '\0'; memcpy(lis_file, tmpbuf, dot - tmpbuf); memcpy(tab_file, tmpbuf, dot - tmpbuf); lis_file[dot - tmpbuf] = '\0'; tab_file[dot - tmpbuf] = '\0'; } strcat(lis_file, ".l"); /* add .l extension for listing file */ strcat(tab_file, ".t"); /* add .t extension for table file */ #endif process_input(); /****************************************************************************/ /* If the user only wanted to edit his grammar, we quit the program. */ /****************************************************************************/ if (edit_bit) { if (first_bit || follow_bit || xref_bit) mkfirst(); PR_HEADING; sprintf(msg_line, "\nNumber of Terminals: %d", num_terminals - 1); /*-1 for %empty */ PRNT(msg_line); sprintf(msg_line, "Number of Nonterminals: %d", num_non_terminals - 1); /* -1 for %ACC */ PRNT(msg_line); sprintf(msg_line, "Number of Productions: %d", num_rules + 1); PRNT(msg_line); if (single_productions_bit) { sprintf(msg_line, "Number of Single Productions: %d", num_single_productions); PRNT(msg_line); } sprintf(msg_line, "Number of Items: %d", num_items); PRNT(msg_line); fclose(syslis); /* close listing file */ return 0; } mkfirst(); /* Construct basic maps */ mkstats(); /* Build State Automaton */ mkrdcts(); /* Build Reduce map, and detect conflicts if any */ /****************************************************************************/ /* Print more relevant statistics. */ /****************************************************************************/ PR_HEADING; sprintf(msg_line, "\nNumber of Terminals: %d", num_terminals - 1); PRNT(msg_line); sprintf(msg_line, "Number of Nonterminals: %d", num_non_terminals - 1); PRNT(msg_line); sprintf(msg_line, "Number of Productions: %d", num_rules + 1); PRNT(msg_line); if (single_productions_bit) { sprintf(msg_line, "Number of Single Productions: %d", num_single_productions); PRNT(msg_line); } sprintf(msg_line, "Number of Items: %d", num_items); PRNT(msg_line); if (scopes_bit) { sprintf(msg_line, "Number of Scopes: %d", num_scopes); PRNT(msg_line); } sprintf(msg_line, "Number of States: %d", num_states); PRNT(msg_line); if (max_la_state > num_states) { sprintf(msg_line, "Number of look-ahead states: %d", max_la_state - num_states); PRNT(msg_line); } sprintf(msg_line, "Number of Shift actions: %d", num_shifts); PRNT(msg_line); sprintf(msg_line, "Number of Goto actions: %d", num_gotos); PRNT(msg_line); if (read_reduce_bit) { sprintf(msg_line, "Number of Shift/Reduce actions: %d", num_shift_reduces); PRNT(msg_line); sprintf(msg_line, "Number of Goto/Reduce actions: %d", num_goto_reduces); PRNT(msg_line); } sprintf(msg_line, "Number of Reduce actions: %d", num_reductions); PRNT(msg_line); sprintf(msg_line, "Number of Shift-Reduce conflicts: %d", num_sr_conflicts); PRNT(msg_line); sprintf(msg_line, "Number of Reduce-Reduce conflicts: %d", num_rr_conflicts); PRNT(msg_line); /**********************************************************/ /* If the removal of single productions is requested, do */ /* so now. */ /* If STATE_BIT is on, we print the states. */ /**********************************************************/ if (states_bit) { ptstats(); if (table_opt != 0) { PR_HEADING; } } /**********************************************************/ /* If the tables are requested, we process them. */ /**********************************************************/ if (table_opt != 0) { if (goto_default_bit && nt_check_bit) { PRNTERR("The options GOTO_DEFAULT and NT_CHECK are " "incompatible. Tables not generated"); } else { struct node *head; int state_no; num_entries = max_la_state + num_shifts + num_shift_reduces + num_gotos + num_goto_reduces + num_reductions; /***********************************************************/ /* We release space used by RHS_SYM, the ADEQUATE_ITEM */ /* map, ITEM_TABLE (if we don't have to dump error maps), */ /* IN_STAT, FIRST, NULL_NT and FOLLOW (if it's no longer */ /* needed). */ /***********************************************************/ ffree(rhs_sym); if (adequate_item != NULL) { struct node *q; int rule_no; for ALL_RULES(rule_no) { q = adequate_item[rule_no]; if (q != NULL) free_nodes(q, q); } ffree(adequate_item); } if (! error_maps_bit) ffree(item_table); for ALL_STATES(state_no) { head = in_stat[state_no]; if (head != NULL) { head = head -> next; free_nodes(head, in_stat[state_no]); } } ffree(in_stat); ffree(first); null_nt += (num_terminals + 1); ffree(null_nt); if (follow != NULL) { if ((! error_maps_bit) || c_bit || cpp_bit || java_bit) { follow += ((num_terminals + 1) * term_set_size); ffree(follow); } } process_tables(); } } fclose(syslis); /* close listing file */ return 0; } /****************************************************************************/ /* PRINT_OPTS: */ /****************************************************************************/ static void print_opts(void) { #if defined(C370) || defined(CW) #if defined(VM) printf("\n%s\n\n" "Usage: jikespg [filename [filetype [filemode]]] ([options]\n\n" "Options Options Options\n" "======= ======= =======\n" "action " "actfile-name=string " "actfile-mode=string\n" "actfile-type=string " "blockb=string " "blocke=string\n" "byte " "conflicts " "default[=<0|1|2|3|4|5>]\n" "edit " "error-maps " "escape=character\n" "first " "follow " "generate-parser[=string]\n" "goto-default " "hactfile-name=string " "hactfile-mode=string\n" "hactfile-type=string " "half-word " "hblockb=string\n" "hblocke=string " "lalr[=integer] " "list\n" "names= " "nt-check " "ormark=character\n" "output-size=integer " "read-reduce " "record-format=< F | V >\n" "scopes " "shift-default " "single-productions\n" "slr " "states " "table[=]\n" "trace[=] " "verbose " "warnings\n" "xref\n\n" "The following options are valid only if GENERATE-PARSER " "and TABLE are activated:\n\n" "debug " "deferred " "file-prefix=string\n" "max-distance=integer " "min-distance=integer " "prefix=string\n" "stack-size=integer " "suffix=string\n\n" "Options must be separated by a space. " "Any non-ambiguous initial prefix of a\n" "valid option may be used as an abbreviation " "for that option. When an option is\n" "composed of two separate words, an " "abbreviation may be formed by concatenating\n" "the first character of each word. Options " "that are switches may benegated by\n" "prefixing them with the string \"no\". " "Default filetype is \"grammar\"; filemode is \"*\"\n", HEADER_INFO); #else printf("\n%s\n\n" "Usage: jikespg [filename] [([options]]\n\n" "Options Options Options\n" "======= ======= =======\n" "action " "actfile-name=string " "blockb=string\n" "blocke=string " "byte " "conflicts\n" "default[=<0|1|2|3|4|5>] " "edit " "error-maps\n" "escape=character " "first " "follow\n" "generate-parser[=string] " "goto-default " "hactfile-name=string\n" "half-word " "hblockb=string " "hblocke=string\n" "lalr[=integer] " "list " "names=\n" "nt-check " "ormark=character " "output-size=integer\n" "read-reduce " "record-format=< F | V > " "scopes\n" "shift-default " "single-productions " "slr\n" "states " "table[=] " "trace[=]\n" "verbose " "warnings " "xref\n\n" "The following options are valid only if GENERATE-PARSER " "and TABLE are activated:\n\n" "debug " "deferred " "file-prefix=string\n" "max-distance=integer " "min-distance=integer " "prefix=string\n" "stack-size=integer " "suffix=string\n\n" "Options must be separated by a space. " "Any non-ambiguous initial prefix of a\n" "valid option may be used as an abbreviation " "for that option. When an option is\n" "composed of two separate words, an " "abbreviation may be formed by concatenating\n" "the first character of each word. Options " "that are switches may benegated by\n" "prefixing them with the string \"no\". " "Default filetype is \"grammar\"; filemode is \"*\"\n", HEADER_INFO); #endif #else printf("\n%s" "\n(C) Copyright IBM Corp. 1983, 1999.\n" "Licensed Materials - Program Property of IBM - All Rights Reserved.\n\n" "Usage: jikespg [options] [filename[.extension]]\n\n" "Options Options Options\n" "======= ======= =======\n" "-action " "-actfile-name=string " "-blockb=string\n" "-blocke=string " "-byte " "-conflicts\n" "-default[=<0|1|2|3|4|5>] " "-edit " "-error-maps\n" "-escape=character " "-first " "-follow\n" "-generate-parser[=string] " "-goto-default " "-half-word\n" "-hactfile-name=string " "-hblockb=string " "-hblocke=string\n" "-lalr[=integer] " "-list " "-names=\n" "-nt-check " "-ormark=character " "-output-size=integer\n" "-read-reduce " "-scopes " "-shift-default\n" "-single-productions " "-slr " "-states\n" "-table[=] " "-trace[=] " "-verbose\n" "-warnings " "-xref\n\n" "The following options are valid only if " "GENERATE-PARSER and TABLE are activated:\n" "-debug " "-deferred " "-file-prefix=string\n" "-max-distance=integer " "-min-distance=integer " "-prefix=string\n" "-stack-size=integer " "-suffix=string\n\n" "Options must be separated by a space. " "Any non-ambiguous initial prefix of a\n" "valid option may be used as an abbreviation " "for that option. When an option is\n" "composed of two separate words, an " "abbreviation may be formed by concatenating\n" "the first character of each word. " "Options that are switches may benegated by\n" "prefixing them with the string \"no\". " "Default input file extension is \".g\"\n", HEADER_INFO); printf("\nVersion %s (27 Jan 98) by Philippe Charles, IBM Research." "\nAddress comments and questions to charles@watson.ibm.com.\n", VERSION); #endif return; } jikespg-1.3/src/mkfirst.c000066400000000000000000002000461167345774400154470ustar00rootroot00000000000000/* $Id: mkfirst.c,v 1.2 1999/11/04 14:02:23 shields Exp $ */ /* This software is subject to the terms of the IBM Jikes Compiler License Agreement available at the following URL: http://www.ibm.com/research/jikes. Copyright (C) 1983, 1999, International Business Machines Corporation and others. All Rights Reserved. You must accept the terms of that agreement to use this software. */ static char hostfile[] = __FILE__; #include #include "common.h" #include "header.h" #define LEN (PRINT_LINE_SIZE - 4) #define NEXT_RULE_SIZE (num_rules + 1) #define LAST_RHS_INDEX(rule_no) rules[rule_no + 1].rhs - 1 #define INIT_FIRST(nt) \ { \ register int k; \ for (k = 0; k < term_set_size; k++)\ first[nt * term_set_size + k] = 0;\ } static BOOLEAN is_terminal_rhs(short *rhs_start, BOOLEAN *produces_terminals, int rule_no); static BOOLEAN is_nullable_rhs(short *rhs_start, int rule_no); static void compute_first(int nt); static void print_unreachables(void); static void print_xref(void); static void print_nt_first(void); static void print_follow_map(void); static short first_map(int root, int tail); static void s_first(int root, int tail, int set); static void compute_follow(int nt); static void quick_sym(short array[], int l, int h); static void check_non_terminals(void); static void no_rules_produced(void); static void nullables_computation(void); static void compute_closure(int lhs_symbol); static void compute_produces(int symbol); static struct f_element_type { short suffix_root, suffix_tail, link; } *first_element; static struct node **direct_produces; static SET_PTR produces; /****************************************************************************/ /* TOP, STACK, and INDEX_OF are used for the linear graph algorithm in */ /* constructing the FIRST, FOLLOW and CLOSURE maps. */ /* */ /* LHS_RULE and NEXT_RULE are used in constructing a map from non-terminals */ /* to the set of rules produced by the non-terminals. */ /* */ /* FIRSTis an array used as a hash table to construct */ /* the mapping from sequence of symbols to their FIRST terminal */ /* set. A sequence is hashed into a location depending on the */ /* first symbol in that sequence. */ /* */ /* FIRST_ITEM_OF is a map from each rule into the first item */ /* that it generates. */ /* */ /* The following pointers are used to construct a mapping from each symbol */ /* in the grammar into the set of items denoted by that symbol. I.e., */ /* */ /* f(t) := { [A -> x .t y] | A -> x t y is a rule in the grammar } */ /* */ /* Since these sets are simply partitions of the set of items, they are kept*/ /* all in a sequential list in the array NEXT_ITEM. The roots of the lists */ /* are placed in the arrats T_ITEMS and NT_ITEMS. */ /****************************************************************************/ static short *stack, *index_of, *lhs_rule, *next_rule, *first_table, *first_item_of, *next_item, *nt_items, *nt_list; static int top; /*****************************************************************************/ /* MKFIRST: */ /*****************************************************************************/ /* MKFIRST constructs the FIRST and FOLLOW maps, the CLOSURE map, */ /* ADEQUATE_ITEM and ITEM_TABLE maps and all other basic maps. */ /*****************************************************************************/ void mkfirst(void) { int symbol, nt, item_no, first_of_empty, rule_no, i; BOOLEAN end_node; term_set_size = num_terminals / SIZEOF_BC + (num_terminals % SIZEOF_BC ? 1 : 0); non_term_set_size = num_non_terminals / SIZEOF_BC + (num_non_terminals % SIZEOF_BC ? 1 : 0); /* allocate various arrays */ lhs_rule = Allocate_short_array(num_non_terminals); lhs_rule -= (num_terminals + 1); next_rule = Allocate_short_array(NEXT_RULE_SIZE); first_item_of = Allocate_short_array(NEXT_RULE_SIZE); stack = Allocate_short_array(num_non_terminals + 1); index_of = Allocate_short_array(num_non_terminals); index_of -= (num_terminals + 1); /*********************************************************************/ /* NT_FIRST is used to construct a mapping from non-terminals to the */ /* set of terminals taht may appear first in a string derived from */ /* the non-terminal. */ /*********************************************************************/ nt_first = (SET_PTR) calloc(num_non_terminals, term_set_size * sizeof(BOOLEAN_CELL)); if (nt_first == NULL) nospace(__FILE__, __LINE__); nt_first -= ((num_terminals + 1) * term_set_size); next_item = Allocate_short_array(num_items + 1); nt_items = Allocate_short_array(num_non_terminals); nt_items -= (num_terminals + 1); nt_list = Allocate_short_array(num_non_terminals); nt_list -= (num_terminals + 1); first_element = (struct f_element_type *) calloc(num_items + 1, sizeof(struct f_element_type)); if (first_element == NULL) nospace(__FILE__, __LINE__); item_table = (struct itemtab *) calloc(num_items + 1, sizeof(struct itemtab)); if (item_table == NULL) nospace(__FILE__, __LINE__); for ALL_NON_TERMINALS(i) /* Initialize LHS_RULE to NIL */ lhs_rule[i] = NIL; /**************************************************************/ /* In this loop, we construct the LHS_RULE map which maps */ /* each non-terminal symbol into the set of rules it produces */ /**************************************************************/ for ALL_RULES(rule_no) { symbol = rules[rule_no].lhs; if (lhs_rule[symbol] == NIL) next_rule[rule_no] = rule_no; else { next_rule[rule_no] = next_rule[lhs_rule[symbol]]; next_rule[lhs_rule[symbol]] = rule_no; } lhs_rule[symbol] = rule_no; } /*************************************************************/ /* Check if there are any non-terminals that do not produce */ /* any rules. */ /*************************************************************/ no_rules_produced(); /*************************************************************/ /* Construct the CLOSURE map of non-terminals. */ /*************************************************************/ closure = (struct node **) calloc(num_non_terminals, sizeof(struct node *)); if (closure == NULL) nospace(__FILE__, __LINE__); closure -= (num_terminals + 1); for ALL_NON_TERMINALS(i) index_of[i] = OMEGA; top = 0; for ALL_NON_TERMINALS(nt) { if (index_of[nt] == OMEGA) compute_closure(nt); } /*************************************************************/ /* Construct the NULL_NT map for non-terminals. */ /* A non-terminal B is said to be nullable if either: */ /* B -> %empty or B -> B1 B2 B3 ... Bk where Bi is */ /* nullable for 1 <= i <= k */ /*************************************************************/ null_nt = Allocate_boolean_array(num_non_terminals); null_nt -= (num_terminals + 1); nullables_computation(); /*************************************************************/ /* Construct the FIRST map for non-terminals and also a list */ /* of non-terminals whose first set is empty. */ /*************************************************************/ for ALL_NON_TERMINALS(i) /* Initialize INDEX_OF to OMEGA */ index_of[i] = OMEGA; top = 0; for ALL_NON_TERMINALS(nt) { if (index_of[nt] == OMEGA) compute_first(nt); } /*************************************************************/ /* Since every input source will be followed by the EOFT */ /* symbol, FIRST[accept_image] cannot contain empty but */ /* instead must contain the EOFT symbol. */ /*************************************************************/ if (null_nt[accept_image]) { null_nt[accept_image] = FALSE; RESET_BIT_IN(nt_first, accept_image, empty); SET_BIT_IN(nt_first, accept_image, eoft_image); } /***************************************************************/ /* Check whether there are any non-terminals that do not */ /* generate any terminal strings. If so, signal error and stop.*/ /***************************************************************/ check_non_terminals(); /***************************************************************/ /* Construct the ITEM_TABLE, FIRST_ITEM_OF, and NT_ITEMS maps. */ /***************************************************************/ first_table = Allocate_short_array(num_symbols + 1); for ALL_SYMBOLS(i) /* Initialize FIRST_TABLE to NIL */ first_table[i] = NIL; top = 1; first_of_empty = top; first_element[first_of_empty].suffix_root = 1; first_element[first_of_empty].suffix_tail = 0; for ALL_NON_TERMINALS(i) /* Initialize NT_ITEMS to NIL */ nt_items[i] = NIL; item_no = 0; item_table[item_no].rule_number = 0; item_table[item_no].symbol = empty; item_table[item_no].dot = 0; item_table[item_no].suffix_index = NIL; for ALL_RULES(rule_no) { int j, k; first_item_of[rule_no] = item_no + 1; j = 0; k = LAST_RHS_INDEX(rule_no); for ENTIRE_RHS(i, rule_no) { item_no++; symbol = rhs_sym[i]; item_table[item_no].rule_number = rule_no; item_table[item_no].symbol = symbol; item_table[item_no].dot = j; if (lalr_level > 1 || symbol IS_A_NON_TERMINAL || symbol == error_image) { if (i == k) item_table[item_no].suffix_index = first_of_empty; else item_table[item_no].suffix_index = first_map(i + 1, k); } else item_table[item_no].suffix_index = NIL; if (symbol IS_A_NON_TERMINAL) { next_item[item_no] = nt_items[symbol]; nt_items[symbol] = item_no; } j++; } item_table[++item_no].rule_number = rule_no; item_table[item_no].symbol = empty; item_table[item_no].dot = j; item_table[item_no].suffix_index = NIL; } /***************************************************************/ /* We now compute the first set for all suffixes that were */ /* inserted in the FIRST_TABLE map. There are TOP such suffixes*/ /* Extra space is also allocated to compute the first set for */ /* suffixes whose left-hand side is the ACCEPT non-terminal. */ /* The first set for these suffixes are the sets needed to */ /* construct the FOLLOW map and compute look-ahead sets. They */ /* are placed in the FIRST table in the range 1..NUM_FIRST_SETS*/ /* The first element in the FIRST table contains the first sets*/ /* for the empty sequence. */ /***************************************************************/ num_first_sets = top; for (end_node = ((rule_no = lhs_rule[accept_image]) == NIL); ! end_node; end_node = (rule_no == lhs_rule[accept_image])) { rule_no = next_rule[rule_no]; num_first_sets++; } first = (SET_PTR) calloc(num_first_sets + 1, term_set_size * sizeof(BOOLEAN_CELL)); if (first == NULL) nospace(__FILE__, __LINE__); for (i = 1; i <= top; i++) { s_first(first_element[i].suffix_root, first_element[i].suffix_tail, i); } rule_no = lhs_rule[accept_image]; for (i = top + 1; i <= num_first_sets; i++) { rule_no = next_rule[rule_no]; item_no = first_item_of[rule_no]; item_table[item_no].suffix_index = i; INIT_FIRST(i); SET_BIT_IN(first, i, eoft_image); } /***************************************************************/ /* If the READ/REDUCE option is on, we precalculate the kernel */ /* of the final states which simply consists of the last item */ /* in the corresponding rule. Rules with the ACCEPT */ /* non-terminal as their left-hand side are not considered so */ /* as to let the Accpet action remain as a Reduce action */ /* instead of a Goto/Reduce action. */ /***************************************************************/ adequate_item = (struct node **) calloc(num_rules + 1, sizeof(struct node *)); if (adequate_item == NULL) nospace(__FILE__, __LINE__); if (read_reduce_bit) { for ALL_RULES(rule_no) { int j; j = RHS_SIZE(rule_no); if (rules[rule_no].lhs != accept_image && j > 0) { struct node *p; item_no = first_item_of[rule_no] + j; p = Allocate_node(); p -> value = item_no; p -> next = NULL; adequate_item[rule_no] = p; } else adequate_item[rule_no] = NULL; } } /***************************************************************/ /* Construct the CLITEMS map. Each element of CLITEMS points */ /* to a circular linked list of items. */ /***************************************************************/ clitems = (struct node **) calloc(num_non_terminals, sizeof(struct node *)); if (clitems == NULL) nospace(__FILE__, __LINE__); clitems -= (num_terminals + 1); for ALL_NON_TERMINALS(nt) { clitems[nt] = NULL; for (end_node = ((rule_no = lhs_rule[nt]) == NIL); ! end_node; end_node = (rule_no == lhs_rule[nt])) { struct node *p; rule_no = next_rule[rule_no]; p = Allocate_node(); p -> value = first_item_of[rule_no]; if (clitems[nt] == NULL) p -> next = p; else { p -> next = clitems[nt] -> next; clitems[nt] -> next = p; } clitems[nt] = p; } } /***************************************************************/ /* If LALR_LEVEL > 1, we need to calculate RMPSELF, a set that */ /* identifies the nonterminals that can right-most produce */ /* themselves. In order to compute RMPSELF, the map PRODUCES */ /* must be constructed which identifies for each nonterminal */ /* the set of nonterminals that it can right-most produce. */ /***************************************************************/ if (lalr_level > 1) { produces = (SET_PTR) calloc(num_non_terminals, non_term_set_size * sizeof(BOOLEAN_CELL)); if (produces == NULL) nospace(__FILE__, __LINE__); produces -= ((num_terminals + 1) * non_term_set_size); direct_produces = (struct node **) calloc(num_non_terminals, sizeof(struct node *)); if (direct_produces == NULL) nospace(__FILE__, __LINE__); direct_produces -= (num_terminals + 1); for ALL_NON_TERMINALS(nt) { struct node *p, *q; for (end_node = ((p = clitems[nt]) == NULL); ! end_node; end_node = (p == clitems[nt])) { p = p -> next; item_no = p -> value; symbol = item_table[item_no].symbol; if (symbol IS_A_NON_TERMINAL) { i = item_table[item_no].suffix_index; if (IS_IN_SET(first, i, empty) && (! IS_IN_NTSET(produces, nt, symbol - num_terminals))) { NTSET_BIT_IN(produces, nt, symbol - num_terminals); q = Allocate_node(); q -> value = symbol; q -> next = direct_produces[nt]; direct_produces[nt] = q; } } } } /************************************************************/ /* Complete the construction of the RIGHT_MOST_PRODUCES map */ /* for non-terminals using the digraph algorithm. */ /************************************************************/ for ALL_NON_TERMINALS(nt) index_of[nt] = OMEGA; top = 0; for ALL_NON_TERMINALS(nt) { if (index_of[nt] == OMEGA) compute_produces(nt); } init_rmpself(produces); produces += ((num_terminals + 1) * non_term_set_size); ffree(produces); direct_produces += (num_terminals + 1); ffree(direct_produces); } /***************************************************************/ /* Construct the FOLLOW map if */ /* 1) an SLR table is requested */ /* 2) if we have to print the FOLLOW map */ /* 3) Error-maps are requested */ /* 4) There are more than one starting symbol. */ /***************************************************************/ if (slr_bit || follow_bit || error_maps_bit || next_rule[lhs_rule[accept_image]] != lhs_rule[accept_image]) { follow = (SET_PTR) calloc(num_non_terminals, term_set_size * sizeof(BOOLEAN_CELL)); if (follow == NULL) nospace(__FILE__, __LINE__); follow -= ((num_terminals + 1) * term_set_size); SET_BIT_IN(follow, accept_image, eoft_image); for ALL_NON_TERMINALS(i) /* Initialize INDEX_OF to OMEGA */ index_of[i] = OMEGA; index_of[accept_image] = INFINITY; /* mark computed */ top = 0; for ALL_NON_TERMINALS(nt) { if (index_of[nt] == OMEGA) /* not yet computed ? */ compute_follow(nt); } /***************************************************************/ /* Initialize FIRST for suffixes that can follow each starting*/ /* non-terminal ( except the main symbol) with the FOLLOW set */ /* of the non-terminal in question. */ /***************************************************************/ rule_no = lhs_rule[accept_image]; if (next_rule[rule_no] != rule_no) { rule_no = next_rule[rule_no]; /* first rule */ top = item_table[first_item_of[rule_no]].suffix_index; for (i = top + 1; i <= num_first_sets; i++) { rule_no = next_rule[rule_no]; item_no = first_item_of[rule_no]; symbol = item_table[item_no].symbol; if (symbol IS_A_NON_TERMINAL) { ASSIGN_SET(first, i, follow, symbol); } } } } /***************************************************************/ /* If WARNINGS option is turned on, the unreachable symbols in */ /* the grammar are printed. */ /***************************************************************/ if (warnings_bit) print_unreachables(); /***************************************************************/ /* If a Cross_Reference listing is requested, it is generated */ /* here. */ /***************************************************************/ if (xref_bit) print_xref(); /***************************************************************/ /* If a listing of the FIRST map is requested, it is generated */ /* here. */ /***************************************************************/ if (first_bit) print_nt_first(); /****************************************************************/ /* If a listing of the FOLLOW map is requested, it is generated */ /* here. */ /***************************************************************/ if (follow_bit) print_follow_map(); /***************************************************************/ /* Free allocated arrays. */ /***************************************************************/ nt_first += ((num_terminals + 1) * term_set_size); ffree(nt_first); nt_list += (num_terminals + 1); ffree(nt_list); ffree(first_table); ffree(first_element); nt_items += (num_terminals + 1); ffree(nt_items); ffree(next_item); ffree(stack); index_of += (num_terminals + 1); ffree(index_of); lhs_rule += (num_terminals + 1); ffree(lhs_rule); ffree(next_rule); ffree(first_item_of); return; } /*****************************************************************************/ /* NO_RULES_PRODUCED: */ /*****************************************************************************/ static void no_rules_produced(void) { char line[PRINT_LINE_SIZE + 1], tok[SYMBOL_SIZE + 1]; int nt_root, nt_last, symbol; /*************************************************************/ /* Build a list of all non-terminals that do not produce any */ /* rules. */ /*************************************************************/ nt_root = NIL; for ALL_NON_TERMINALS(symbol) { if (lhs_rule[symbol] == NIL) { if (nt_root == NIL) nt_root = symbol; else nt_list[nt_last] = symbol; nt_last = symbol; } } /*************************************************************/ /* If the list of non-terminals that do not produce any rules*/ /* is not empty, signal error and stop. */ /*************************************************************/ if (nt_root != NIL) { PR_HEADING; nt_list[nt_last] = NIL; if (nt_list[nt_root] == NIL) { PRNTERR("The following Non-terminal does not produce any rules: "); } else { PRNTERR("The following Non-terminals do not produce any rules: "); } strcpy(line, " "); for (symbol = nt_root; symbol != NIL; symbol = nt_list[symbol]) { restore_symbol(tok, RETRIEVE_STRING(symbol)); if (strlen(line) + strlen(tok) > PRINT_LINE_SIZE) { PRNT(line); print_large_token(line, tok, " ", LEN); } else strcat(line, tok); strcat(line,BLANK); } PRNT(line); exit(12); } } /*****************************************************************************/ /* COMPUTE_CLOSURE: */ /*****************************************************************************/ /* This function computes the closure of a non-terminal LHS_SYMBOL passed */ /* to it as an argument using the digraph algorithm. */ /* The closure of a non-terminal A is the set of all non-terminals Bi that */ /* can directly or indirectly start a string generated by A. */ /* I.e., A *::= Bi X where X is an arbitrary string. */ /*****************************************************************************/ static void compute_closure(int lhs_symbol) { int indx; short *nont_list; int symbol, rule_no, nt_root, i; struct node *p, *q; BOOLEAN end_node; nont_list = Allocate_short_array(num_non_terminals); nont_list -= (num_terminals + 1); /* Temporary direct */ /* access set for closure. */ stack[++top] = lhs_symbol; indx = top; index_of[lhs_symbol] = indx; for ALL_NON_TERMINALS(i) nont_list[i] = OMEGA; nont_list[lhs_symbol] = NIL; nt_root = lhs_symbol; closure[lhs_symbol] = NULL; /* Permanent closure set. Linked list */ for (end_node = ((rule_no = lhs_rule[lhs_symbol]) == NIL); ! end_node; /* Iterate over all rules of LHS_SYMBOL */ end_node = (rule_no == lhs_rule[lhs_symbol])) { rule_no = next_rule[rule_no]; symbol = (RHS_SIZE(rule_no) == 0 ? empty : rhs_sym[rules[rule_no].rhs]); if (symbol IS_A_NON_TERMINAL) { if (nont_list[symbol] == OMEGA) { if (index_of[symbol] == OMEGA) /* if first time seen */ compute_closure(symbol); index_of[lhs_symbol] = MIN(index_of[lhs_symbol], index_of[symbol]); nont_list[symbol] = nt_root; nt_root = symbol; /* add closure[symbol] to closure of LHS_SYMBOL. */ for (end_node = ((q = closure[symbol]) == NULL); ! end_node; end_node = (q == closure[symbol])) { q = q -> next; if (nont_list[q -> value] == OMEGA) { nont_list[q -> value] = nt_root; nt_root = q -> value; } } } } } for (; nt_root != lhs_symbol; nt_root = nont_list[nt_root]) { p = Allocate_node(); p -> value = nt_root; if (closure[lhs_symbol] == NULL) p -> next = p; else { p -> next = closure[lhs_symbol] -> next; closure[lhs_symbol] -> next = p; } closure[lhs_symbol] = p; } if (index_of[lhs_symbol] == indx) { for (symbol = stack[top]; symbol != lhs_symbol; symbol = stack[--top]) { q = closure[symbol]; if (q != NULL) { p = q -> next; free_nodes(p, q); /* free nodes used by CLOSURE[SYMBOL] */ closure[symbol] = NULL; } p = Allocate_node(); p -> value = lhs_symbol; p -> next = p; closure[symbol] = p; for (end_node = ((q = closure[lhs_symbol]) == NULL); ! end_node; end_node = (q == closure[lhs_symbol])) { q = q -> next; if (q -> value != symbol) { p = Allocate_node(); p -> value = q -> value; p -> next = closure[symbol] -> next; closure[symbol] -> next = p; closure[symbol] = p; } } index_of[symbol] = INFINITY; } index_of[lhs_symbol] = INFINITY; top--; } nont_list += (num_terminals + 1); ffree(nont_list); return; } /*****************************************************************************/ /* NULLABLES_COMPUTATION: */ /*****************************************************************************/ /* This procedure computes the set of non-terminal symbols that can */ /* generate the empty string. Such non-terminals are said to be nullable. */ /* */ /* A non-terminal "A" can generate empty if the grammar in question contains */ /* a rule: */ /* A ::= B1 B2 ... Bn n >= 0, 1 <= i <= n */ /* and Bi, for all i, is a nullable non-terminal. */ /*****************************************************************************/ static void nullables_computation(void) { short *rhs_start; int rule_no, nt; BOOLEAN changed = TRUE, end_node; rhs_start = Allocate_short_array(NEXT_RULE_SIZE); /******************************************************************/ /* First, mark all non-terminals as non-nullable. Then initialize*/ /* RHS_START. RHS_START is a mapping from each rule in the grammar*/ /* into the next symbol in its right-hand side that has not yet */ /* proven to be nullable. */ /******************************************************************/ for ALL_NON_TERMINALS(nt) null_nt[nt] = FALSE; for ALL_RULES(rule_no) rhs_start[rule_no] = rules[rule_no].rhs; /******************************************************************/ /* We now iterate over the rules and try to advance the RHS_START */ /* pointer thru each right-hand side as far as we can. If one or */ /* more non-terminals are found to be nullable, they are marked */ /* as such and the process is repeated. */ /* */ /* If we go through all the rules and no new non-terminal is found*/ /* to be nullable then we stop and return. */ /* */ /* Note that for each iteration, only rules associated with */ /* non-terminals that are non-nullable are considered. Further, */ /* as soon as a non-terminal is found to be nullable, the */ /* remaining rules associated with it are not considered. I.e., */ /* we quit the inner loop. */ /******************************************************************/ while(changed) { changed = FALSE; for ALL_NON_TERMINALS(nt) { for (end_node = ((rule_no = lhs_rule[nt]) == NIL); ! null_nt[nt] && ! end_node; end_node = (rule_no == lhs_rule[nt])) { rule_no = next_rule[rule_no]; if (is_nullable_rhs(rhs_start,rule_no)) { changed = TRUE; null_nt[nt] = TRUE; } } } } ffree(rhs_start); return; } /*****************************************************************************/ /* IS_NULLABLE_RHS: */ /*****************************************************************************/ /* This procedure tries to advance the RHS_START pointer. If the current */ /* symbol identified by the RHS_START element is a terminal it returns FALSE */ /* to indicate that it cannot go any further. If it encounters a non-null- */ /* lable non-terminal, it also returns FALSE. Otherwise, the whole right-hand*/ /* side is consumed, and it returns the value TRUE. */ /*****************************************************************************/ static BOOLEAN is_nullable_rhs(short *rhs_start, int rule_no) { int symbol; for(rhs_start[rule_no] = rhs_start[rule_no]; rhs_start[rule_no] <= rules[rule_no + 1].rhs - 1; rhs_start[rule_no]++) { symbol = rhs_sym[rhs_start[rule_no]]; if (symbol IS_A_TERMINAL) return(FALSE); else if (! null_nt[symbol]) /* symbol is a non-terminal */ return(FALSE); } return(TRUE); } /*****************************************************************************/ /* COMPUTE_FIRST: */ /*****************************************************************************/ /* This subroutine computes FIRST(NT) for some non-terminal NT using the */ /* digraph algorithm. */ /* FIRST(NT) is the set of all terminals Ti that may start a string generated*/ /* by NT. That is, NT *::= Ti X where X is an arbitrary string. */ /*****************************************************************************/ static void compute_first(int nt) { int indx; BOOLEAN end_node, blocked; int i, symbol, rule_no; SET_PTR temp_set; temp_set = (SET_PTR) calloc(1, term_set_size * sizeof(BOOLEAN_CELL)); if (temp_set == NULL) nospace(__FILE__, __LINE__); stack[++top] = nt; indx = top; index_of[nt] = indx; /**************************************************************/ /* Iterate over all rules generated by non-terminal NT... */ /* In this application of the transitive closure algorithm, */ /* */ /* G(A) := { t | A ::= t X for a terminal t and a string X } */ /* */ /* The relation R is defined as follows: */ /* */ /* R(A, B) iff A ::= B1 B2 ... Bk B X */ /* */ /* where Bi is nullable for 1 <= i <= k */ /**************************************************************/ for (end_node = ((rule_no = lhs_rule[nt]) == NIL); ! end_node; /* Iterate over all rules produced by NT */ end_node = (rule_no == lhs_rule[nt])) { rule_no = next_rule[rule_no]; blocked = FALSE; for ENTIRE_RHS(i, rule_no) { symbol = rhs_sym[i]; if (symbol IS_A_NON_TERMINAL) { if (index_of[symbol] == OMEGA) compute_first(symbol); index_of[nt] = MIN( index_of[nt], index_of[symbol]); ASSIGN_SET(temp_set, 0, nt_first, symbol); RESET_BIT(temp_set, empty); SET_UNION(nt_first, nt, temp_set, 0); blocked = NOT(null_nt[symbol]); } else { SET_BIT_IN(nt_first, nt, symbol); blocked = TRUE; } if (blocked) break; } if (! blocked) { SET_BIT_IN(nt_first, nt, empty); } } if (index_of[nt] == indx) { for (symbol = stack[top]; symbol != nt; symbol = stack[--top]) { ASSIGN_SET(nt_first, symbol, nt_first, nt); index_of[symbol] = INFINITY; } index_of[nt] = INFINITY; top--; } ffree(temp_set); return; } /*****************************************************************************/ /* CHECK_NON_TERMINALS: */ /*****************************************************************************/ /* This procedure checks whether or not any non-terminal symbols can fail to */ /* generate a string of terminals. */ /* */ /* A non-terminal "A" can generate a terminal string if the grammar in */ /* question contains a rule of the form: */ /* */ /* A ::= X1 X2 ... Xn n >= 0, 1 <= i <= n */ /* */ /* and Xi, for all i, is a terminal or a non-terminal that can generate a */ /* string of terminals. */ /* This routine is structurally identical to COMPUTE_NULLABLES. */ /*****************************************************************************/ static void check_non_terminals(void) { char line[PRINT_LINE_SIZE + 1], tok[SYMBOL_SIZE + 1]; short *rhs_start; int rule_no, nt_root, nt_last, symbol, nt; BOOLEAN changed = TRUE, end_node, *produces_terminals; rhs_start = Allocate_short_array(NEXT_RULE_SIZE); produces_terminals = Allocate_boolean_array(num_non_terminals); produces_terminals -= (num_terminals + 1); /******************************************************************/ /* First, mark all non-terminals as not producing terminals. Then */ /* initialize RHS_START. RHS_START is a mapping from each rule in */ /* the grammar into the next symbol in its right-hand side that */ /* has not yet proven to be a symbol that generates terminals. */ /******************************************************************/ for ALL_NON_TERMINALS(nt) produces_terminals[nt] = FALSE; produces_terminals[accept_image] = TRUE; for ALL_RULES(rule_no) rhs_start[rule_no] = rules[rule_no].rhs; /******************************************************************/ /* We now iterate over the rules and try to advance the RHS_START */ /* pointer to each right-hand side as far as we can. If one or */ /* more non-terminals are found to be "all right", they are */ /* marked as such and the process is repeated. */ /* */ /* If we go through all the rules and no new non-terminal is */ /* found to be "all right" then we stop and return. */ /* */ /* Note that on each iteration, only rules associated with */ /* non-terminals that are not "all right" are considered. Further,*/ /* as soon as a non-terminal is found to be "all right", the */ /* remaining rules associated with it are not considered. I.e., */ /* we quit the inner loop. */ /******************************************************************/ while(changed) { changed = FALSE; for ALL_NON_TERMINALS(nt) { for (end_node = ((rule_no = lhs_rule[nt]) == NIL); (! produces_terminals[nt]) && (! end_node); end_node = (rule_no == lhs_rule[nt])) { rule_no = next_rule[rule_no]; if (is_terminal_rhs(rhs_start, produces_terminals, rule_no)) { changed = TRUE; produces_terminals[nt] = TRUE; } } } } /*************************************************************/ /* Construct a list of all non-terminals that do not generate*/ /* terminal strings. */ /*************************************************************/ nt_root = NIL; for ALL_NON_TERMINALS(nt) { if (! produces_terminals[nt]) { if (nt_root == NIL) nt_root = nt; else nt_list[nt_last] = nt; nt_last = nt; } } /*************************************************************/ /* If there are non-terminal symbols that do not generate */ /* terminal strings, print them out and stop the program. */ /*************************************************************/ if (nt_root != NIL) { nt_list[nt_last] = NIL; /* mark end of list */ PR_HEADING; strcpy(line, "*** ERROR: The following Non-terminal"); if (nt_list[nt_root] == NIL) strcat(line, " does not generate any terminal strings: "); else { strcat(line, "s do not generate any terminal strings: "); PRNT(line); strcpy(line, " "); /* 8 spaces */ } for (symbol = nt_root; symbol != NIL; symbol = nt_list[symbol]) { restore_symbol(tok, RETRIEVE_STRING(symbol)); if (strlen(line) + strlen(tok) > PRINT_LINE_SIZE-1) { PRNT(line); print_large_token(line, tok, " ", LEN); } else strcat(line, tok); strcat(line, BLANK); } PRNT(line); exit(12); } produces_terminals += (num_terminals + 1); ffree(produces_terminals); ffree(rhs_start); } /*****************************************************************************/ /* IS_TERMINAL_RHS: */ /*****************************************************************************/ /* This procedure tries to advance the RHS_START pointer. If the current */ /* symbol identified by the RHS_START element is a bad non-terminal it */ /* returns FALSE. Otherwise, the whole right-hand side is traversed, and it */ /* returns the value TRUE. */ /*****************************************************************************/ static BOOLEAN is_terminal_rhs(short *rhs_start, BOOLEAN *produces_terminals, int rule_no) { int symbol; for(rhs_start[rule_no] = rhs_start[rule_no]; rhs_start[rule_no] <= rules[rule_no + 1].rhs - 1; rhs_start[rule_no]++) { symbol = rhs_sym[rhs_start[rule_no]]; if (symbol IS_A_NON_TERMINAL) { if (! produces_terminals[symbol]) return(FALSE); } } return(TRUE); } /*****************************************************************************/ /* FIRST_MAP: */ /*****************************************************************************/ /* FIRST_MAP takes as arguments two pointers, ROOT and TAIL, to a sequence */ /* of symbols in RHS which it inserts in FIRST_TABLE. The vector FIRST_TABLE*/ /* is used as the base for a hashed table where collisions are resolved by */ /* links. Elements added to this hash table are allocated from the vector */ /* FIRST_ELEMENT, with the variable TOP always indicating the position of the*/ /* last element in FIRST_ELEMENT that was allocated. */ /* NOTE: The suffix indentified by ROOT and TAIL is presumed not to be empty.*/ /* That is, ROOT <= TAIL !!! */ /*****************************************************************************/ static short first_map(int root, int tail) { int i, j, k; for (i = first_table[rhs_sym[root]]; i != NIL; i = first_element[i].link) { for (j = root + 1, k = first_element[i].suffix_root + 1; (j <= tail && k <= first_element[i].suffix_tail); j++, k++) { if (rhs_sym[j] != rhs_sym[k]) break; } if (j > tail && k > first_element[i].suffix_tail) return((short) i); } top++; first_element[top].suffix_root = root; first_element[top].suffix_tail = tail; first_element[top].link = first_table[rhs_sym[root]]; first_table[rhs_sym[root]] = top; return(top); } /*****************************************************************************/ /* S_FIRST: */ /*****************************************************************************/ /* S_FIRST takes as argument, two pointers: ROOT and TAIL to a sequence of */ /* symbols in the vector RHS, and INDEX which is the index of a first set. */ /* It computes the set of all terminals that can appear as the first symbol */ /* in the sequence and places the result in the FIRST set indexable by INDEX.*/ /*****************************************************************************/ static void s_first(int root, int tail, int index) { int i, symbol; symbol = (root > tail ? empty : rhs_sym[root]); if (symbol IS_A_TERMINAL) { INIT_FIRST(index); SET_BIT_IN(first, index, symbol); /* add it to set */ } else { ASSIGN_SET(first, index, nt_first, symbol); } for (i = root + 1; i <= tail && IS_IN_SET(first, index, empty); i++) { symbol = rhs_sym[i]; RESET_BIT_IN(first, index, empty); /* remove EMPTY */ if (symbol IS_A_TERMINAL) { SET_BIT_IN(first, index, symbol); /* add it to set */ } else { SET_UNION(first, index, nt_first, symbol); } } return; } /******************************************************************/ /* COMPUTE_PRODUCES: */ /******************************************************************/ /* For a given symbol, complete the computation of */ /* PRODUCES[symbol]. */ /******************************************************************/ static void compute_produces(int symbol) { int indx; int new_symbol; struct node *p, *q; stack[++top] = symbol; indx = top; index_of[symbol] = indx; for (p = direct_produces[symbol]; p != NULL; q = p, p = p -> next) { new_symbol = p -> value; if (index_of[new_symbol] == OMEGA) /* first time seen? */ compute_produces(new_symbol); index_of[symbol] = MIN(index_of[symbol], index_of[new_symbol]); NTSET_UNION(produces, symbol, produces, new_symbol); } if (direct_produces[symbol] != NULL) free_nodes(direct_produces[symbol], q); if (index_of[symbol] == indx) /*symbol is SCC root */ { for (new_symbol = stack[top]; new_symbol != symbol; new_symbol = stack[--top]) { ASSIGN_NTSET(produces, new_symbol, produces, symbol); index_of[new_symbol] = INFINITY; } index_of[symbol] = INFINITY; top--; } return; } /*****************************************************************************/ /* COMPUTE_FOLLOW: */ /*****************************************************************************/ /* COMPUTE_FOLLOW computes FOLLOW[nt] for some non-terminal NT using the */ /* digraph algorithm. FOLLOW[NT] is the set of all terminals Ti that */ /* may immediately follow a string X generated by NT. I.e., if NT *::= X */ /* then X Ti is a valid substring of a class of strings that may be */ /* recognized by the language. */ /*****************************************************************************/ static void compute_follow(int nt) { int indx; int rule_no, lhs_symbol, item_no; SET_PTR temp_set; temp_set = (SET_PTR) calloc(1, term_set_size * sizeof(BOOLEAN_CELL)); if (temp_set == NULL) nospace(__FILE__, __LINE__); /**************************************************************/ /* FOLLOW[NT] was initialized to 0 for all non-terminals. */ /**************************************************************/ stack[++top] = nt; indx = top; index_of[nt] = indx; for (item_no = nt_items[nt]; item_no != NIL; item_no = next_item[item_no]) { /* iterate over all items of NT */ ASSIGN_SET(temp_set, 0, first, item_table[item_no].suffix_index); if (IS_ELEMENT(temp_set, empty)) { RESET_BIT(temp_set, empty); rule_no = item_table[item_no].rule_number; lhs_symbol = rules[rule_no].lhs; if (index_of[lhs_symbol] == OMEGA) compute_follow(lhs_symbol); SET_UNION( follow, nt, follow, lhs_symbol); index_of[nt] = MIN( index_of[nt], index_of[lhs_symbol]); } SET_UNION(follow, nt, temp_set, 0); } if (index_of[nt] == indx) { for (lhs_symbol = stack[top]; lhs_symbol != nt; lhs_symbol = stack[--top]) { ASSIGN_SET(follow, lhs_symbol, follow, nt); index_of[lhs_symbol] = INFINITY; } index_of[nt] = INFINITY; top--; } ffree(temp_set); return; } /*****************************************************************************/ /* PRINT_UNREACHABLES: */ /*****************************************************************************/ static void print_unreachables(void) { short *symbol_list; int nt, t_root, nt_root, rule_no, symbol, i; BOOLEAN end_node; char line[PRINT_LINE_SIZE + 1], tok[SYMBOL_SIZE + 1]; /***************************************************************/ /* SYMBOL_LIST is used for two purposes: */ /* 1) to mark symbols that are reachable from the Accepting */ /* non-terminal. */ /* 2) to construct lists of symbols that are not reachable. */ /***************************************************************/ symbol_list = Allocate_short_array(num_symbols + 1); for ALL_SYMBOLS(i) symbol_list[i] = OMEGA; symbol_list[eoft_image] = NIL; symbol_list[empty] = NIL; if (error_maps_bit) symbol_list[error_image] = NIL; /*********************************************************************/ /* Initialize a list consisting only of the Accept non-terminal. */ /* This list is a work pile of non-terminals to process as follows: */ /* Each non-terminal in the front of the list is removed in turn and */ /* 1) All terminal symbols in one of its right-hand sides are */ /* marked reachable. */ /* 2) All non-terminals in one of its right-hand sides are placed */ /* in the the work pile of it had not been processed previously */ /*********************************************************************/ nt_root = accept_image; symbol_list[nt_root] = NIL; for (nt = nt_root; nt != NIL; nt = nt_root) { nt_root = symbol_list[nt]; for (end_node = ((rule_no = lhs_rule[nt]) == NIL); ! end_node; end_node = (rule_no == lhs_rule[nt])) { rule_no = next_rule[rule_no]; for ENTIRE_RHS(i, rule_no) { symbol = rhs_sym[i]; if (symbol IS_A_TERMINAL) symbol_list[symbol] = NIL; else if (symbol_list[symbol] == OMEGA) { symbol_list[symbol] = nt_root; nt_root = symbol; } } } } /***************************************************************/ /* We now iterate (backwards to keep things in order) over the */ /* terminal symbols, and place each unreachable terminal in a */ /* list. If the list is not empty, we signal that these symbols*/ /* are unused. */ /***************************************************************/ t_root = NIL; for ALL_TERMINALS_BACKWARDS(symbol) { if (symbol_list[symbol] == OMEGA) { symbol_list[symbol] = t_root; t_root = symbol; } } if (t_root != NIL) { PR_HEADING; if (symbol_list[t_root] != NIL) { PRNT("*** The following Terminals are useless: "); fprintf(syslis, "\n\n"); strcpy(line, " "); /* 8 spaces */ } else strcpy(line, "*** The following Terminal is useless: "); for (symbol = t_root; symbol != NIL; symbol = symbol_list[symbol]) { restore_symbol(tok, RETRIEVE_STRING(symbol)); if (strlen(line) + strlen(tok) > PRINT_LINE_SIZE) { PRNT(line); print_large_token(line, tok, " ", LEN); } else { strcat(line, tok); strcat(line, BLANK); } strcat(line, BLANK); } PRNT(line); } /***************************************************************/ /* We now iterate (backward to keep things in order) over the */ /* non-terminals, and place each unreachable non-terminal in a */ /* list. If the list is not empty, we signal that these */ /* symbols are unused. */ /***************************************************************/ nt_root = NIL; for ALL_NON_TERMINALS_BACKWARDS(symbol) { if (symbol_list[symbol] == OMEGA) { symbol_list[symbol] = nt_root; nt_root = symbol; } } if (nt_root != NIL) { PR_HEADING; if (symbol_list[nt_root] != NIL) { PRNT("*** The following Non-Terminals are useless: "); fprintf(syslis, "\n\n"); strcpy(line, " "); /* 8 spaces */ } else strcpy(line, "*** The following Non-Terminal is useless: "); for (symbol = nt_root; symbol != NIL; symbol = symbol_list[symbol]) { restore_symbol(tok, RETRIEVE_STRING(symbol)); if (strlen(line) + strlen(tok) > PRINT_LINE_SIZE) { PRNT(line); print_large_token(line, tok, " ", LEN); } else strcat(line, tok); strcat(line, BLANK); } PRNT(line); } ffree(symbol_list); return; } /*****************************************************************************/ /* PRINT_XREF: */ /*****************************************************************************/ /* PRINT_XREF prints out the Cross-reference map. We build a map from each */ /* terminal into the set of items whose Dot-symbol (symbol immediately */ /* following the dot ) is the terminal in question. Note that we iterate */ /* backwards over the rules to keep the rules associated with the items */ /* sorted, since they are inserted in STACK fashion in the lists: Last-in, */ /* First out. */ /*****************************************************************************/ static void print_xref(void) { short *sort_sym, *t_items; int i, offset, rule_no, item_no, symbol; char line[PRINT_LINE_SIZE + 1], tok[SYMBOL_SIZE + 1]; /*********************************************************************/ /* SORT_SYM is used to sort the symbols for cross_reference listing. */ /*********************************************************************/ sort_sym = Allocate_short_array(num_symbols + 1); t_items = Allocate_short_array(num_terminals + 1); for ALL_TERMINALS(i) t_items[i] = NIL; for ALL_RULES_BACKWARDS(rule_no) { item_no = first_item_of[rule_no]; for ENTIRE_RHS(i, rule_no) { symbol = rhs_sym[i]; if (symbol IS_A_TERMINAL) { next_item[item_no] = t_items[symbol]; t_items[symbol] = item_no; } item_no++; } } for ALL_SYMBOLS(i) sort_sym[i] = i; quick_sym(sort_sym, 1, num_symbols); PR_HEADING; fprintf(syslis, "\n\nCross-reference table:\n"); output_line_no += 3; for ALL_SYMBOLS(i) { symbol = sort_sym[i]; if (symbol != accept_image && symbol != eoft_image && symbol != empty) { fprintf(syslis, "\n"); ENDPAGE_CHECK; restore_symbol(tok, RETRIEVE_STRING(symbol)); print_large_token(line, tok, "", PRINT_LINE_SIZE-7); strcat(line, " ==>> "); offset = strlen(line) - 1; if (symbol IS_A_NON_TERMINAL) { BOOLEAN end_node; for (end_node = ((rule_no = lhs_rule[symbol]) == NIL); ! end_node; end_node = (rule_no == lhs_rule[symbol])) { rule_no = next_rule[rule_no]; sprintf(tok, "%d", rule_no); if (strlen(tok) + strlen(line) > PRINT_LINE_SIZE) { int j; fprintf(syslis, "\n%s", line); ENDPAGE_CHECK; strcpy(line, BLANK); for (j = 1; j <= offset; j++) strcat(line, BLANK); } strcat(line, tok); strcat(line, BLANK); } fprintf(syslis, "\n%s", line); ENDPAGE_CHECK; item_no = nt_items[symbol]; } else { for (item_no = t_items[symbol]; item_no != NIL; item_no = next_item[item_no]) { rule_no = item_table[item_no].rule_number; sprintf(tok, "%d", rule_no); if (strlen(tok) + strlen(line) > PRINT_LINE_SIZE) { int j; fprintf(syslis, "\n%s", line); ENDPAGE_CHECK; strcpy(line, BLANK); for (j = 1; j <= offset; j++) strcat(line, BLANK); } strcat(line, tok); strcat(line, BLANK); } fprintf(syslis, "\n%s",line); ENDPAGE_CHECK; } } } fprintf(syslis, "\n\n"); output_line_no +=2; ffree(t_items); ffree(sort_sym); return; } /*****************************************************************************/ /* QUICK_SYM: */ /*****************************************************************************/ /* QUICK_SYM takes as arguments an array of pointers whose elements point to */ /* nodes and two integer arguments: L, H. L and H indicate respectively the */ /* lower and upper bound of a section in the array. */ /*****************************************************************************/ static void quick_sym(short array[], int l, int h) { /**************************************************************/ /* Since no more than 2**15-1 symbols are allowed, the stack */ /* not grow past 14. */ /**************************************************************/ int lostack[14], histack[14], lower, upper, top, i, j; short temp, pivot; top = 1; lostack[top] = l; histack[top] = h; while(top != 0) { lower = lostack[top]; upper = histack[top--]; while(upper > lower) { /********************************************************/ /* Split the array section indicated by LOWER and UPPER */ /* using ARRAY[LOWER] as the pivot. */ /********************************************************/ i = lower; pivot = array[lower]; for (j = lower + 1; j <= upper; j++) { if (strcmp(RETRIEVE_STRING(array[j]), RETRIEVE_STRING(pivot)) < 0) { temp = array[++i]; array[i] = array[j]; array[j] = temp; } } array[lower] = array[i]; array[i] = pivot; top++; if ((i - lower) < (upper - i)) { lostack[top] = i + 1; histack[top] = upper; upper = i - 1; } else { histack[top] = i - 1; lostack[top] = lower; lower = i + 1; } } } return; } /*****************************************************************************/ /* PRINT_NT_FIRST: */ /*****************************************************************************/ /* PRINT_NT_FIRST prints the first set for each non-terminal. */ /*****************************************************************************/ static void print_nt_first(void) { int nt, t; char line[PRINT_LINE_SIZE + 1], tok[SYMBOL_SIZE + 1]; PR_HEADING; fprintf(syslis, "\nFirst map for non-terminals:\n\n"); output_line_no += 3; for ALL_NON_TERMINALS(nt) { restore_symbol(tok, RETRIEVE_STRING(nt)); print_large_token(line, tok, "", PRINT_LINE_SIZE - 7); strcat(line, " ==>> "); for ALL_TERMINALS(t) { if (IS_IN_SET(nt_first, nt, t)) { restore_symbol(tok, RETRIEVE_STRING(t)); if (strlen(line) + strlen(tok) > PRINT_LINE_SIZE - 1) { fprintf(syslis, "\n%s", line); ENDPAGE_CHECK; print_large_token(line, tok, " ", LEN); } else strcat(line, tok); strcat(line, BLANK); } } fprintf(syslis, "\n%s\n", line); output_line_no++; ENDPAGE_CHECK; } return; } /*****************************************************************************/ /* PRINT_FOLLOW_MAP: */ /*****************************************************************************/ /* PRINT_FOLLOW_MAP prints the follow map. */ /*****************************************************************************/ static void print_follow_map(void) { int nt, t; char line[PRINT_LINE_SIZE + 1], tok[SYMBOL_SIZE + 1]; PR_HEADING; fprintf(syslis, "\nFollow Map:\n\n"); output_line_no += 3; for ALL_NON_TERMINALS(nt) { restore_symbol(tok, RETRIEVE_STRING(nt)); print_large_token(line, tok, "", PRINT_LINE_SIZE-7); strcat(line, " ==>> "); for ALL_TERMINALS(t) { if (IS_IN_SET(follow, nt, t)) { restore_symbol(tok, RETRIEVE_STRING(t)); if (strlen(line) + strlen(tok) > PRINT_LINE_SIZE-2) { fprintf(syslis, "\n%s", line); ENDPAGE_CHECK; print_large_token(line, tok, " ", LEN); } else strcat(line, tok); strcat(line, BLANK); } } fprintf(syslis, "\n%s\n", line); output_line_no++; ENDPAGE_CHECK; } return; } jikespg-1.3/src/mkred.c000066400000000000000000001447571167345774400151120ustar00rootroot00000000000000/* $Id: mkred.c,v 1.2 1999/11/04 14:02:23 shields Exp $ */ /* This software is subject to the terms of the IBM Jikes Compiler License Agreement available at the following URL: http://www.ibm.com/research/jikes. Copyright (C) 1983, 1999, International Business Machines Corporation and others. All Rights Reserved. You must accept the terms of that agreement to use this software. */ static char hostfile[] = __FILE__; #include "common.h" #include "reduce.h" #include "header.h" /***********************************************************************/ /* STACK_ROOT is used in la_traverse to construct a stack of symbols. */ /* The boolean vector SINGLE_COMPLETE_ITEM identifies states whose */ /* kernel consists of a single final item and other conditions allows */ /* us to compute default reductions for such states. */ /* The vector LA_BASE is used in COMPUTE_READ and TRACE_LALR_PATH to */ /* identify states whose read sets can be completely computed from */ /* their kernel items. */ /***********************************************************************/ static struct node *stack_root = NULL; static BOOLEAN *single_complete_item; static int *la_base; /*****************************************************************************/ /* LPGACCESS: */ /*****************************************************************************/ /* Given a STATE_NO and an ITEM_NO, ACCESS computes the set of states where */ /* the rule from which ITEM_NO is derived was introduced through closure. */ /*****************************************************************************/ struct node *lpgaccess(int state_no, int item_no) { int i; BOOLEAN end_node; struct node *access_root, *head, *tail, *q, *p, *s; /****************************************************************/ /* Build a list pointed to by ACCESS_ROOT originally consisting */ /* only of STATE_NO. */ /****************************************************************/ access_root = Allocate_node(); access_root -> value = state_no; access_root -> next = NULL; for (i = item_table[item_no].dot; i > 0; i--)/*distance to travel is DOT */ { head = access_root; /* Save old ACCESS_ROOT */ access_root = NULL; /* Initialize ACCESS_ROOT for new list */ for (p = head; p != NULL; tail = p, p = p -> next) { /***********************************************************/ /* Compute set of states with transition into p->value. */ /***********************************************************/ for (end_node = ((s = in_stat[p -> value]) == NULL); ! end_node; end_node = (s == in_stat[p -> value])) { s = s -> next; q = Allocate_node(); q -> value = s -> value; q -> next = access_root; access_root = q; } } free_nodes(head, tail); /* free previous list */ } return(access_root); } /*****************************************************************************/ /* TRACE_LALR_PATH: */ /*****************************************************************************/ /* Given an item of the form: [x .A y], where x and y are arbitrary strings, */ /* and A is a non-terminal, we pretrace the path(s) in the automaton that */ /* will be followed in computing the look-ahead set for that item in */ /* STATE_NO. A number is assigned to all pairs (S, B), where S is a state, */ /* and B is a non-terminal, involved in the paths. GOTO_INDX points to the */ /* GOTO_ELEMENT of (STATE_NO, A). */ /*****************************************************************************/ static void trace_lalr_path(int state_no, int goto_indx) { int i, symbol, item, state; struct goto_header_type go_to; BOOLEAN contains_empty; struct node *p, *r, *t, *w; /*********************************************************************/ /* If STATE is a state number we first check to see if its base */ /* look-ahead set is a special one that does not contain EMPTY and */ /* has already been assigned a slot that can be reused. */ /* ((LA_BASE[STATE] != OMEGA) signals this condition.) */ /* NOTE that look-ahead follow sets are shared only when the maximum */ /* look-ahead level allowed is 1 and single productions will not be */ /* removed. If either (or both) of these conditions is true, we need */ /* to have a unique slot assigned to each pair [S, A] (where S is a */ /* state, and A is a non-terminal) in the automaton. */ /*********************************************************************/ go_to = statset[state_no].go_to; state = GOTO_ACTION(go_to, goto_indx); if (state > 0) { if (la_base[state] != OMEGA && lalr_level == 1 && (! single_productions_bit)) { GOTO_LAPTR(go_to, goto_indx) = la_base[state]; return; } r = statset[state].kernel_items; } else r = adequate_item[-state]; /***********************************************************************/ /* At this point, R points to a list of items which are the successors */ /* of the items needed to initialize the Look-ahead follow sets. If */ /* anyone of these items contains EMPTY, we trace the Digraph for other*/ /* look-ahead follow sets that may be needed, and signal this fact */ /* using the variable CONTAINS_EMPTY. */ /***********************************************************************/ la_top++; /* allocate new slot */ INT_CHECK(la_top); GOTO_LAPTR(go_to, goto_indx) = la_top; contains_empty = FALSE; for (; r != NULL; r = r -> next) { item = r -> value - 1; if (IS_IN_SET(first, item_table[item].suffix_index, empty)) { contains_empty = TRUE; symbol = rules[item_table[item].rule_number].lhs; w = lpgaccess(state_no, item); for (t = w; t != NULL; p = t, t = t -> next) { struct goto_header_type go_to; go_to = statset[t -> value].go_to; for (i = 1; GOTO_SYMBOL(go_to, i) != symbol; i++) ; if (GOTO_LAPTR(go_to, i) == OMEGA) trace_lalr_path(t -> value, i); } free_nodes(w, p); } } /********************************************************************/ /* If the look-ahead follow set involved does not contain EMPTY, we */ /* mark the state involved (STATE) so that other look-ahead follow */ /* sets which may need this set may reuse the same one. */ /* NOTE that if CONTAINS_EMPTY is false, then STATE has to denote a */ /* state number (positive value) and not a rule number (negative). */ /********************************************************************/ if (! contains_empty) la_base[state] = GOTO_LAPTR(go_to, goto_indx); return; } /*****************************************************************************/ /* COMPUTE_READ: */ /*****************************************************************************/ /* COMPUTE_READ computes the number of intermediate look-ahead sets that */ /* will be needed (in LA_TOP), allocates space for the sets(LA_SET), and */ /* initializes them. */ /* By intermediate look-ahead set, we mean the set of terminals that may */ /* follow a non-terminal in a given state. */ /* These sets are initialized to the set of terminals that can immediately */ /* follow the non-terminal in the state to which it can shift (READ set). */ /*****************************************************************************/ static void compute_read(void) { int state_no, item_no, rule_no, lhs_symbol, state, i, j, la_ptr; struct node *p, *q, *s, *v; if (lalr_level > 1 || single_productions_bit) { read_set = (SET_PTR) calloc(num_states + 1, sizeof(BOOLEAN_CELL) * term_set_size); if (read_set == NULL) nospace(__FILE__, __LINE__); } /************************************************************************/ /* We traverse all the states and for all complete items that requires */ /* a look-ahead set, we retrace the state digraph (with the help of the */ /* routine TRACE_LALR_PATH) and assign a unique number to all look-ahead*/ /* follow sets that it needs. A look-ahead follow set is a set of */ /* terminal symbols associated with a pair [S, A], where S is a state, */ /* and A is a non-terminal: */ /* */ /* [S, A] --> Follow-set */ /* Follow-set = {t | t is a terminal that can be shifted on after */ /* execution of a goto action on A in state S}. */ /* */ /* Each follow set is initialized with the set of terminals that can be */ /* shifted on in state S2, where GOTO(S, A) = S2. After initialization */ /* a follow set F that does not contain the special terminal symbol */ /* EMPTY is marked with the help of the array LA_BASE, and if the */ /* highest level of look-ahead allowed is 1, then only one such set is */ /* allocated, and shared for all pairs (S, B) whose follow set is F. */ /************************************************************************/ la_top = 0; la_base = (int *) calloc(num_states + 1, sizeof(int)); if (la_base == NULL) nospace(__FILE__, __LINE__); for ALL_STATES(i) la_base[i] = OMEGA; for ALL_STATES(state_no) { for (p = ((lalr_level <= 1 && single_complete_item[state_no]) ? NULL : statset[state_no].complete_items); p != NULL; p = p -> next) { item_no = p -> value; rule_no = item_table[item_no].rule_number; lhs_symbol = rules[rule_no].lhs; if (lhs_symbol != accept_image) { v = lpgaccess(state_no, item_no); for (s = v; s != NULL; q = s, s = s -> next) { struct goto_header_type go_to; go_to = statset[s -> value].go_to; for (i = 1; GOTO_SYMBOL(go_to, i) != lhs_symbol; i++) ; if (GOTO_LAPTR(go_to, i) == OMEGA) trace_lalr_path(s -> value, i); } free_nodes(v, q); } } /***********************************************************************/ /* If the look-ahead level is greater than 1 or single productions */ /* actions are to be removed when possible, then we have to compute */ /* a Follow-set for all pairs [S, A] in the state automaton. Therefore,*/ /* we also have to consider Shift-reduce actions as reductions, and */ /* trace back to their roots as well. */ /* Note that this is not necessary for Goto-reduce actions. Since */ /* they terminate with a non-terminal, and that non-terminal is */ /* followed by the empty string, and we know that it must produce a */ /* rule that either ends up in a reduction, a shift-reduce, or another */ /* goto-reduce. It will therefore be taken care of automatically by */ /* transitive closure. */ /***********************************************************************/ if (lalr_level > 1 || single_productions_bit) { struct shift_header_type sh; struct goto_header_type go_to; sh = shift[statset[state_no].shift_number]; for (j = 1; j <= sh.size; j++) { if (SHIFT_ACTION(sh, j) < 0) { rule_no = - SHIFT_ACTION(sh, j); lhs_symbol = rules[rule_no].lhs; item_no = adequate_item[rule_no] -> value - 1; v = lpgaccess(state_no, item_no); for (s = v; s != NULL; q = s, s = s -> next) { go_to = statset[s -> value].go_to; for (i = 1; GOTO_SYMBOL(go_to, i) != lhs_symbol; i++) ; if (GOTO_LAPTR(go_to, i) == OMEGA) trace_lalr_path(s -> value, i); } free_nodes(v, q); } } /*******************************************************************/ /* We also need to compute the set of terminal symbols that can be */ /* read in a state entered via a terminal transition. */ /*******************************************************************/ if (lalr_level > 1 && state_no != 1) { q = statset[state_no].kernel_items; item_no = q -> value - 1; if (item_table[item_no].symbol IS_A_TERMINAL) { ASSIGN_SET(read_set, state_no, first, item_table[item_no].suffix_index); for (q = q -> next; q != NULL; q = q -> next) { item_no = q -> value - 1; SET_UNION(read_set, state_no, first, item_table[item_no].suffix_index); } } } } } /*********************************************************************/ /* We now allocate space for LA_INDEX and LA_SET, and initialize */ /* all its elements as indicated in reduce.h. The array LA_BASE is */ /* used to keep track of Follow sets that have been initialized. If */ /* another set needs to be initialized with a value that has been */ /* already computed, LA_BASE is used to retrieve the value. */ /*********************************************************************/ for ALL_STATES(i) la_base[i] = OMEGA; la_index = Allocate_short_array(la_top + 1); la_set = (SET_PTR) calloc(la_top + 1, term_set_size * sizeof(BOOLEAN_CELL)); if (la_set == NULL) nospace(__FILE__, __LINE__); for ALL_STATES(state_no) { struct goto_header_type go_to; go_to = statset[state_no].go_to; for (i = 1; i <= go_to.size; i++) { la_ptr = GOTO_LAPTR(go_to, i); if (la_ptr != OMEGA) /* Follow Look-ahead needed */ { state = GOTO_ACTION(go_to, i); if (state > 0) { if (la_base[state] != OMEGA) /* already computed */ { la_index[la_ptr] = la_index[la_base[state]]; ASSIGN_SET(la_set, la_ptr, la_set, la_base[state]); q = NULL; } else { la_base[state] = la_ptr; q = statset[state].kernel_items; } } else q = adequate_item[-state]; if (q != NULL) { item_no = q -> value - 1; /* initialize with first item */ ASSIGN_SET(la_set, la_ptr, first, item_table[item_no].suffix_index); for (q = q -> next; q != NULL; q = q -> next) { item_no = q -> value - 1; SET_UNION(la_set, la_ptr, first, item_table[item_no].suffix_index); } if (IS_IN_SET(la_set, la_ptr, empty)) la_index[la_ptr] = OMEGA; else la_index[la_ptr] = INFINITY; if (lalr_level > 1 || single_productions_bit) { if(state > 0) { ASSIGN_SET(read_set, state, la_set, la_ptr); } } } } } } ffree(la_base); return; } /*****************************************************************************/ /* LA_TRAVERSE: */ /*****************************************************************************/ /* LA_TRAVERSE takes two major arguments: STATE_NO, and an index (GOTO_INDX) */ /* that points to the GOTO_ELEMENT array in STATE_NO for the non-terminal */ /* left hand side of an item for which look-ahead is to be computed. The */ /* look-ahead of an item of the form [x. A y] in state STATE_NO is the set */ /* of terminals that can appear immediately after A in the context summarized*/ /* by STATE_NO. When a look-ahead set is computed, the result is placed in */ /* an allocation of LA_ELEMENT pointed to by the LA_PTR field of the */ /* GOTO_ELEMENT array. */ /* */ /* The same digraph algorithm used in MKFIRST is used for this computation. */ /* */ /*****************************************************************************/ void la_traverse(int state_no, int goto_indx, int *stack_top) { int indx; int symbol, item, state, i, la_ptr; struct goto_header_type go_to; struct node *r, *s, *t, *w; go_to = statset[state_no].go_to; la_ptr = GOTO_LAPTR(go_to, goto_indx); s = Allocate_node(); /* Push LA_PTR down the stack */ s -> value = la_ptr; s -> next = stack_root; stack_root = s; indx = ++(*stack_top); /* one element was pushed into the stack */ la_index[la_ptr] = indx; /**********************************************************************/ /* Compute STATE, action to perform on Goto symbol in question. If */ /* STATE is positive, it denotes a state to which to shift. If it is */ /* negative, it is a rule on which to perform a Goto-Reduce. */ /**********************************************************************/ state = GOTO_ACTION(go_to, goto_indx); if (state > 0) /* Not a Goto-Reduce action */ r = statset[state].kernel_items; else r = adequate_item[-state]; for (; r != NULL; r = r -> next) { /* loop over items [A -> x LHS_SYMBOL . y] */ item = r -> value - 1; if IS_IN_SET(first, item_table[item].suffix_index, empty) { symbol = rules[item_table[item].rule_number].lhs; w = lpgaccess(state_no, item); /* states where RULE was */ /* introduced through closure */ for (t = w; t != NULL; s = t, t = t -> next) { struct goto_header_type go_to; /**********************************************************/ /* Search for GOTO action in access-state after reducing */ /* RULE to its left hand side (SYMBOL). Q points to the */ /* GOTO_ELEMENT in question. */ /**********************************************************/ go_to = statset[t -> value].go_to; for (i = 1; GOTO_SYMBOL(go_to, i) != symbol; i++) ; if (la_index[GOTO_LAPTR(go_to, i)] == OMEGA) la_traverse(t -> value, i, stack_top); SET_UNION(la_set, la_ptr, la_set, GOTO_LAPTR(go_to, i)); la_index[la_ptr] = MIN(la_index[la_ptr], la_index[GOTO_LAPTR(go_to, i)]); } free_nodes(w, s); } } if (la_index[la_ptr] == indx) /* Top of a SCC */ { s = stack_root; for (i = stack_root -> value; i != la_ptr; stack_root = stack_root -> next, i = stack_root -> value) { ASSIGN_SET(la_set, i, la_set, la_ptr); la_index[i] = INFINITY; (*stack_top)--; /* one element was popped from the stack; */ } la_index[la_ptr] = INFINITY; r = stack_root; /* mark last element that is popped and ... */ stack_root = stack_root -> next; /* ... pop it! */ (*stack_top)--; /* one element was popped from the stack; */ free_nodes(s, r); } return; } /*****************************************************************************/ /* COMPUTE_LA: */ /*****************************************************************************/ /* COMPUTE_LA takes as argument a state number (STATE_NO), an item number */ /* (ITEM_NO), and a set (LOOK_AHEAD). It computes the look-ahead set of */ /* terminals for the given item in the given state and places the answer in */ /* the set LOOK_AHEAD. */ /*****************************************************************************/ void compute_la(int state_no, int item_no, SET_PTR look_ahead) { int lhs_symbol, i; struct node *r, *s, *v; stack_root = NULL; lhs_symbol = rules[item_table[item_no].rule_number].lhs; if (lhs_symbol == accept_image) { ASSIGN_SET(look_ahead, 0, first, item_table[item_no-1].suffix_index); return; } INIT_SET(look_ahead); /* initialize set */ v = lpgaccess(state_no, item_no); for (s = v; s != NULL; r = s, s = s -> next) { struct goto_header_type go_to; /*****************************************************************/ /* Search for GOTO action in Access-State after reducing rule to */ /* its left hand side(LHS_SYMBOL). Q points to the state. */ /*****************************************************************/ go_to = statset[s -> value].go_to; for (i = 1; GOTO_SYMBOL(go_to, i) != lhs_symbol; i++) ; /***********************************************************/ /* If look-ahead after left hand side is not yet computed, */ /* LA_TRAVERSE the graph to compute it. */ /***********************************************************/ if (la_index[GOTO_LAPTR(go_to, i)] == OMEGA) { int stack_top = 0; la_traverse(s -> value, i, &stack_top); } SET_UNION(look_ahead, 0, la_set, GOTO_LAPTR(go_to, i)); } RESET_BIT(look_ahead, empty); /* empty not valid look-ahead */ free_nodes(v, r); return; } /**********************************************************************/ /* BUILD_IN_STAT: */ /**********************************************************************/ /* We construct the IN_STAT map which is the inverse of the transition*/ /* map formed by GOTO and SHIFT maps. */ /* This map is implemented as a table of pointers that can be indexed */ /* by the states to a circular list of integers representing other */ /* states that contain transitions to the state in question. */ /**********************************************************************/ static void build_in_stat(void) { struct shift_header_type sh; struct goto_header_type go_to; struct node *q; int state_no, i, n; for ALL_STATES(state_no) { n = statset[state_no].shift_number; sh = shift[n]; for (i = 1; i <= sh.size; ++i) { n = SHIFT_ACTION(sh, i); if (n > 0 && n <= num_states) /* A shift action? */ { q = Allocate_node(); q -> value = state_no; if (in_stat[n] == NULL) q -> next = q; else { q -> next = in_stat[n] -> next; in_stat[n] -> next = q; } in_stat[n] = q; } } go_to = statset[state_no].go_to; for (i = 1; i <= go_to.size; i++) { n = GOTO_ACTION(go_to, i); if (n > 0) /* A goto action */ { q = Allocate_node(); q -> value = state_no; if (in_stat[n] == NULL) q -> next = q; else { q -> next = in_stat[n] -> next; in_stat[n] -> next = q; } in_stat[n] = q; } } } return; } /*****************************************************************************/ /* MKRDCTS: */ /*****************************************************************************/ /* MKRDCTS constructs the REDUCE map and detects conflicts in the grammar. */ /* When constructing an LALR parser, the subroutine COMPUTE_LA is invoked to */ /* compute the lalr look-ahead sets. For an SLR parser, the FOLLOW map */ /* computed earlier in the procedure MKFIRST is used. */ /* */ /* For a complete description of the lookahead algorithm used in this */ /* program, see Charles, PhD thesis, NYU 1991. */ /*****************************************************************************/ void mkrdcts(void) { short *symbol_list, *rule_count; int symbol_root, reduce_size, state_no, item_no, rule_no, symbol, default_rule, i, n; struct node **action; struct node *p, *q, *r, *item_ptr; BOOLEAN *no_shift_on_error_sym; SET_PTR look_ahead; /**********************************************************************/ /* Set up a pool of temporary space. If LALR(k), k > 1 is requested, */ /* INIT_LALRK_PROCESS sets up the necessary environment for the */ /* computation of multiple lookahead. */ /**********************************************************************/ reset_temporary_space(); init_lalrk_process(); /**********************************************************************/ /* IN_STAT is used to construct a reverse transition map. See */ /* BUILD_IN_STAT for more detail. */ /* */ /* RULE_COUNT is an array used to count the number of reductions on */ /* particular rules within a given state. */ /* */ /* NO_SHIFT_ON_ERROR_SYM is a vector used to identify states that */ /* contain shift actions on the %ERROR symbol. Such states are marked*/ /* only when DEFAULT_OPT is 5. */ /* */ /* SYMBOL_LIST is used to construct temporary lists of terminals on */ /* which reductions are defined. */ /* */ /* When default actions are requested, the vector SINGLE_COMPLETE_ITEM*/ /* is used to identify states that contain exactly one final item. */ /* NOTE that when the READ_REDUCE options is turned on, the LR(0) */ /* automaton constructed contains no such state. */ /* */ /* ACTION is an array that is used as the base for a mapping from */ /* each terminal symbol into a list of actions that can be executed */ /* on that symbol in a given state. */ /* */ /* LOOK_AHEAD is used to compute lookahead sets. */ /**********************************************************************/ in_stat = (struct node **) calloc(num_states + 1, sizeof(struct node *)); if (in_stat == NULL) nospace(__FILE__, __LINE__); rule_count = Allocate_short_array(num_rules + 1); no_shift_on_error_sym = Allocate_boolean_array(num_states + 1); symbol_list = Allocate_short_array(num_terminals + 1); single_complete_item = Allocate_boolean_array(num_states + 1); action = (struct node **) calloc(num_terminals + 1, sizeof(struct node *)); if (action == NULL) nospace(__FILE__, __LINE__); look_ahead = (SET_PTR) calloc(1, term_set_size * sizeof(BOOLEAN_CELL)); if (look_ahead == NULL) nospace(__FILE__, __LINE__); /****************************************************************/ /* If we will be removing single productions, we need to keep */ /* track of all (state, symbol) pairs on which a conflict is */ /* detected. The structure conflict_symbols is used as a base */ /* to construct that map. See ADD_CONFLICT_SYMBOL in resolve.c. */ /* NOTE that this allocation automatically initialized all */ /* elements of the conflict_symbols array to NULL. */ /****************************************************************/ if (single_productions_bit) { conflict_symbols = (struct node **) calloc(num_states + 1, sizeof(struct node *)); if (conflict_symbols == NULL) nospace(__FILE__, __LINE__); } /**********************************************************************/ /* First, construct the IN_STAT map. Next, iterate over the states to */ /* construct two boolean vectors. One indicates whether there is a */ /* shift action on the ERROR symbol when the DEFAULT_OPT is 5. The */ /* other indicates whether it is all right to take default action in */ /* states containing exactly one final item. */ /* */ /* We also check whether the grammar is LR(0). I.e., whether it needs */ /* any look-ahead at all. */ /**********************************************************************/ build_in_stat(); for ALL_STATES(state_no) { struct shift_header_type sh; no_shift_on_error_sym[state_no] = TRUE; if (default_opt == 5) { n = statset[state_no].shift_number; sh = shift[n]; for (i = 1; i <= sh.size; ++i) { if (SHIFT_SYMBOL(sh, i) == error_image) no_shift_on_error_sym[state_no] = FALSE; } } /**********************************************************************/ /* Compute whether this state is a final state. I.e., a state that */ /* contains only a single complete item. If so, mark it as a default */ /* state. Note that if the READ-REDUCE option is used, the automaton */ /* will not contain such states. Also, states are marked only when */ /* default actions are requested. */ /**********************************************************************/ item_ptr = statset[state_no].kernel_items; item_no = item_ptr -> value; single_complete_item[state_no] = ((! read_reduce_bit) && (! single_productions_bit) && (table_opt != OPTIMIZE_TIME) && (table_opt != OPTIMIZE_SPACE) && (default_opt > 0) && (item_ptr -> next == NULL) && (item_table[item_no].symbol == empty)); /**********************************************************************/ /* If a state has a complete item, and more than one kernel item */ /* which is different from the complete item, then this state */ /* requires look-ahead for the complete item. */ /**********************************************************************/ if (highest_level == 0) { r = statset[state_no].complete_items; if (r != NULL) { if (item_ptr -> next != NULL || item_ptr -> value != r -> value) highest_level = 1; } } } /****************************************************************/ /* We call COMPUTE_READ to perform the following tasks: */ /* 1) Count how many elements are needed in LA_ELEMENT: LA_TOP */ /* 2) Allocate space for and initialize LA_SET and LA_INDEX */ /****************************************************************/ if (! slr_bit) compute_read(); /****************************************************************/ /* Allocate space for REDUCE which will be used to map each */ /* into its reduce map. We also initialize RULE_COUNT which */ /* will be used to count the number of reduce actions on each */ /* rule with in a given state. */ /****************************************************************/ reduce = (struct reduce_header_type *) calloc(num_states + 1, sizeof(struct reduce_header_type)); if (reduce == NULL) nospace(__FILE__, __LINE__); for ALL_RULES(i) rule_count[i] = 0; /****************************************************************/ /* We are now ready to construct the reduce map. First, we */ /* initialize MAX_LA_STATE to NUM_STATES. If no lookahead */ /* state is added (the grammar is LALR(1)) this value will not */ /* change. Otherwise, MAX_LA_STATE is incremented by 1 for each */ /* lookahead state added. */ /****************************************************************/ max_la_state = num_states; /****************************************************************/ /* We iterate over the states, compute the lookahead sets, */ /* resolve conflicts (if multiple lookahead is requested) and/or*/ /* report the conflicts if requested... */ /****************************************************************/ for ALL_STATES(state_no) { struct reduce_header_type red; default_rule = OMEGA; symbol_root = NIL; item_ptr = statset[state_no].complete_items; if (item_ptr != NULL) { /**********************************************************************/ /* Check if it is possible to take default reduction. The DEFAULT_OPT */ /* parameter indicates what kind of default options are requested. */ /* The various values it can have are: */ /* */ /* a) 0 => no default reduction. */ /* b) 1 => default reduction only on adequate states. I.e., */ /* states with only one complete item in their kernel. */ /* c) 2 => Default on all states that contain exactly one */ /* complete item not derived from an empty rule. */ /* d) 3 => Default on all states that contain exactly one */ /* complete item including items from empty rules. */ /* e) 4 => Default reduction on all states that contain exactly */ /* one item. If a state contains more than one item we */ /* take Default on the item that generated the most */ /* reductions. If there is a tie, one is selected at */ /* random. */ /* f) 5 => Same as 4 except that no default actions are computed */ /* for states that contain a shift action on the ERROR */ /* symbol. */ /* */ /* In the code below, we first check for category 3. If it is not */ /* satisfied, then we check for the others. Note that in any case, */ /* default reductions are never taken on the ACCEPT rule. */ /* */ /**********************************************************************/ item_no = item_ptr -> value; rule_no = item_table[item_no].rule_number; symbol = rules[rule_no].lhs; if (single_complete_item[state_no] && symbol != accept_image) { default_rule = rule_no; item_ptr = NULL; /* No need to check for conflicts */ } /******************************************************************/ /* Iterate over all complete items in the state, build action */ /* map, and check for conflicts. */ /******************************************************************/ for (; item_ptr != NULL; item_ptr = item_ptr -> next) { /* for all complete items */ item_no = item_ptr -> value; rule_no = item_table[item_no].rule_number; if (slr_bit) /* SLR table? use Follow */ { ASSIGN_SET(look_ahead, 0, follow, rules[rule_no].lhs); } else compute_la(state_no, item_no, look_ahead); for ALL_TERMINALS(symbol) /* for all symbols in la set */ { if (IS_ELEMENT(look_ahead, symbol)) { p = Allocate_node(); p -> value = item_no; if (action[symbol] == NULL) { symbol_list[symbol] = symbol_root; symbol_root = symbol; } else { /**********************************************/ /* Always place the rule with the largest */ /* right-hand side first in the list. */ /**********************************************/ n = item_table[action[symbol] -> value].rule_number; if (RHS_SIZE(n) >= RHS_SIZE(rule_no)) { p -> value = action[symbol] -> value; action[symbol] -> value = item_no; } } p -> next = action[symbol]; action[symbol] = p; } } } /******************************************************************/ /* At this stage, we have constructed the ACTION map for STATE_NO.*/ /* ACTION is a map from each symbol into a set of final items. */ /* The rules associated with these items are the rules by which */ /* to reduce when the lookahead is the symbol in question. */ /* SYMBOL_LIST/SYMBOL_ROOT is a list of the non-empty elements of */ /* ACTION. If the number of elements in a set ACTION(t), for some */ /* terminal t, is greater than one or it is not empty and STATE_NO*/ /* contains a shift action on t then STATE_NO has one or more */ /* conflict(s). The procedure RESOLVE_CONFLICTS takes care of */ /* resolving the conflicts appropriately and returns an ACTION */ /* map where each element has either 0 (if the conflicts were */ /* shift-reduce conflicts, the shift is given precedence) or 1 */ /* element (if the conflicts were reduce-reduce conflicts, only */ /* the first element in the ACTION(t) list is returned). */ /******************************************************************/ if (symbol_root != NIL) { resolve_conflicts(state_no, action, symbol_list, symbol_root); for (symbol = symbol_root; symbol != NIL; symbol = symbol_list[symbol]) { if (action[symbol] != NULL) { item_no = action[symbol] -> value; rule_count[item_table[item_no].rule_number]++; } } } } /*********************************************************************/ /* We are now ready to compute the size of the reduce map for */ /* STATE_NO (reduce_size) and the default rule. */ /* If the state being processed contains only a single complete item */ /* then the DEFAULT_RULE was previously computed and the list of */ /* symbols is empty. */ /* NOTE: a REDUCE_ELEMENT will be allocated for all states, even */ /* those that have no reductions at all. This will facilitate the */ /* Table Compression routines, for they can assume that such an */ /* object exists, and can be used for Default values. */ /*********************************************************************/ reduce_size = 0; if (symbol_root != NIL) { /******************************************************************/ /* Compute REDUCE_SIZE, the number of reductions in the state and */ /* DEFAULT_RULE: the rule with the highest number of reductions */ /* to it. */ /******************************************************************/ n = 0; for (q = statset[state_no].complete_items; q != NULL; q = q -> next) { item_no = q -> value; rule_no = item_table[item_no].rule_number; symbol = rules[rule_no].lhs; reduce_size += rule_count[rule_no]; if ((rule_count[rule_no] > n) && (no_shift_on_error_sym[state_no]) && (symbol != accept_image)) { n = rule_count[rule_no]; default_rule = rule_no; } } /*********************************************************/ /* If the removal of single productions is requested */ /* and/or parsing tables will not be output, figure out */ /* if the level of the default option requested permits */ /* default actions, and compute how many reduce actions */ /* can be eliminated as a result. */ /*********************************************************/ if (default_opt == 0) default_rule = OMEGA; else if (table_opt != OPTIMIZE_TIME && table_opt != OPTIMIZE_SPACE && ! single_productions_bit) { q = statset[state_no].complete_items; if (q -> next == NULL) { item_no = q -> value; rule_no = item_table[item_no].rule_number; if (default_opt > 2 || /* No empty rule defined */ (default_opt == 2 && RHS_SIZE(rule_no) != 0)) reduce_size -= n; else default_rule = OMEGA; } else if (default_opt > 3) reduce_size -= n; } num_reductions += reduce_size; } /**************************************************************/ /* NOTE that the default fields are set for all states, */ /* whether or not DEFAULT actions are requested. This is */ /* all right since one can always check whether (DEFAULT > 0) */ /* before using these fields. */ /**************************************************************/ red = Allocate_reduce_map(reduce_size); reduce[state_no] = red; REDUCE_SYMBOL(red, 0) = DEFAULT_SYMBOL; REDUCE_RULE_NO(red, 0) = default_rule; for (symbol = symbol_root; symbol != NIL; symbol = symbol_list[symbol]) { if (action[symbol] != NULL) { rule_no = item_table[action[symbol] -> value].rule_number; if (rule_no != default_rule || table_opt == OPTIMIZE_SPACE || table_opt == OPTIMIZE_TIME || single_productions_bit) { REDUCE_SYMBOL(red, reduce_size) = symbol; REDUCE_RULE_NO(red, reduce_size) = rule_no; reduce_size--; } free_nodes(action[symbol], action[symbol]); action[symbol] = NULL; } } /************************************************************/ /* Reset RULE_COUNT elements used in this state. */ /************************************************************/ for (q = statset[state_no].complete_items; q != NULL; q = q -> next) { rule_no = item_table[q -> value].rule_number; rule_count[rule_no] = 0; } } /* end for ALL_STATES*/ printf("\n"); fprintf(syslis,"\n\n"); /****************************************************************/ /* If the automaton required multiple lookahead, construct the */ /* permanent lookahead states. */ /****************************************************************/ if (max_la_state > num_states) create_lastats(); /****************************************************************/ /* We are now finished with the LALR(k) construction of the */ /* automaton. Clear all temporary space that was used in that */ /* process and calculate the maximum lookahead level that was */ /* needed. */ /****************************************************************/ exit_lalrk_process(); free_conflict_space(); lalr_level = highest_level; /****************************************************************/ /* If the removal of single productions is requested, do that. */ /****************************************************************/ if (single_productions_bit) remove_single_productions(); /****************************************************************/ /* If either more than one lookahead was needed or the removal */ /* of single productions was requested, the automaton was */ /* transformed with the addition of new states and new */ /* transitions. In such a case, we reconstruct the IN_STAT map. */ /****************************************************************/ if (lalr_level > 1 || single_productions_bit) { for ALL_STATES(state_no) { /* First, clear out the previous map */ if (in_stat[state_no] != NULL) { q = in_stat[state_no] -> next; /* point to root */ free_nodes(q, in_stat[state_no]); in_stat[state_no] = NULL; } } build_in_stat(); /* rebuild in_stat map */ } /******************************************************************/ /* Print informational messages and free all temporary space that */ /* was used to compute lookahead information. */ /******************************************************************/ if (not_lrk) { printf("This grammar is not LR(K).\n"); fprintf(syslis,"This grammar is not LR(K).\n"); } else if (num_rr_conflicts > 0 || num_sr_conflicts > 0) { if (! slr_bit) { if (highest_level != INFINITY) { printf("This grammar is not LALR(%d).\n", highest_level); fprintf(syslis, "This grammar is not LALR(%d).\n", highest_level); } else { printf("This grammar is not LALR(K).\n"); fprintf(syslis,"This grammar is not LALR(K).\n"); } } else { printf("This grammar is not SLR(1).\n"); fprintf(syslis,"This grammar is not SLR(1).\n"); } } else { if (highest_level == 0) { printf("This grammar is LR(0).\n"); fprintf(syslis,"This grammar is LR(0).\n"); } else if (slr_bit) { printf("This grammar is SLR(1).\n"); fprintf(syslis,"This grammar is SLR(1).\n"); } else { printf("This grammar is LALR(%d).\n", highest_level); fprintf(syslis, "This grammar is LALR(%d).\n", highest_level); } } ffree(rule_count); ffree(no_shift_on_error_sym); ffree(symbol_list); ffree(single_complete_item); ffree(action); ffree(look_ahead); if (conflict_symbols != NULL) ffree(conflict_symbols); if (read_set != NULL) ffree(read_set); if (la_index != NULL) ffree(la_index); if (la_set != NULL) ffree(la_set); return; } /* end mkrdcts */ jikespg-1.3/src/mkstates.c000066400000000000000000000657451167345774400156420ustar00rootroot00000000000000/* $Id: mkstates.c,v 1.2 1999/11/04 14:02:23 shields Exp $ */ /* This software is subject to the terms of the IBM Jikes Compiler License Agreement available at the following URL: http://www.ibm.com/research/jikes. Copyright (C) 1983, 1999, International Business Machines Corporation and others. All Rights Reserved. You must accept the terms of that agreement to use this software. */ static char hostfile[] = __FILE__; #include "common.h" #include "header.h" static void mklr0(void); static struct state_element *lr0_state_map(struct node *kernel); /****************************************************************************/ /* STATE_ELEMENT is used to represent states. Each state is mapped into a */ /* unique number. The components QUEUE and LINK are auxiliary: */ /* QUEUE is used to form a sequential linked-list of the states ordered */ /* STATE_NUMBER and identified by the variable STATE_ROOT. */ /* LINK is used to resolve collisions in hashing the states. */ /* NEXT_SHIFT is used to resolve collisions in hashing SHIFT maps. */ /****************************************************************************/ struct state_element { struct state_element *link, *queue, *next_shift; struct node *kernel_items, *complete_items; struct shift_header_type lr0_shift; struct goto_header_type lr0_goto; short shift_number, state_number; }; static struct state_element **state_table, **shift_table, *state_root, *state_tail; static short *shift_action; static struct goto_header_type no_gotos_ptr; static struct shift_header_type no_shifts_ptr; /*****************************************************************************/ /* MKSTATS: */ /*****************************************************************************/ /* In this procedure, we first construct the LR(0) automaton. */ /*****************************************************************************/ void mkstats(void) { int j; no_gotos_ptr.size = 0; /* For states with no GOTOs */ no_gotos_ptr.map = NULL; no_shifts_ptr.size = 0; /* For states with no SHIFTs */ no_shifts_ptr.map = NULL; mklr0(); if (error_maps_bit && (table_opt == OPTIMIZE_TIME || table_opt == OPTIMIZE_SPACE)) produce(); /**********************************************************************/ /* Free space trapped by the CLOSURE and CLITEMS maps. */ /**********************************************************************/ for ALL_NON_TERMINALS(j) { struct node *p, *q; q = clitems[j]; if (q != NULL) { p = q -> next; free_nodes(p, q); } q = closure[j]; if (q != NULL) { p = q -> next; free_nodes(p, q); } } closure += (num_terminals + 1); ffree(closure); clitems += (num_terminals + 1); ffree(clitems); return; } /*****************************************************************************/ /* MKLR0: */ /*****************************************************************************/ /* This procedure constructs an LR(0) automaton. */ /*****************************************************************************/ static void mklr0(void) { /*****************************************************************/ /* STATE_TABLE is the array used to hash the states. States are */ /* identified by their Kernel set of items. Hash locations are */ /* computed for the states. As states are inserted in the table, */ /* they are threaded together via the QUEUE component of */ /* STATE_ELEMENT. The variable STATE_ROOT points to the root of */ /* the thread, and the variable STATE_TAIL points to the tail. */ /* */ /* After constructing a state, Shift and Goto actions are */ /* defined on that state based on a partition of the set of items*/ /* in that state. The partitioning is based on the symbols */ /* following the dot in the items. The array PARTITION is used */ /* for that partitioning. LIST and ROOT are used to construct */ /* temporary lists of symbols in a state on which Shift or Goto */ /* actions are defined. */ /* NT_LIST and NT_ROOT are used to build temporary lists of */ /* non-terminals. */ /*****************************************************************/ struct node *p, *q, *r, *new_item, *tail, *item_ptr, **partition, *closure_root, *closure_tail; struct state_element *state, *new_state; BOOLEAN end_node; int goto_size, shift_size, i, state_no, next_item_no, item_no, symbol, rule_no, shift_root, nt_root, root; struct goto_header_type go_to; short *shift_list, *nt_list, *list; /******************************************************************/ /* Set up a a pool of temporary space. */ /******************************************************************/ reset_temporary_space(); list = Allocate_short_array(num_symbols + 1); shift_action = Allocate_short_array(num_terminals + 1); shift_list = Allocate_short_array(num_terminals + 1); nt_list = Allocate_short_array(num_non_terminals); nt_list -= (num_terminals + 1); partition = (struct node **) calloc(num_symbols + 1, sizeof(struct node *)); if (partition == NULL) nospace(__FILE__, __LINE__); state_table = (struct state_element **) calloc(STATE_TABLE_SIZE, sizeof(struct state_element *)); if (state_table == NULL) nospace(__FILE__, __LINE__); shift_table = (struct state_element **) calloc(SHIFT_TABLE_SIZE, sizeof(struct state_element *)); if (shift_table == NULL) nospace(__FILE__, __LINE__); /* INITIALIZATION -----------------------------------------------------------*/ goto_size = 0; shift_size = 0; state_root = NULL; for (i = 0; i <= num_terminals; i++) shift_action[i] = OMEGA; nt_root = NIL; for ALL_NON_TERMINALS(i) nt_list[i] = OMEGA; /* PARTITION, STATE_TABLE and SHIFT_TABLE are initialized by calloc */ /* END OF INITIALIZATION ----------------------------------------------------*/ /*****************************************************************/ /* Kernel of the first state consists of the first items in each */ /* rule produced by Accept non-terminal. */ /*****************************************************************/ q = NULL; for (end_node = ((p = clitems[accept_image]) == NULL); ! end_node; /* Loop over circular list */ end_node = (p == clitems[accept_image])) { p = p -> next; new_item = Allocate_node(); new_item -> value = p -> value; new_item -> next = q; q = new_item; } /*****************************************************************/ /* Insert first state in STATE_TABLE and keep constructing states*/ /* until we no longer can. */ /*****************************************************************/ for (state = lr0_state_map(q); /* insert initial state */ state != NULL; /* and process next state until no more */ state = state -> queue) { /******************************************************************/ /* Now we construct a list of all non-terminals that can be */ /* introduced in this state through closure. The CLOSURE of each */ /* non-terminal has been previously computed in MKFIRST. */ /******************************************************************/ for (q = state -> kernel_items; q != NULL; /* iterate over kernel set of items */ q = q -> next) { item_no = q -> value; symbol = item_table[item_no].symbol; /* symbol after dot */ if (symbol IS_A_NON_TERMINAL) /* Dot symbol */ { if (nt_list[symbol] == OMEGA) /* not yet seen */ { nt_list[symbol] = nt_root; nt_root = symbol; for (end_node = ((p = closure[symbol]) == NULL); ! end_node; /* Loop over circular list */ end_node = (p == closure[symbol])) { /* add its closure to list */ p = p -> next; if (nt_list[p -> value] == OMEGA) { nt_list[p -> value] = nt_root; nt_root = p -> value; } } } } } /*******************************************************************/ /* We now construct lists of all start items that the closure */ /* non-terminals produce. A map from each non-terminal to its set */ /* start items has previously been computed in MKFIRST. (CLITEMS) */ /* Empty items are placed directly in the state, whereas non_empty */ /* items are placed in a temporary list rooted at CLOSURE_ROOT. */ /*******************************************************************/ closure_root = NULL; /* used to construct list of closure items */ for (symbol = nt_root; symbol != NIL; nt_list[symbol] = OMEGA, symbol = nt_root) { nt_root = nt_list[symbol]; for (end_node = ((p = clitems[symbol]) == NULL); ! end_node; /* Loop over circular list */ end_node = (p == clitems[symbol])) { p = p -> next; item_no = p -> value; new_item = Allocate_node(); new_item -> value = item_no; if (item_table[item_no].symbol == empty) /* complete item */ { /* Add to COMPLETE_ITEMS set in state */ new_item -> next = state -> complete_items; state -> complete_items = new_item; } else { /* closure item, add to closure list */ if (closure_root == NULL) closure_root = new_item; else closure_tail -> next = new_item; closure_tail = new_item; } } } if (closure_root != NULL) /* any non-complete closure items? */ { /* construct list of them and kernel items */ closure_tail -> next = state -> kernel_items; item_ptr = closure_root; } else /* else just consider kernel items */ item_ptr = state -> kernel_items; /*******************************************************************/ /* In this loop, the PARTITION map is constructed. At this point,*/ /* ITEM_PTR points to all the non_complete items in the closure of */ /* the state, plus all the kernel items. We note that the kernel */ /* items may still contain complete-items, and if any is found, the*/ /* COMPLETE_ITEMS list is updated. */ /*******************************************************************/ root = NIL; for (; item_ptr != NULL; item_ptr = item_ptr -> next) { item_no = item_ptr -> value; symbol = item_table[item_no].symbol; if (symbol != empty) /* incomplete item */ { next_item_no = item_no + 1; if (partition[symbol] == NULL) { /* PARTITION not defined on symbol */ list[symbol] = root; /* add to list */ root = symbol; if (symbol IS_A_TERMINAL) /* Update transition count */ shift_size++; else goto_size++; } for (p = partition[symbol]; p != NULL; tail = p, p = p -> next) { if (p -> value > next_item_no) break; } r = Allocate_node(); r -> value = next_item_no; r -> next = p; if (p == partition[symbol]) /* Insert at beginning */ partition[symbol] = r; else tail -> next = r; } else /* Update complete item set with item from kernel */ { p = Allocate_node(); p -> value = item_no; p -> next = state -> complete_items; state -> complete_items = p; } } if (closure_root != NULL) free_nodes(closure_root, closure_tail); /*******************************************************************/ /* We now iterate over the set of partitions and update the state */ /* automaton and the transition maps: SHIFT and GOTO. Each */ /* partition represents the kernel of a state. */ /*******************************************************************/ if (goto_size > 0) { go_to = Allocate_goto_map(goto_size); state -> lr0_goto = go_to; } else state -> lr0_goto = no_gotos_ptr; shift_root = NIL; for (symbol = root; symbol != NIL; /* symbols on which transition is defined */ symbol = list[symbol]) { short action = OMEGA; /*****************************************************************/ /* If the partition contains only one item, and it is adequate */ /* (i.e. the dot immediately follows the last symbol), and */ /* READ-REDUCE is requested, a new state is not created, and the */ /* action is marked as a Shift-reduce or a Goto-reduce. Otherwise*/ /* if a state with that kernel set does not yet exist, we create */ /* it. */ /*****************************************************************/ q = partition[symbol]; /* kernel of a new state */ if (read_reduce_bit && q -> next == NULL) { item_no = q -> value; if (item_table[item_no].symbol == empty) { rule_no = item_table[item_no].rule_number; if (rules[rule_no].lhs != accept_image) { action = -rule_no; free_nodes(q, q); } } } if (action == OMEGA) /* Not a Read-Reduce action */ { new_state = lr0_state_map(q); action = new_state -> state_number; } /****************************************************************/ /* At this stage, the partition list has been freed (for an old */ /* state or an ADEQUATE item), or used (for a new state). The */ /* PARTITION field involved should be reset. */ /****************************************************************/ partition[symbol] = NULL; /* To be reused */ /*****************************************************************/ /* At this point, ACTION contains the value of the state to Shift*/ /* to, or rule to Read-Reduce on. If the symbol involved is a */ /* terminal, we update the Shift map; else, it is a non-terminal */ /* and we update the Goto map. */ /* Shift maps are constructed temporarily in SHIFT_ACTION. */ /* Later, they are inserted into a map of unique Shift maps, and */ /* shared by states that contain identical shifts. */ /* Since the lookahead set computation is based on the GOTO maps,*/ /* all these maps and their element maps should be kept as */ /* separate entities. */ /*****************************************************************/ if (symbol IS_A_TERMINAL) /* terminal? add to SHIFT map */ { shift_action[symbol] = action; shift_list[symbol] = shift_root; shift_root = symbol; if (action > 0) num_shifts++; else num_shift_reduces++; } /*****************************************************************/ /* NOTE that for Goto's we update the field LA_PTR of GOTO. This */ /* field will be used later in the routine MKRDCTS to point to a */ /* look-ahead set. */ /*****************************************************************/ else { GOTO_SYMBOL(go_to, goto_size) = symbol; /* symbol field */ GOTO_ACTION(go_to, goto_size) = action; /* state field */ GOTO_LAPTR(go_to, goto_size) = OMEGA; /* la_ptr field */ goto_size--; if (action > 0) num_gotos++; else num_goto_reduces++; } } /*******************************************************************/ /* We are now going to update the set of Shift-maps. Ths idea is */ /* to do a look-up in a hash table based on SHIFT_TABLE to see if */ /* the Shift map associated with the current state has already been*/ /* computed. If it has, we simply update the SHIFT_NUMBER and the */ /* SHIFT field of the current state. Otherwise, we allocate and */ /* construct a SHIFT_ELEMENT map, update the current state, and */ /* add it to the set of Shift maps in the hash table. */ /* Note that the SHIFT_NUMBER field in the STATE_ELEMENTs could */ /* have been factored out and associated instead with the */ /* SHIFT_ELEMENTs. That would have saved some space, but only in */ /* the short run. This field was purposely stored in the */ /* STATE_ELEMENTs, because once the states have been constructed, */ /* they are not kept, whereas the SHIFT_ELEMENTs are kept. */ /* One could have also threaded through the states that contain */ /* original shift maps so as to avoid duplicate assignments in */ /* creating the SHIFT map later. However, this would have */ /* increased the storage requirement, and would probably have saved*/ /* (at most) a totally insignificant amount of time. */ /*******************************************************************/ update_shift_maps: { unsigned long hash_address; struct shift_header_type sh; struct state_element *p; hash_address = shift_size; for (symbol = shift_root; symbol != NIL; symbol = shift_list[symbol]) { hash_address += ABS(shift_action[symbol]); } hash_address %= SHIFT_TABLE_SIZE; for (p = shift_table[hash_address]; p != NULL; /* Search has table for shift map */ p = p -> next_shift) { sh = p -> lr0_shift; if (sh.size == shift_size) { for (i = 1; i <= shift_size; i++) /* Compare shift maps */ { if (SHIFT_ACTION(sh, i) != shift_action[SHIFT_SYMBOL(sh, i)]) break; } if (i > shift_size) /* Are they equal ? */ { state -> lr0_shift = sh; state -> shift_number = p -> shift_number; for (symbol = shift_root; symbol != NIL; symbol = shift_list[symbol]) { /* Clear SHIFT_ACTION */ shift_action[symbol] = OMEGA; } shift_size = 0; /* Reset for next round */ goto leave_update_shift_maps; } } } if (shift_size > 0) { sh = Allocate_shift_map(shift_size); num_shift_maps++; state -> shift_number = num_shift_maps; } else { state -> shift_number = 0; sh = no_shifts_ptr; } state -> lr0_shift = sh; state -> next_shift = shift_table[hash_address]; shift_table[hash_address] = state; for (symbol = shift_root; symbol != NIL; symbol = shift_list[symbol]) { SHIFT_SYMBOL(sh, shift_size) = symbol; SHIFT_ACTION(sh, shift_size) = shift_action[symbol]; shift_action[symbol] = OMEGA; shift_size--; } } /*end update_shift_maps */ leave_update_shift_maps:; } /*********************************************************************/ /* Construct STATSET, a "compact" and final representation of */ /* State table, and SHIFT which is a set of all shift maps needed. */ /* NOTE that assignments to elements of SHIFT may occur more than */ /* once, but that's ok. It is probably faster to do that than to */ /* set up an elaborate scheme to avoid the multiple assignment which */ /* may in fact cost more. Look at it this way: it is only a pointer */ /* assignment, namely a Load and a Store. */ /* Release all NODEs used by the maps CLITEMS and CLOSURE. */ /*********************************************************************/ { struct state_element *p; /*********************************************************************/ /* If the grammar is LALR(k), k > 1, more states may be added and */ /* the size of the shift map increased. */ /*********************************************************************/ shift = (struct shift_header_type *) calloc(num_states + 1, sizeof(struct shift_header_type)); if (shift == NULL) nospace(__FILE__, __LINE__); shift[0] = no_shifts_ptr; /* MUST be initialized for LALR(k) */ statset = (struct statset_type *) calloc(num_states + 1, sizeof(struct statset_type)); if (statset == NULL) nospace(__FILE__, __LINE__); for (p = state_root; p != NULL; p = p -> queue) { state_no = p -> state_number; statset[state_no].kernel_items = p -> kernel_items; statset[state_no].complete_items = p -> complete_items; shift[p -> shift_number] = p -> lr0_shift; statset[state_no].shift_number = p -> shift_number; statset[state_no].go_to = p -> lr0_goto; } } ffree(list); ffree(shift_action); ffree(shift_list); nt_list += (num_terminals + 1); ffree(nt_list); ffree(partition); ffree(state_table); ffree(shift_table); return; } /*****************************************************************************/ /* LR0_STATE_MAP: */ /*****************************************************************************/ /* LR0_STATE_MAP takes as an argument a pointer to a kernel set of items. If */ /* no state based on that kernel set already exists, then a new one is */ /* created and added to STATE_TABLE. In any case, a pointer to the STATE of */ /* the KERNEL is returned. */ /*****************************************************************************/ static struct state_element *lr0_state_map(struct node *kernel) { unsigned long hash_address = 0; struct node *p; struct state_element *state_ptr, *ptr; /*********************************************/ /* Compute the hash address. */ /*********************************************/ for (p = kernel; p != NULL; p = p -> next) { hash_address += p -> value; } hash_address %= STATE_TABLE_SIZE; /*************************************************************************/ /* Check whether a state is already defined by the KERNEL set. */ /*************************************************************************/ for (state_ptr = state_table[hash_address]; state_ptr != NULL; state_ptr = state_ptr -> link) { struct node *q, *r; for (p = state_ptr -> kernel_items, q = kernel; p != NULL && q != NULL; p = p -> next, r = q, q = q -> next) { if (p -> value != q -> value) break; } if (p == q) /* Both P and Q are NULL? */ { free_nodes(kernel, r); return(state_ptr); } } /*******************************************************************/ /* Add a new state based on the KERNEL set. */ /*******************************************************************/ ptr = (struct state_element *) talloc(sizeof(struct state_element)); if (ptr == (struct state_element *) NULL) nospace(__FILE__, __LINE__); num_states++; SHORT_CHECK(num_states); ptr -> queue = NULL; ptr -> kernel_items = kernel; ptr -> complete_items = NULL; ptr -> state_number = num_states; ptr -> link = state_table[hash_address]; state_table[hash_address] = ptr; if (state_root == NULL) state_root = ptr; else state_tail -> queue = ptr; state_tail = ptr; return(ptr); } jikespg-1.3/src/partset.c000066400000000000000000000411411167345774400154510ustar00rootroot00000000000000/* $Id: partset.c,v 1.2 1999/11/04 14:02:23 shields Exp $ */ /* This software is subject to the terms of the IBM Jikes Compiler License Agreement available at the following URL: http://www.ibm.com/research/jikes. Copyright (C) 1983, 1999, International Business Machines Corporation and others. All Rights Reserved. You must accept the terms of that agreement to use this software. */ static char hostfile[] = __FILE__; #include "common.h" #include "header.h" #define B_ASSIGN_SET(s1, dest, s2, source, bound) \ { int j; \ for (j = 0; j < bound; j++) \ s1[dest * bound + j] = s2[source * bound + j]; \ } #define B_SET_UNION(s1, dest, s2, source, bound) \ { int j; \ for (j = 0; j < bound; j++) \ s1[dest * bound + j] |= s2[source * bound + j]; \ } static BOOLEAN equal_sets(SET_PTR set1, int indx1, SET_PTR set2, int indx2, int bound); /*********************************************************************/ /* PARTSET: */ /*********************************************************************/ /* This procedure, PARTSET, is invoked to apply a heuristic of the */ /* Optimal Partitioning algorithm to a COLLECTION of subsets. The */ /* size of each subset in COLLECTION is passed in a parallel vector: */ /* ELEMENT_SIZE. Let SET_SIZE be the length of the bit_strings used */ /* to represent the subsets in COLLECTION, the universe of the */ /* subsets is the set of integers: [1..SET_SIZE]. */ /* The third argument, LIST, is a vector identifying the order in */ /* which the subsets in COLLECTION must be processed when they are */ /* output. */ /* The last two arguments, START and STACK are output parameters. */ /* We recall that the output of Optimal Partitioning is two vectors: */ /* a BASE vector and a RANGE vector... START is the base vector. */ /* It is used to indicate the starting position in the range */ /* vector for each subset. When a subset shares elements with */ /* another subset, this is indicated by in index in START being */ /* negative. START also contains an extra "fence" element. I.e., */ /* it has one more element than COLLECTION. */ /* STACK is a vector used to construct a partition of the elements */ /* of COLLECTION. That partition is used later (in ctabs or tabutil) */ /* to output the final range vector... */ /* */ /*********************************************************************/ /* */ /* We first merge all sets that are identical. A hash table is used */ /* to keep track of subsets that have already been seen. */ /* DOMAIN_TABLE is used as the base of the hash table. DOMAIN_LINK */ /* is used to link subsets that collided. */ /* */ /* The next step is to partition the unique subsets in the hash */ /* table based on the number of elements they contain. The vector */ /* PARTITION is used for that purpose. */ /* */ /* Finally, we attempt to overlay as many subsets as possible by */ /* performing the following steps: */ /* */ /* 1) Choose a base set in the partition with the largest subsets */ /* and push it into a stack. (using the vector STACK) */ /* */ /* 2) Iterate over the remaining non_empty elements of the partitions*/ /* in decreasing order of the size of the subsets contained in the*/ /* element in question. If there exists a subset in the element */ /* which is a subset of the subset on top of the stack, currently */ /* being constructed, remove it from the partition, and push it */ /* into the stack. Repeat step 2 until the partition is empty. */ /* */ /*********************************************************************/ void partset(SET_PTR collection, short *element_size, short *list, short *start, short *stack, int set_size) { unsigned long hash_address; int collection_size, offset, i, previous, base_set, size_root, next_size, size, bctype, j, index, subset; short domain_table[STATE_TABLE_SIZE], *domain_link, *size_list, *partition, *next, *head; BOOLEAN *is_a_base; SET_PTR temp_set; collection_size = num_states; if (set_size == num_terminals) { bctype = term_set_size; collection_size = num_states; } else if (set_size == num_non_terminals) { bctype = non_term_set_size; collection_size = num_states; } else /* called from scope processing */ { bctype = num_states / SIZEOF_BC + (num_states % SIZEOF_BC ? 1 : 0); collection_size = set_size; set_size = num_states; } size_list = Allocate_short_array(set_size + 1); partition = Allocate_short_array(set_size + 1); domain_link = Allocate_short_array(collection_size + 1); head = Allocate_short_array(collection_size + 1); next = Allocate_short_array(collection_size + 1); is_a_base = Allocate_boolean_array(collection_size + 1); temp_set = (SET_PTR) calloc(1, bctype * sizeof(BOOLEAN_CELL)); if (temp_set == NULL) nospace(__FILE__, __LINE__); /********************************************************************/ /* DOMAIN_TABLE is the base of a hash table used to compute the set */ /* of unique subsets in COLLECTION. Collisions are resolved by links*/ /* which are implemented in DOMAIN_LINK. */ /* HEAD is an array containing either the value OMEGA which */ /* indicates that the corresponding subset in COLLECTION is */ /* identical to another set, or it contains the "root" of a list of */ /* subsets that are identical. The elements of the list are placed */ /* in the array NEXT. When a state is at te root of a list, it is */ /* used as a representative of that list. */ /********************************************************************/ for (i = 0; i <= STATE_TABLE_UBOUND; i++) domain_table[i] = NIL; /*************************************************************/ /* We now iterate over the states and attempt to insert each */ /* domain set into the hash table... */ /*************************************************************/ for (index = 1; index <= collection_size; index++) { hash_address = 0; for (i = 0; i < bctype; i++) hash_address += collection[index * bctype + i]; hash_address %= STATE_TABLE_SIZE; /***************************************************************/ /* Next, we search the hash table to see if the subset was */ /* already inserted in it. If we find such a subset, we simply */ /* add INDEX to a list associated with the subset found and */ /* mark it as a duplicate by setting the head of its list to */ /* OMEGA. Otherwise, we have a new set... */ /***************************************************************/ for (i = domain_table[hash_address]; i != NIL; i = domain_link[i]) { if (equal_sets(collection, index, collection, i, bctype)) { head[index] = OMEGA; next[index] = head[i]; head[i] = index; goto continu; } } /*************************************************************/ /* ...Subset indicated by INDEX not previously seen. Insert */ /* it into the hash table, and initialize a new list with it.*/ /*************************************************************/ domain_link[index] = domain_table[hash_address]; domain_table[hash_address] = index; head[index] = NIL; /* Start a new list */ continu: ; } /*************************************************************/ /* We now partition all the unique sets in the hash table */ /* based on the number of elements they contain... */ /* NEXT is also used to construct these lists. Recall that */ /* the unique elements are roots of lists. Hence, their */ /* corresponding HEAD elements are used, but their */ /* corresponding NEXT field is still unused. */ /*************************************************************/ for (i = 0; i <= set_size; i++) partition[i] = NIL; for (index = 1; index <= collection_size; index++) { if (head[index] != OMEGA) /* Subset representative */ { size = element_size[index]; next[index] = partition[size]; partition[size] = index; } } /*************************************************************/ /* ...Construct a list of all the elements of PARTITION */ /* that are not empty. Only elements in this list will be */ /* considered for subset merging later ... */ /* Note that since the elements of PARTITION are added to */ /* the list in ascending order and in stack-fashion, the */ /* resulting list will be sorted in descending order. */ /*************************************************************/ size_root = NIL; for (i = 0; i <= set_size; i++) { if (partition[i] != NIL) { size_list[i] = size_root; size_root = i; } } /*************************************************************/ /* Merge subsets that are mergeable using heuristic described*/ /* above. The vector IS_A_BASE is used to mark subsets */ /* chosen as bases. */ /*************************************************************/ for (i = 0; i <= collection_size; i++) is_a_base[i] = FALSE; for (size = size_root; size != NIL; size = size_list[size]) { /* For biggest partition there is */ for (base_set = partition[size]; base_set != NIL; base_set = next[base_set]) { /* For each set in it... */ /*****************************************************/ /* Mark the state as a base state, and initialize */ /* its stack. The list representing the stack will */ /* be circular... */ /*****************************************************/ is_a_base[base_set] = TRUE; stack[base_set] = base_set; /**************************************************************/ /* For remaining elements in partitions in decreasing order...*/ /**************************************************************/ for (next_size = size_list[size]; next_size != NIL; next_size = size_list[next_size]) { previous = NIL; /* mark head of list */ /**************************************************/ /* Iterate over subsets in the partition until we */ /* find one that is a subset of the subset on top */ /* of the stack. If none is found, we go on to */ /* the next element of the partition. Otherwise, */ /* we push the new subset on top of the stack and */ /* go on to the next element of the partition. */ /* INDEX identifies the state currently on top */ /* of the stack. */ /**************************************************/ for (subset = partition[next_size]; subset != NIL; previous = subset, subset = next[subset]) { index = stack[base_set]; B_ASSIGN_SET(temp_set, 0, collection, index, bctype); B_SET_UNION(temp_set, 0, collection, subset, bctype); /* SUBSET is a subset of INDEX?*/ if (equal_sets(temp_set, 0, collection, index, bctype)) { if (previous == NIL) partition[next_size] = next[subset]; else next[previous] = next[subset]; stack[subset] = stack[base_set]; stack[base_set] = subset; break; /* for (subset = partition[next_size]... */ } } } } } /*************************************************************/ /* Iterate over the states in the order in which they are to */ /* be output, and assign an offset location to each state. */ /* Notice that an extra element is added to the size of each */ /* base subset for the "fence" element. */ /*************************************************************/ offset = 1; for (i= 1; i<= collection_size; i++) { base_set = list[i]; if (is_a_base[base_set]) { start[base_set] = offset; /***********************************************************/ /* Assign the same offset to each subset that is */ /* identical to the BASE_SET subset in question. Also, */ /* mark the fact that this is a copy by using the negative */ /* value of the OFFSET. */ /***********************************************************/ for (index = head[base_set]; index != NIL; index = next[index]) start[index] = - start[base_set]; size = element_size[base_set] + 1; offset += size; SHORT_CHECK(offset); /*********************************************************/ /* Now, assign offset values to each subset of the */ /* BASE_SET. Once again, we mark them as sharing elements*/ /* by using the negative value of the OFFSET. */ /* Recall that the stack is constructed as a circular */ /* list. Therefore, its end is reached when we go back */ /* to the root... In this case, the root is already */ /* processed, so we stop when we reach it. */ /*********************************************************/ for (index = stack[base_set]; index != base_set; index = stack[index]) { size = element_size[index] + 1; start[index] = -(offset - size); /*****************************************************/ /* INDEX identifies a subset of BASE_SET. Assign the */ /* same offset as INDEX to each subset j that is */ /* identical to the subset INDEX. */ /*****************************************************/ for (j = head[index]; j != NIL; j = next[j]) start[j] = start[index]; } } } start[collection_size+1] = offset; ffree(size_list); ffree(partition); ffree(domain_link); ffree(head); ffree(next); ffree(is_a_base); ffree(temp_set); return; } /****************************************************************************/ /* EQUAL_SETS: */ /****************************************************************************/ /* EQUAL_SETS checks to see if two sets are equal and returns True or False */ /****************************************************************************/ static BOOLEAN equal_sets(SET_PTR set1, int indx1, SET_PTR set2, int indx2, int bound) { register int i; for (i = 0; i < bound; i++) { if (set1[indx1 * bound + i] != set2[indx2 * bound + i]) return(0); } return(TRUE); } jikespg-1.3/src/prntstat.c000066400000000000000000000250501167345774400156470ustar00rootroot00000000000000/* $Id: prntstat.c,v 1.2 1999/11/04 14:02:23 shields Exp $ */ /* This software is subject to the terms of the IBM Jikes Compiler License Agreement available at the following URL: http://www.ibm.com/research/jikes. Copyright (C) 1983, 1999, International Business Machines Corporation and others. All Rights Reserved. You must accept the terms of that agreement to use this software. */ static char hostfile[] = __FILE__; #include #include "common.h" #include "header.h" /*****************************************************************************/ /* PTSTATS: */ /*****************************************************************************/ /* PT_STATS prints all the states of the parser. */ /*****************************************************************************/ void ptstats(void) { int max_size, state_no, symbol, number, i; struct goto_header_type go_to; struct shift_header_type sh; struct reduce_header_type red; char temp[SYMBOL_SIZE + 1], line[MAX_LINE_SIZE + 1]; PR_HEADING; fprintf(syslis,"Shift STATES: "); for ALL_STATES(state_no) /* iterate over the states */ { print_state(state_no); max_size = 0; /****************************************************************/ /* Compute the size of the largest symbol. The MAX_SIZE cannot */ /* be larger than PRINT_LINE_SIZE - 17 to allow for printing of */ /* headers for actions to be taken on the symbols. */ /****************************************************************/ sh = shift[statset[state_no].shift_number]; for (i = 1; i <= sh.size; i++) { symbol = SHIFT_SYMBOL(sh, i); restore_symbol(temp, RETRIEVE_STRING(symbol)); max_size = MAX(max_size, strlen(temp)); } go_to = statset[state_no].go_to; for (i = 1; i <= go_to.size; i++) { symbol = GOTO_SYMBOL(go_to, i); restore_symbol(temp, RETRIEVE_STRING(symbol)); max_size = MAX(max_size, strlen(temp)); } red = reduce[state_no]; for (i = 1; i <= red.size; i++) { symbol = REDUCE_SYMBOL(red, i); restore_symbol(temp, RETRIEVE_STRING(symbol)); max_size = MAX(max_size, strlen(temp)); } max_size = MIN(max_size, PRINT_LINE_SIZE - 17); /**************************************************************/ /* 1) Print all Shift actions. */ /* 2) Print all Goto actions. */ /* 3) Print all reduce actions. */ /* 4) If there is a default then print it. */ /**************************************************************/ if (sh.size > 0) { fprintf(syslis, "\n"); ENDPAGE_CHECK; for (i = 1; i <= sh.size; i++) { symbol = SHIFT_SYMBOL(sh, i); restore_symbol(temp, RETRIEVE_STRING(symbol)); print_large_token(line, temp, "", max_size); number = ABS(SHIFT_ACTION(sh, i)); if (SHIFT_ACTION(sh, i) > (short) num_states) { fprintf(syslis, "\n%-*s La/Sh %d", max_size, line, number); ENDPAGE_CHECK; } else if (SHIFT_ACTION(sh, i) > 0) { fprintf(syslis, "\n%-*s Shift %d", max_size, line, number); ENDPAGE_CHECK; } else { fprintf(syslis, "\n%-*s Sh/Rd %d", max_size, line, number); ENDPAGE_CHECK; } } } if (go_to.size > 0) { fprintf(syslis, "\n"); ENDPAGE_CHECK; for (i = 1; i <= go_to.size; i++) { symbol = GOTO_SYMBOL(go_to, i); restore_symbol(temp, RETRIEVE_STRING(symbol)); print_large_token(line, temp, "", max_size); number = ABS(GOTO_ACTION(go_to, i)); if (GOTO_ACTION(go_to, i) > 0) { fprintf(syslis, "\n%-*s Goto %d", max_size, line, number); ENDPAGE_CHECK; } else { fprintf(syslis, "\n%-*s Gt/Rd %d", max_size, line, number); ENDPAGE_CHECK; } } } if (red.size != 0) { fprintf(syslis, "\n"); ENDPAGE_CHECK; for (i = 1; i <= red.size; i++) { symbol = REDUCE_SYMBOL(red, i); restore_symbol(temp, RETRIEVE_STRING(symbol)); print_large_token(line, temp, "", max_size); number = REDUCE_RULE_NO(red, i); if (rules[number].lhs != accept_image) { fprintf(syslis, "\n%-*s Reduce %d", max_size, line, number); ENDPAGE_CHECK; } else { fprintf(syslis, "\n%-*s Accept",max_size, line); ENDPAGE_CHECK; } } } if (default_opt > 0) { if (REDUCE_RULE_NO(red, 0) != OMEGA) { fprintf(syslis, "\n\nDefault reduction to rule %d", REDUCE_RULE_NO(red, 0)); output_line_no++; ENDPAGE_CHECK; } } } if (max_la_state > num_states) { PR_HEADING; fprintf(syslis,"Look-Ahead STATES:"); } for ALL_LA_STATES(state_no) { char buffer[PRINT_LINE_SIZE + 1]; i = number_len(state_no) + 8; /* 8 = length of "STATE" */ /* + 2 spaces + newline */ fill_in(buffer, (PRINT_LINE_SIZE - i) ,'-'); fprintf(syslis, "\n\n\nSTATE %d %s",state_no, buffer); output_line_no += 2; ENDPAGE_CHECK; /**************************************************************/ /* Print the set of states that have transitions to STATE_NO. */ /**************************************************************/ if (lastats[state_no].in_state == state_no) { fprintf(syslis,"\n(Unreachable State)\n"); output_line_no++; ENDPAGE_CHECK; } else { fprintf(syslis,"\n(%d)\n", lastats[state_no].in_state); output_line_no++; ENDPAGE_CHECK; max_size = 0; /*********************************************************/ /* Compute the size of the largest symbol. The MAX_SIZE */ /* cannot be larger than PRINT_LINE_SIZE - 17 to allow */ /* for printing of headers for actions to be taken on */ /* the symbols. */ /*********************************************************/ sh = shift[lastats[state_no].shift_number]; for (i = 1; i <= sh.size; i++) { symbol = SHIFT_SYMBOL(sh, i); restore_symbol(temp, RETRIEVE_STRING(symbol)); max_size = MAX(max_size, strlen(temp)); } red = lastats[state_no].reduce; for (i = 1; i <= red.size; i++) { symbol = REDUCE_SYMBOL(red, i); restore_symbol(temp, RETRIEVE_STRING(symbol)); max_size = MAX(max_size, strlen(temp)); } max_size = MIN(max_size, PRINT_LINE_SIZE - 17); /**********************************************************/ /* 1) Print all Shift actions. */ /* 2) Print all Goto actions. */ /* 3) Print all reduce actions. */ /* 4) If there is a default then print it. */ /**********************************************************/ fprintf(syslis, "\n"); ENDPAGE_CHECK; for (i = 1; i <= sh.size; i++) { symbol = SHIFT_SYMBOL(sh, i); restore_symbol(temp, RETRIEVE_STRING(symbol)); print_large_token(line, temp, "", max_size); number = ABS(SHIFT_ACTION(sh, i)); if (SHIFT_ACTION(sh, i) > (short) num_states) { fprintf(syslis, "\n%-*s La/Sh %d", max_size, line, number); ENDPAGE_CHECK; } else if (SHIFT_ACTION(sh, i) > 0) { fprintf(syslis, "\n%-*s Shift %d", max_size, line, number); ENDPAGE_CHECK; } else { fprintf(syslis, "\n%-*s Sh/Rd %d", max_size, line, number); ENDPAGE_CHECK; } } fprintf(syslis, "\n"); ENDPAGE_CHECK; for (i = 1; i <= red.size; i++) { symbol = REDUCE_SYMBOL(red, i); restore_symbol(temp, RETRIEVE_STRING(symbol)); print_large_token(line, temp, "", max_size); number = REDUCE_RULE_NO(red, i); fprintf(syslis, "\n%-*s Reduce %d", max_size, line, number); ENDPAGE_CHECK; } if (default_opt > 0 && REDUCE_RULE_NO(red, 0) != OMEGA) { fprintf(syslis, "\n\nDefault reduction to rule %d", REDUCE_RULE_NO(red, 0)); output_line_no++; ENDPAGE_CHECK; } } } fprintf(syslis,"\n"); ENDPAGE_CHECK; return; } jikespg-1.3/src/produce.c000066400000000000000000001533441167345774400154410ustar00rootroot00000000000000/* $Id: produce.c,v 1.2 1999/11/04 14:02:23 shields Exp $ */ /* This software is subject to the terms of the IBM Jikes Compiler License Agreement available at the following URL: http://www.ibm.com/research/jikes. Copyright (C) 1983, 1999, International Business Machines Corporation and others. All Rights Reserved. You must accept the terms of that agreement to use this software. */ static char hostfile[] = __FILE__; #include #include "common.h" #include "header.h" static short *stack, *index_of, *nt_list, *item_list, *item_of, *next_item, *scope_table; static int scope_top = 0; static struct node **direct_produces; static struct scope_elmt { short link, item, index; } *scope_element; static BOOLEAN *symbol_seen; static SET_PTR produces, right_produces, left_produces; static int top; static void compute_produces(int symbol); static void print_name_map(int symbol); static void process_scopes(void); static BOOLEAN is_scope(int item_no); static BOOLEAN scope_check(int lhs_symbol, int target, int source); static insert_prefix(int item_no); static BOOLEAN is_prefix_equal(int item_no, int item_no2); static insert_suffix(int item_no); static BOOLEAN is_suffix_equal(int item_no1, int item_no2); static void print_scopes(void); static get_shift_symbol(int lhs_symbol); /****************************************************************************/ /* PRODUCE: */ /****************************************************************************/ /* This procedure computes for each state the set of non-terminal symbols */ /* that are required as candidates for secondary error recovery. If the */ /* option NAMES=OPTIMIZED is requested, the NAME map is optimized and SYMNO */ /* is updated accordingly. */ /****************************************************************************/ void produce(void) { /*****************************************************************/ /* TOP, STACK, and INDEX are used for the digraph algorithm */ /* in the routines COMPUTE_PRODUCES. */ /* */ /* The array PRODUCES is used to construct two maps: */ /* */ /* 1) PRODUCES, a mapping from each non-terminal A to the set of */ /* non-terminals C such that: */ /* */ /* A =>* x C w */ /* */ /* 2) RIGHT_MOST_PRODUCES, a mapping from each non-terminal A to */ /* the set of non-terminals C such that: */ /* */ /* C =>+ A x and x =>* %empty. */ /* */ /* NOTE: This is really a reverse right-most produces mapping, */ /* since given the above rule, we say that */ /* C right-most produces A. */ /* */ /*****************************************************************/ int state_no, state, nt_root, item_no, item_root, rule_no, symbol, nt, i, n; short *names_map; struct node **goto_domain, *p, *q; BOOLEAN *name_used, end_node; SET_PTR set; stack = Allocate_short_array(num_symbols + 1); index_of = Allocate_short_array(num_symbols + 1); names_map = Allocate_short_array(num_names + 1); name_used = Allocate_boolean_array(num_names + 1); item_list = Allocate_short_array(num_items + 1); nt_list = Allocate_short_array(num_non_terminals + 1); nt_list -= (num_terminals + 1); set = (SET_PTR) calloc(1, non_term_set_size * sizeof(BOOLEAN_CELL)); if (set == NULL) nospace(__FILE__, __LINE__); produces = (SET_PTR) calloc(num_non_terminals, non_term_set_size * sizeof(BOOLEAN_CELL)); if (produces == NULL) nospace(__FILE__, __LINE__); produces -= ((num_terminals + 1) * non_term_set_size); direct_produces = (struct node **) calloc(num_non_terminals, sizeof(struct node *)); if (direct_produces == NULL) nospace(__FILE__, __LINE__); direct_produces -= (num_terminals + 1); goto_domain = (struct node **) calloc(num_states + 1, sizeof(struct node *)); if (goto_domain == NULL) nospace(__FILE__, __LINE__); /*********************************************************************/ /* Note that the space allocated for PRODUCES and DIRECT_PRODUCES */ /* is automatically initialized to 0 by calloc. Logically, this sets */ /* all the sets in the PRODUCES map to the empty set and all the */ /* pointers in DIRECT_PRODUCES are set to NULL. */ /* */ /* Next, PRODUCES is initialized to compute RIGHT_MOST_PRODUCES. */ /* Also, we count the number of error rules and verify that they are */ /* in the right format. */ /*********************************************************************/ item_root = NIL; for ALL_NON_TERMINALS(nt) { for (end_node = ((p = clitems[nt]) == NULL); ! end_node; end_node = (p == clitems[nt])) { p = p -> next; item_no = p -> value; symbol = item_table[item_no].symbol; if (symbol IS_A_NON_TERMINAL) { i = item_table[item_no].suffix_index; if (IS_IN_SET(first, i, empty) && (! IS_IN_NTSET(produces, symbol, nt - num_terminals))) { NTSET_BIT_IN(produces, symbol, nt - num_terminals); q = Allocate_node(); q -> value = nt; q -> next = direct_produces[symbol]; direct_produces[symbol] = q; } } rule_no = item_table[item_no].rule_number; for (i = 0; i < RHS_SIZE(rule_no); i++) { if (item_table[item_no + i].symbol == error_image) break; } item_no += i; symbol = item_table[item_no].symbol; if (symbol == error_image) { if (item_table[item_no + 1].symbol IS_A_NON_TERMINAL && i > 0) { symbol = item_table[item_no + 2].symbol; if (symbol == empty) num_error_rules++; } if (warnings_bit && symbol != empty) { item_list[item_no] = item_root; item_root = item_no; } } symbol = eoft_image; } } /*********************************************************************/ /* If WARNINGS_BIT is on and some error rules are in the wrong, */ /* format, report them. */ /*********************************************************************/ if (warnings_bit && item_root != NIL) { PR_HEADING; if (item_list[item_root] == NIL) fprintf(syslis, "*** This error rule is not in manual format:\n\n"); else fprintf(syslis, "*** These error rules are not in manual format:\n\n"); for (item_no = item_root; item_no != NIL; item_no = item_list[item_no]) { print_item(item_no); } } /********************************************************************/ /* Complete the construction of the RIGHT_MOST_PRODUCES map for */ /* non-terminals using the digraph algorithm. */ /* We make sure that each non-terminal A is not present in its own */ /* PRODUCES set since we are interested in the non-reflexive */ /* (positive) transitive closure. */ /********************************************************************/ for ALL_SYMBOLS(i) index_of[i] = OMEGA; top = 0; for ALL_NON_TERMINALS(nt) { if (index_of[nt] == OMEGA) compute_produces(nt); NTRESET_BIT_IN(produces, nt, nt - num_terminals); } /********************************************************************/ /* Construct the minimum subset of the domain of the GOTO map */ /* needed for automatic secondary level error recovery. For each */ /* state, we start out with the set of all nonterminals on which */ /* there is a transition in that state, and pare it down to a */ /* subset S, by removing all nonterminals B in S such that there */ /* is a goto-reduce action on B by a single production. If the */ /* READ-REDUCE option is not turned on, then, we check whether or */ /* not the goto action on B is to an LR(0) reduce state.Once we have*/ /* our subset S, we further reduce its size as follows. For each */ /* nonterminal A in S such that there exists another nonterminal */ /* B in S, where B ^= A, A ->+ Bx and x =>* %empty, we remove A */ /* from S. */ /* At the end of this process, the nonterminal elements whose */ /* NT_LIST values are still OMEGA are precisely the nonterminal */ /* symbols that are never used as candidates. */ /********************************************************************/ for ALL_NON_TERMINALS(i) nt_list[i] = OMEGA; nt_list[accept_image] = NIL; for ALL_STATES(state_no) { struct goto_header_type go_to; go_to = statset[state_no].go_to; nt_root = NIL; INIT_NTSET(set); for (i = 1; i <= go_to.size; i++) { symbol = GOTO_SYMBOL(go_to, i); state = GOTO_ACTION(go_to, i); if (state < 0) rule_no = -state; else { q = statset[state].kernel_items; item_no = q -> value; if (q -> next != NULL) rule_no = 0; else rule_no = item_table[item_no].rule_number; } if (rule_no == 0 || RHS_SIZE(rule_no) != 1) { nt_list[symbol] = nt_root; nt_root = symbol; NTSET_UNION(set, 0, produces, symbol); } } goto_domain[state_no] = NULL; for (symbol = nt_root; symbol != NIL; symbol = nt_list[symbol]) { if (! IS_ELEMENT(set, symbol - num_terminals)) { q = Allocate_node(); q -> value = symbol; q -> next = goto_domain[state_no]; goto_domain[state_no] = q; gotodom_size++; } } } /********************************************************************/ /* Allocate and construct the permanent goto domain structure: */ /* GD_INDEX and GD_RANGE. */ /********************************************************************/ n = 0; gd_index = Allocate_short_array(num_states + 2); gd_range = Allocate_short_array(gotodom_size + 1); for ALL_STATES(state_no) { gd_index[state_no] = n + 1; for (p = goto_domain[state_no]; p != NULL; q = p, p = p -> next) gd_range[++n] = p -> value; if (goto_domain[state_no] != NULL) free_nodes(goto_domain[state_no], q); } gd_index[num_states + 1] = n + 1; /******************************************************************/ /* Remove names assigned to nonterminals that are never used as */ /* error candidates. */ /******************************************************************/ if (names_opt == OPTIMIZE_PHRASES) { /*****************************************************************/ /* In addition to nonterminals that are never used as candidates,*/ /* if a nullable nonterminal was assigned a name by default */ /* (nonterminals that were "named" by default are identified */ /* with negative indices), that name is also removed. */ /*****************************************************************/ for ALL_NON_TERMINALS(symbol) { if (nt_list[symbol] == OMEGA) symno[symbol].name_index = symno[accept_image].name_index; else if (symno[symbol].name_index < 0) { if (null_nt[symbol]) symno[symbol].name_index = symno[accept_image].name_index; else symno[symbol].name_index = - symno[symbol].name_index; } } /*******************************************************************/ /* Adjust name map to remove unused elements and update SYMNO map. */ /*******************************************************************/ for (i = 1; i <= num_names; i++) name_used[i] = FALSE; for ALL_SYMBOLS(symbol) name_used[symno[symbol].name_index] = TRUE; n = 0; for (i = 1; i <= num_names; i++) { if (name_used[i]) { name[++n] = name[i]; names_map[i] = n; } } num_names = n; for ALL_SYMBOLS(symbol) symno[symbol].name_index = names_map[symno[symbol].name_index]; } /********************************************************************/ /* If the option LIST_BIT is ON, print the name map. */ /********************************************************************/ if (list_bit) { PR_HEADING; fprintf(syslis, "\nName map:\n"); output_line_no += 2; for ALL_SYMBOLS(symbol) { if (symno[symbol].name_index != symno[accept_image].name_index) print_name_map(symbol); } for ALL_SYMBOLS(symbol) { if (symbol != accept_image && symno[symbol].name_index == symno[accept_image].name_index) print_name_map(symbol); } } if (scopes_bit) process_scopes(); ffree(stack); ffree(index_of); ffree(names_map); ffree(name_used); nt_list += (num_terminals + 1); ffree(nt_list); ffree(set); produces += ((num_terminals + 1) * non_term_set_size); ffree(produces); direct_produces += (num_terminals + 1); ffree(direct_produces); ffree(goto_domain); return; } /******************************************************************/ /* COMPUTE_PRODUCES: */ /******************************************************************/ /* This procedure is used to compute the transitive closure of */ /* the PRODUCES, LEFT_PRODUCES and RIGHT_MOST_PRODUCES maps. */ /******************************************************************/ static void compute_produces(int symbol) { int indx; int new_symbol; struct node *p, *q; stack[++top] = symbol; indx = top; index_of[symbol] = indx; for (p = direct_produces[symbol]; p != NULL; q = p, p = p -> next) { new_symbol = p -> value; if (index_of[new_symbol] == OMEGA) /* first time seen? */ compute_produces(new_symbol); index_of[symbol] = MIN(index_of[symbol], index_of[new_symbol]); NTSET_UNION(produces, symbol, produces, new_symbol); } if (direct_produces[symbol] != NULL) free_nodes(direct_produces[symbol], q); if (index_of[symbol] == indx) /*symbol is SCC root */ { for (new_symbol = stack[top]; new_symbol != symbol; new_symbol = stack[--top]) { ASSIGN_NTSET(produces, new_symbol, produces, symbol); index_of[new_symbol] = INFINITY; } index_of[symbol] = INFINITY; top--; } return; } /******************************************************************/ /* PRINT_NAME_MAP: */ /******************************************************************/ /* This procedure prints the name associated with a given symbol. */ /* The same format that was used in the procedure DISPLAY_INPUT */ /* to print aliases is used to print name mappings. */ /******************************************************************/ static void print_name_map(int symbol) { int len; char line[PRINT_LINE_SIZE], tok[SYMBOL_SIZE + 1]; restore_symbol(tok, RETRIEVE_STRING(symbol)); len = PRINT_LINE_SIZE - 5; print_large_token(line, tok, "", len); strcat(line, " ::= "); restore_symbol(tok, RETRIEVE_NAME(symno[symbol].name_index)); if (strlen(line) + strlen(tok) > PRINT_LINE_SIZE - 1) { fprintf(syslis, "\n%s", line); ENDPAGE_CHECK; len = PRINT_LINE_SIZE - 4; print_large_token(line, tok, " ", len); } else strcat(line, tok); fprintf(syslis, "\n%s", line); ENDPAGE_CHECK; return; } /******************************************************************/ /* PROCESS_SCOPES: */ /******************************************************************/ /* Compute set of "scopes" and use it to construct SCOPE map. */ /******************************************************************/ static void process_scopes(void) { short *prefix_index, *suffix_index, *state_index; struct node **states_of; int num_state_sets = 0, i, j, k, n; short max_prefix_length = 0, dot_symbol, nt, symbol, item_root, item_no, rule_no, state_no, nt_root; BOOLEAN end_node; struct node *p, *q; prefix_index = Allocate_short_array(num_items + 1); suffix_index = Allocate_short_array(num_items + 1); item_of = Allocate_short_array(num_non_terminals); item_of -= (num_terminals + 1); next_item = Allocate_short_array(num_items + 1); symbol_seen = Allocate_boolean_array(num_non_terminals); symbol_seen -= (num_terminals + 1); states_of = (struct node **) calloc(num_non_terminals, sizeof(struct node *)); states_of -= (num_terminals + 1); state_index = Allocate_short_array(num_non_terminals); state_index -= (num_terminals + 1); scope_element = (struct scope_elmt *) calloc(num_items + 1, sizeof(struct scope_elmt)); /********************************************************************/ /* Initially, PRODUCES was used to compute the right-most-produces */ /* map. We save that map map and make it reflexive. Recall that */ /* RIGHT_PRODUCES is a mapping from each nonterminal B into the set */ /* of nonterminals A such that: */ /* */ /* A =>rm* B */ /* */ /* Next, reallocate PRODUCES and initialize it in order to */ /* construct the LEFT_PRODUCES map. Initially, CALLOC sets PRODUCES */ /* to the empty map. */ /* LEFT_PRODUCES is a mapping from each nonterminal A into the set */ /* of nonterminals B such that: */ /* */ /* A =>lm* B x */ /* */ /* for some arbitrary string x. */ /* */ /* Since A ->* A for all A, we insert A in PRODUCES(A) (but not */ /* in the linked list). */ /* */ /********************************************************************/ right_produces = produces; produces = (SET_PTR) calloc(num_non_terminals, non_term_set_size * sizeof(BOOLEAN_CELL)); if (produces == NULL) nospace(__FILE__, __LINE__); produces -= ((num_terminals + 1) * non_term_set_size); for ALL_NON_TERMINALS(nt) { NTSET_BIT_IN(right_produces, nt, nt - num_terminals); NTSET_BIT_IN(produces, nt, nt - num_terminals); direct_produces[nt] = NULL; for (end_node = ((p = clitems[nt]) == NULL); ! end_node; end_node = (p == clitems[nt])) { p = p -> next; for (item_no = p -> value; item_table[item_no].symbol IS_A_NON_TERMINAL; item_no++) { symbol = item_table[item_no].symbol; if (! IS_IN_NTSET(produces, nt, symbol - num_terminals)) { NTSET_BIT_IN(produces, nt, symbol - num_terminals); q = Allocate_node(); q -> value = symbol; q -> next = direct_produces[nt]; direct_produces[nt] = q; } if (! null_nt[symbol]) break; } } } /****************************************************************/ /* Complete the construction of the LEFT_produces map for */ /* non_terminals using the digraph algorithm. */ /****************************************************************/ for ALL_NON_TERMINALS(nt) index_of[nt] = OMEGA; top = 0; for ALL_NON_TERMINALS(nt) { if (index_of[nt] == OMEGA) compute_produces(nt); } left_produces = produces; /********************************************************************/ /* Allocate and initialize the PRODUCES array to construct the */ /* PRODUCES map. After allocation, CALLOC sets all sets to empty. */ /* Since A ->* A for all A, we insert A in PRODUCES(A) (but not */ /* in the linked list). */ /********************************************************************/ produces = (SET_PTR) calloc(num_non_terminals, non_term_set_size * sizeof(BOOLEAN_CELL)); if (produces == NULL) nospace(__FILE__, __LINE__); produces -= ((num_terminals + 1) * non_term_set_size); for ALL_NON_TERMINALS(nt) { NTSET_BIT_IN(produces, nt, nt - num_terminals); direct_produces[nt] = NULL; for (end_node = ((p = clitems[nt]) == NULL); ! end_node; end_node = (p == clitems[nt])) { p = p -> next; for (item_no = p -> value; item_table[item_no].symbol != empty; item_no++) { symbol = item_table[item_no].symbol; if (symbol IS_A_NON_TERMINAL) { if (! IS_IN_NTSET(produces, nt, symbol - num_terminals)) { NTSET_BIT_IN(produces, nt, symbol - num_terminals); q = Allocate_node(); q -> value = symbol; q -> next = direct_produces[nt]; direct_produces[nt] = q; } } } } } /****************************************************************/ /* Complete the construction of the PRODUCES map for */ /* non_terminals using the digraph algorithm. */ /* */ /* Since $ACC =>* x A y for all nonterminal A in the grammar, a */ /* single call to COMPUTE_PRODUCES does the trick. */ /****************************************************************/ for ALL_NON_TERMINALS(nt) index_of[nt] = OMEGA; top = 0; compute_produces(accept_image); /********************************************************************/ /* Construct a mapping from each non_terminal A into the set of */ /* items of the form [B -> x . A y]. */ /********************************************************************/ for ALL_NON_TERMINALS(nt) item_of[nt] = NIL; for ALL_ITEMS(item_no) { dot_symbol = item_table[item_no].symbol; if (dot_symbol IS_A_NON_TERMINAL) { next_item[item_no] = item_of[dot_symbol]; item_of[dot_symbol] = item_no; } } /********************************************************************/ /* Construct a list of scoped items in ITEM_LIST. */ /* Scoped items are derived from rules of the form A -> x B y such */ /* that B =>* w A z, %empty not in FIRST(y), and it is not the case */ /* that x = %empty and B ->* A v. */ /* Scoped items may also be identified by the user, using %error */ /* productions. */ /* As scoped items are added to the list, we keep track of the */ /* longest prefix encountered. This is subsequently used to */ /* bucket sort the scoped items in descending order of the length */ /* of their prefixes. */ /********************************************************************/ for ALL_ITEMS(item_no) item_list[item_no] = OMEGA; item_root = NIL; for ALL_ITEMS(item_no) { dot_symbol = item_table[item_no].symbol; if (dot_symbol == error_image) { if (item_table[item_no].dot != 0 && (! IS_IN_SET(first, item_table[item_no].suffix_index, empty))) { if (item_list[item_no] == OMEGA) { item_list[item_no] = item_root; item_root = item_no; max_prefix_length = MAX(max_prefix_length, item_table[item_no].dot); } } } else if (dot_symbol IS_A_NON_TERMINAL) { symbol = rules[item_table[item_no].rule_number].lhs; if (! IS_IN_SET(first, item_table[item_no].suffix_index, empty) && IS_IN_NTSET(produces, dot_symbol, symbol - num_terminals)) { if (is_scope(item_no)) { for (i = item_no + 1; ;i++) { symbol = item_table[i].symbol; if (symbol IS_A_TERMINAL) break; if (! null_nt[symbol]) break; } if (symbol IS_A_NON_TERMINAL) { for ALL_NON_TERMINALS(nt) symbol_seen[nt] = FALSE; symbol = get_shift_symbol(symbol); } if (symbol != empty && item_list[i] == OMEGA) { item_list[i] = item_root; item_root = i; max_prefix_length = MAX(max_prefix_length, item_table[i].dot); } } } } } /*********************************************************************/ /* In this loop, the prefix and suffix string for each scope in */ /* entered into a table. We also use the SYMBOL_SEEN array to */ /* identify the set of left-hand side symbols associated with the */ /* scopes. */ /*********************************************************************/ scope_table = Allocate_short_array(SCOPE_SIZE); for (i = 0; i < SCOPE_SIZE; i++) scope_table[i] = NIL; for ALL_NON_TERMINALS(nt) symbol_seen[nt] = FALSE; for (item_no = item_root; item_no != NIL; item_no = item_list[item_no]) { rule_no = item_table[item_no].rule_number; symbol = rules[rule_no].lhs; num_scopes = num_scopes + 1; symbol_seen[symbol] = TRUE; prefix_index[item_no] = insert_prefix(item_no); suffix_index[item_no] = insert_suffix(item_no); } ffree(scope_table); /*********************************************************************/ /* We now construct a mapping from each nonterminal symbol that is */ /* the left-hand side of a rule containing scopes into the set of */ /* states that has a transition on the nonterminal in question. */ /*********************************************************************/ nt_root = NIL; for ALL_NON_TERMINALS(nt) states_of[nt] = NULL; for ALL_STATES(state_no) { struct goto_header_type go_to; go_to = statset[state_no].go_to; for (i = 1; i <= go_to.size; i++) { symbol = GOTO_SYMBOL(go_to, i); if (symbol_seen[symbol]) { if (states_of[symbol] == NULL) { nt_list[symbol] = nt_root; nt_root = symbol; num_state_sets = num_state_sets + 1; } q = Allocate_node(); q -> value = state_no; q -> next = states_of[symbol]; states_of[symbol] = q; } } } right_produces += ((num_terminals + 1) * non_term_set_size); ffree(right_produces); left_produces += ((num_terminals + 1) * non_term_set_size); ffree(left_produces); /*********************************************************************/ /* Next, we used the optimal partition procedure to compress the */ /* space used by the sets of states, allocate the SCOPE structure */ /* and store the compressed sets of states in it. */ /* We also sort the list of items by the length of their prefixes in */ /* descending order. This is done primarily as an optimization. */ /* If a longer prefix matches prior to a shorter one, the parsing */ /* will terminate quicker. */ /*********************************************************************/ process_scope_states: { SET_PTR collection; short *element_size, *list, *start, *stack, *ordered_symbol, *state_list, *bucket; int state_root, state_no; state_set_size = num_states / SIZEOF_BC + (num_states % SIZEOF_BC ? 1 : 0); collection = (SET_PTR) calloc(num_state_sets + 1, state_set_size * sizeof(BOOLEAN_CELL)); if (collection == NULL) nospace(__FILE__, __LINE__); element_size = Allocate_short_array(num_state_sets + 1); start = Allocate_short_array(num_state_sets + 2); stack = Allocate_short_array(num_state_sets + 1); ordered_symbol = Allocate_short_array(num_state_sets + 1); list = Allocate_short_array(num_state_sets + 1); state_list = Allocate_short_array(num_states + 1); bucket = Allocate_short_array(max_prefix_length + 1); for (symbol = nt_root, i = 1; symbol != NIL; symbol = nt_list[symbol], i++) { list[i] = i; ordered_symbol[i] = symbol; EMPTY_COLLECTION_SET(i); element_size[i] = 0; for (p = states_of[symbol]; p != NULL; p = p -> next) { element_size[i]++; SET_COLLECTION_BIT(i, p -> value); } } partset(collection, element_size, list, start, stack, num_state_sets); for (i = 1; i <= num_state_sets; i++) { symbol = ordered_symbol[i]; state_index[symbol] = ABS(start[i]); } scope_state_size = start[num_state_sets + 1] - 1; scope = (struct scope_type *) calloc(num_scopes + 1, sizeof(struct scope_type)); if (scope == NULL) nospace(__FILE__, __LINE__); scope_right_side = Allocate_short_array(scope_rhs_size + 1); scope_state = Allocate_short_array(scope_state_size + 1); k = 0; for (i = 0; i <= (int) num_states; i++) state_list[i] = OMEGA; for (i = 1; i <= num_state_sets; i++) { if (start[i] > 0) { state_root = 0; state_list[state_root] = NIL; for (end_node = ((j = i) == NIL); ! end_node; end_node = (j == i)) { j = stack[j]; symbol = ordered_symbol[j]; for (p = states_of[symbol]; p != NULL; p = p -> next) { state_no = p -> value; if (state_list[state_no] == OMEGA) { state_list[state_no] = state_root; state_root = state_no; } } } for (state_no = state_root; state_no != NIL; state_no = state_root) { state_root = state_list[state_no]; state_list[state_no] = OMEGA; k++; scope_state[k] = state_no; } } } for (symbol = nt_root; symbol != NIL; symbol = nt_list[symbol]) { for (p = states_of[symbol]; p != NULL; q = p, p = p -> next) ; free_nodes(states_of[symbol], q); } /***********************************************************************/ /* Use the BUCKET array as a base to partition the scoped items */ /* based on the length of their prefixes. The list of items in each */ /* bucket is kept in the NEXT_ITEM array sorted in descending order */ /* of the length of the right-hand side of the item. */ /* Items are kept sorted in that fashion because when two items have */ /* the same prefix, we want the one with the shortest suffix to be */ /* chosen. In other words, if we have two scoped items, say: */ /* */ /* A ::= x . y and B ::= x . z where |y| < |z| */ /* */ /* and both of them are applicable in a given context with similar */ /* result, then we always want A ::= x . y to be used. */ /***********************************************************************/ for (i = 1; i <= max_prefix_length; i++) bucket[i] = NIL; for (item_no = item_root; item_no != NIL; item_no = item_list[item_no]) { int tail; k = item_table[item_no].dot; for (i = bucket[k]; i != NIL; tail = i, i = next_item[i]) { if (RHS_SIZE(item_table[item_no].rule_number) >= RHS_SIZE(item_table[i].rule_number)) break; } next_item[item_no] = i; if (i == bucket[k]) bucket[k] = item_no; /* insert at the beginning */ else next_item[tail] = item_no; /* insert in middle or end */ } /*********************************************************************/ /* Reconstruct list of scoped items in sorted order. Since we want */ /* the items in descending order, we start with the smallest bucket */ /* proceeding to the largest one and insert the items from each */ /* bucket in LIFO order in ITEM_LIST. */ /*********************************************************************/ item_root = NIL; for (k = 1; k <= max_prefix_length; k++) { for (item_no = bucket[k]; item_no != NIL; item_no = next_item[item_no]) { item_list[item_no] = item_root; item_root = item_no; } } ffree(collection); ffree(element_size); ffree(start); ffree(stack); ffree(ordered_symbol); ffree(state_list); ffree(list); ffree(bucket); } /* End PROCESS_SCOPE_STATES */ /*********************************************************************/ /* Next, we initialize the remaining fields of the SCOPE structure. */ /*********************************************************************/ item_no = item_root; for (i = 1; item_no != NIL; i++) { scope[i].prefix = prefix_index[item_no]; scope[i].suffix = suffix_index[item_no]; rule_no = item_table[item_no].rule_number; scope[i].lhs_symbol = rules[rule_no].lhs; symbol = rhs_sym[rules[rule_no].rhs + item_table[item_no].dot]; if (symbol IS_A_TERMINAL) scope[i].look_ahead = symbol; else { for ALL_NON_TERMINALS(j) symbol_seen[j] = FALSE; scope[i].look_ahead = get_shift_symbol(symbol); } scope[i].state_set = state_index[scope[i].lhs_symbol]; item_no = item_list[item_no]; } for (j = 1; j <= scope_top; j++) { if (scope_element[j].item < 0) { item_no = -scope_element[j].item; rule_no = item_table[item_no].rule_number; n = scope_element[j].index; for (k = rules[rule_no].rhs+item_table[item_no].dot - 1; k >= rules[rule_no].rhs; /* symbols before dot*/ k--) scope_right_side[n++] = rhs_sym[k]; } else { item_no = scope_element[j].item; rule_no = item_table[item_no].rule_number; n = scope_element[j].index; for (k = rules[rule_no].rhs + item_table[item_no].dot; k < rules[rule_no + 1].rhs; /* symbols after dot */ k++) { symbol = rhs_sym[k]; if (symbol IS_A_NON_TERMINAL) { if (! null_nt[symbol]) scope_right_side[n++] = rhs_sym[k]; } else if (symbol != error_image) scope_right_side[n++] = rhs_sym[k]; } } scope_right_side[n] = 0; } if (list_bit) print_scopes(); ffree(prefix_index); ffree(suffix_index); item_of += (num_terminals + 1); ffree(item_of); ffree(next_item); symbol_seen += (num_terminals + 1); ffree(symbol_seen); states_of += (num_terminals + 1); ffree(states_of); state_index += (num_terminals + 1); ffree(state_index); ffree(scope_element); return; } /*********************************************************************/ /* IS_SCOPE: */ /*********************************************************************/ /* This procedure checks whether or not an item of the form: */ /* [A -> w B x where B ->* y A z is a valid scope. */ /* */ /* Such an item is a valid scope if the following conditions hold: */ /* */ /* 1) it is not the case that x =>* %empty */ /* 2) either it is not the case that w =>* %empty or it is not the */ /* case that B =>lm* A. */ /* 3) it is not the case that whenever A is introduced through */ /* closure, it is introduced by a nonterminal C where C =>rm* A */ /* and C =>rm+ B. */ /*********************************************************************/ static BOOLEAN is_scope(int item_no) { int i, nt, lhs_symbol, target, symbol; for (i = item_no - item_table[item_no].dot; i < item_no; i++) { symbol = item_table[i].symbol; if (symbol IS_A_TERMINAL) return(TRUE); if (! null_nt[symbol]) return(TRUE); } lhs_symbol = rules[item_table[item_no].rule_number].lhs; target = item_table[item_no].symbol; if (IS_IN_NTSET(left_produces, target, lhs_symbol - num_terminals)) return(FALSE); if (item_table[item_no].dot > 0) return(TRUE); for ALL_NON_TERMINALS(nt) symbol_seen[nt] = FALSE; return(scope_check(lhs_symbol, target, lhs_symbol)); } /*********************************************************************/ /* SCOPE_CHECK: */ /*********************************************************************/ /* Given a nonterminal LHS_SYMBOL and a nonterminal TARGET where, */ /* */ /* LHS_SYMBOL ::= TARGET x */ /* */ /* find out if whenever LHS_SYMBOL is introduced through closure, it */ /* is introduced by a nonterminal SOURCE such that */ /* */ /* SOURCE ->rm* LHS_SYMBOL */ /* */ /* and */ /* */ /* SOURCE ->rm+ TARGET */ /* */ /*********************************************************************/ static BOOLEAN scope_check(int lhs_symbol, int target, int source) { int item_no, rule_no, symbol; symbol_seen[source] = TRUE; if (IS_IN_NTSET(right_produces, target, source - num_terminals) && IS_IN_NTSET(right_produces, lhs_symbol, source - num_terminals)) return(FALSE); for (item_no = item_of[source]; item_no != NIL; item_no = next_item[item_no]) { if (item_table[item_no].dot != 0) return(TRUE); rule_no = item_table[item_no].rule_number; symbol = rules[rule_no].lhs; if (! symbol_seen[symbol]) /* not yet processed */ { if (scope_check(lhs_symbol, target, symbol)) return(TRUE); } } return(FALSE); } /*********************************************************************/ /* INSERT_PREFIX: */ /*********************************************************************/ /* This procedure takes as argument an item and inserts the string */ /* prefix of the item preceeding the "dot" into the scope table, if */ /* that string is not already there. In any case, the index number */ /* associated with the prefix in question is returned. */ /* NOTE that since both prefixes and suffixes are entered in the */ /* table, the prefix of a given item, ITEM_NO, is encoded as */ /* -ITEM_NO, whereas the suffix of that item is encoded as +ITEM_NO. */ /*********************************************************************/ static insert_prefix(int item_no) { int i, j, rule_no; unsigned long hash_address = 0; rule_no = item_table[item_no].rule_number; for (i = rules[rule_no].rhs; /* symbols before dot */ i < rules[rule_no].rhs + item_table[item_no].dot; i++) hash_address += rhs_sym[i]; i = hash_address % SCOPE_SIZE; for (j = scope_table[i]; j != NIL; j = scope_element[j].link) { if (is_prefix_equal(scope_element[j].item, item_no)) return(scope_element[j].index); } scope_top++; scope_element[scope_top].item = -item_no; scope_element[scope_top].index = scope_rhs_size + 1; scope_element[scope_top].link = scope_table[i]; scope_table[i] = scope_top; scope_rhs_size += (item_table[item_no].dot + 1); return(scope_element[scope_top].index); } /******************************************************************/ /* IS_PREFIX_EQUAL: */ /******************************************************************/ /* This boolean function takes two items as arguments and checks */ /* whether or not they have the same prefix. */ /******************************************************************/ static BOOLEAN is_prefix_equal(int item_no, int item_no2) { int item_no1, start, dot, i, j; if (item_no > 0) /* a suffix */ return(FALSE); item_no1 = -item_no; if (item_table[item_no1].dot != item_table[item_no2].dot) return(FALSE); j = rules[item_table[item_no1].rule_number].rhs; start = rules[item_table[item_no2].rule_number].rhs; dot = start + item_table[item_no2].dot - 1; for (i = start; i <= dot; i++) /* symbols before dot */ { if (rhs_sym[i] != rhs_sym[j]) return(FALSE); j++; } return(TRUE); } /*********************************************************************/ /* INSERT_SUFFIX: */ /*********************************************************************/ /* This procedure is analoguous to INSERT_PREFIX. It takes as */ /* argument an item, and inserts the suffix string following the dot */ /* in the item into the scope table, if it is not already there. */ /* In any case, it returns the index associated with the suffix. */ /* When inserting a suffix into the table, all nullable nonterminals */ /* in the suffix are disregarded. */ /*********************************************************************/ static insert_suffix(int item_no) { int i, j, rule_no, num_elements = 0; unsigned long hash_address = 0; rule_no = item_table[item_no].rule_number; for (i = rules[rule_no].rhs + item_table[item_no].dot; i < rules[rule_no + 1].rhs; /* symbols after dot */ i++) { if (rhs_sym[i] IS_A_NON_TERMINAL) { if (! null_nt[rhs_sym[i]]) { hash_address += rhs_sym[i]; num_elements++; } } else if (rhs_sym[i] != error_image) { hash_address += rhs_sym[i]; num_elements++; } } i = hash_address % SCOPE_SIZE; for (j = scope_table[i]; j != NIL; j = scope_element[j].link) { if (is_suffix_equal(scope_element[j].item, item_no)) return(scope_element[j].index); } scope_top++; scope_element[scope_top].item = item_no; scope_element[scope_top].index = scope_rhs_size + 1; scope_element[scope_top].link = scope_table[i]; scope_table[i] = scope_top; scope_rhs_size += (num_elements + 1); return(scope_element[scope_top].index); } /******************************************************************/ /* IS_SUFFIX_EQUAL: */ /******************************************************************/ /* This boolean function takes two items as arguments and checks */ /* whether or not they have the same suffix. */ /******************************************************************/ static BOOLEAN is_suffix_equal(int item_no1, int item_no2) { int rule_no, dot1, dot2, i, j; if (item_no1 < 0) /* a prefix */ return(FALSE); rule_no = item_table[item_no1].rule_number; i = rules[rule_no].rhs + item_table[item_no1].dot; dot1 = rules[rule_no + 1].rhs - 1; rule_no = item_table[item_no2].rule_number; j = rules[rule_no].rhs + item_table[item_no2].dot; dot2 = rules[rule_no + 1].rhs - 1; while (i <= dot1 && j <= dot2) /* non-nullable syms before dot */ { if (rhs_sym[i] IS_A_NON_TERMINAL) { if (null_nt[rhs_sym[i]]) { i++; continue; } } else if (rhs_sym[i] == error_image) { i++; continue; } if (rhs_sym[j] IS_A_NON_TERMINAL) { if (null_nt[rhs_sym[j]]) { j++; continue; } } else if (rhs_sym[j] == error_image) { j++; continue; } if (rhs_sym[i] != rhs_sym[j]) return(FALSE); j++; i++; } for (; i <= dot1; i++) { if (rhs_sym[i] IS_A_NON_TERMINAL) { if (! null_nt[rhs_sym[i]]) return(FALSE); } else if (rhs_sym[i] != error_image) return(FALSE); } for (; j <= dot2; j++) { if (rhs_sym[j] IS_A_NON_TERMINAL) { if (! null_nt[rhs_sym[j]]) return(FALSE); } else if (rhs_sym[j] != error_image) return(FALSE); } return(TRUE); } /******************************************************************/ /* PRINT_SCOPES: */ /******************************************************************/ /* This procedure is similar to the global procedure PTITEM. */ /******************************************************************/ static void print_scopes(void) { int len, offset, i, k, symbol; char line[PRINT_LINE_SIZE + 1], tok[SYMBOL_SIZE + 1], tmp[PRINT_LINE_SIZE]; PR_HEADING; fprintf(syslis, "\nScopes:\n"); output_line_no += 2; for (k=1; k <= num_scopes; k++) { symbol = scope[k].lhs_symbol; restore_symbol(tok, RETRIEVE_STRING(symbol)); len = PRINT_LINE_SIZE - 5; print_large_token(line, tok, "", len); strcat(line, " ::= "); i = (PRINT_LINE_SIZE / 2) - 1; offset = MIN(strlen(line) - 1, i); len = PRINT_LINE_SIZE - (offset + 4); /* locate end of list */ for (i = scope[k].prefix; scope_right_side[i] != 0; i++) ; for (i = i - 1; i >= scope[k].prefix; i--) /* symbols before dot */ { symbol = scope_right_side[i]; restore_symbol(tok, RETRIEVE_STRING(symbol)); if (strlen(line) + strlen(tok) > PRINT_LINE_SIZE - 4) { fprintf(syslis, "\n%s", line); ENDPAGE_CHECK; fill_in(tmp, offset, ' '); print_large_token(line, tok, tmp, len); } else strcat(line, tok); strcat(line, BLANK); } /*********************************************************************/ /* We now add a dot "." to the output line, and print the remaining */ /* symbols in the right hand side. */ /*********************************************************************/ strcat(line, " ."); len = PRINT_LINE_SIZE - (offset + 1); for (i = scope[k].suffix; scope_right_side[i] != 0; i++) { symbol = scope_right_side[i]; restore_symbol(tok, RETRIEVE_STRING(symbol)); if (strlen(line) + strlen(tok) > PRINT_LINE_SIZE - 1) { fprintf(syslis, "\n%s", line); ENDPAGE_CHECK; fill_in(tmp, offset, ' '); print_large_token(line, tok, tmp, len); } else strcat(line, tok); strcat(line, BLANK); } fprintf(syslis, "\n%s", line); ENDPAGE_CHECK; } return; } /*********************************************************************/ /* GET_SHIFT_SYMBOL: */ /*********************************************************************/ /* This procedure takes as parameter a nonterminal, LHS_SYMBOL, and */ /* determines whether or not there is a terminal symbol t such that */ /* LHS_SYMBOL can rightmost produce a string tX. If so, t is */ /* returned, otherwise EMPTY is returned. */ /*********************************************************************/ static get_shift_symbol(int lhs_symbol) { int item_no, rule_no, symbol; BOOLEAN end_node; struct node *p; if (! symbol_seen[lhs_symbol]) { symbol_seen[lhs_symbol] = TRUE; for (end_node = ((p = clitems[lhs_symbol]) == NULL); ! end_node; end_node = (p == clitems[lhs_symbol])) { p = p -> next; item_no = p -> value; rule_no = item_table[item_no].rule_number; if (RHS_SIZE(rule_no) > 0) { symbol = rhs_sym[rules[rule_no].rhs]; if (symbol IS_A_TERMINAL) return(symbol); else { symbol = get_shift_symbol(symbol); if (symbol != empty) return(symbol); } } } } return(empty); } jikespg-1.3/src/ptables.c000066400000000000000000000416551167345774400154330ustar00rootroot00000000000000/* $Id: ptables.c,v 1.2 1999/11/04 14:02:23 shields Exp $ */ /* This software is subject to the terms of the IBM Jikes Compiler License Agreement available at the following URL: http://www.ibm.com/research/jikes. Copyright (C) 1983, 1999, International Business Machines Corporation and others. All Rights Reserved. You must accept the terms of that agreement to use this software. */ static char hostfile[] = __FILE__; #include "common.h" #include "header.h" struct action_element { struct action_element *next; short count, action; }; /****************************************************************************/ /* PROCESS_SHIFT_ACTIONS: */ /****************************************************************************/ /* The array ACTION_COUNT is used to construct a map from each terminal */ /* into the set (list) of actions defined on that terminal. A count of the */ /* number of occurences of each action in the automaton is kept. */ /* This procedure is invoked with a specific shift map which it processes */ /* and updates the ACTION_COUNT map accordingly. */ /****************************************************************************/ static void process_shift_actions(struct action_element **action_count, int shift_no) { struct shift_header_type sh; struct action_element *q; int symbol, act, i; sh = shift[shift_no]; for (i = 1; i <= sh.size; i++) { symbol = SHIFT_SYMBOL(sh, i); act = SHIFT_ACTION(sh, i); for (q = action_count[symbol]; q != NULL; q = q -> next) { if (q -> action == act) break; } if (q == NULL) /* new action not yet seen */ { q = (struct action_element *) talloc(sizeof(struct action_element)); if (q == NULL) nospace(__FILE__, __LINE__); q -> action = act; q -> count = 1; q -> next = action_count[symbol]; action_count[symbol] = q; } else (q -> count)++; } return; } /****************************************************************************/ /* COMPUTE_SHIFT_DEFAULT: */ /****************************************************************************/ /* This procedure updates the vector SHIFTDF, indexable by the terminals in */ /* the grammar. Its task is to assign to each element of SHIFTDF, the action*/ /* most frequently defined on the symbol in question. */ /****************************************************************************/ static void compute_shift_default(void) { struct action_element **action_count, *q; int state_no, symbol, default_action, max_count, shift_count = 0, shift_reduce_count = 0; /******************************************************************/ /* Set up a a pool of temporary space. */ /******************************************************************/ reset_temporary_space(); shiftdf = Allocate_short_array(num_terminals + 1); action_count = (struct action_element **) calloc(num_terminals + 1, sizeof(struct action_element *)); if (action_count == NULL) nospace(__FILE__, __LINE__); /*******************************************************************/ /* For each state, invoke PROCESS_SHIFT_ACTIONS to process the */ /* shift map associated with that state. */ /*******************************************************************/ for ALL_STATES(state_no) { process_shift_actions(action_count, statset[state_no].shift_number); } for ALL_LA_STATES(state_no) { process_shift_actions(action_count, lastats[state_no].shift_number); } /*********************************************************************/ /* We now iterate over the ACTION_COUNT mapping, and for each */ /* terminal t, initialize SHIFTDF[t] to the action that is most */ /* frequently defined on t. */ /*********************************************************************/ for ALL_TERMINALS(symbol) { max_count = 0; default_action = 0; for (q = action_count[symbol]; q != NULL; q = q -> next) { if (q -> count > max_count) { max_count = q -> count; default_action = q -> action; } } shiftdf[symbol] = default_action; if (default_action > 0) /* A state number ? */ shift_count += max_count; else shift_reduce_count += max_count; } sprintf(msg_line, "Number of Shift entries saved by default: %d", shift_count); PRNT(msg_line); sprintf(msg_line, "Number of Shift/Reduce entries saved by default: %d", shift_reduce_count); PRNT(msg_line); num_shifts -= shift_count; num_shift_reduces -= shift_reduce_count; num_entries = num_entries - shift_count - shift_reduce_count; ffree(action_count); return; } /*****************************************************************************/ /* COMPUTE_GOTO_DEFAULT: */ /*****************************************************************************/ /* COMPUTE_GOTO_DEFAULT constructs the vector GOTODEF, which is indexed by */ /* the non-terminals in the grammar. Its task is to assign to each element */ /* of the array the Action which is most frequently defined on the symbol in */ /* question, and remove all such actions from the state automaton. */ /*****************************************************************************/ static void compute_goto_default(void) { struct goto_header_type go_to; struct action_element **action_count, *q; int state_no, symbol, default_action, act, i, k, max_count, goto_count = 0, goto_reduce_count = 0; /******************************************************************/ /* Set up a a pool of temporary space. */ /******************************************************************/ reset_temporary_space(); gotodef = Allocate_short_array(num_non_terminals); gotodef -= (num_terminals + 1); action_count = (struct action_element **) calloc(num_non_terminals, sizeof(struct action_element *)); action_count -= (num_terminals + 1); if (action_count == NULL) nospace(__FILE__, __LINE__); /*******************************************************************/ /* The array ACTION_COUNT is used to construct a map from each */ /* non-terminal into the set (list) of actions defined on that */ /* non-terminal. A count of how many occurences of each action */ /* is also kept. */ /* This loop is analoguous to the loop in PROCESS_SHIFT_ACTIONS. */ /*******************************************************************/ for ALL_STATES(state_no) { go_to = statset[state_no].go_to; for (i = 1; i <= go_to.size; i++) { symbol = GOTO_SYMBOL(go_to, i); act = GOTO_ACTION(go_to, i); for (q = action_count[symbol]; q != NULL; q = q -> next) { if (q -> action == act) break; } if (q == NULL) /* new action not yet seen */ { q = (struct action_element *) talloc(sizeof(struct action_element)); if (q == NULL) nospace(__FILE__, __LINE__); q -> action = act; q -> count = 1; q -> next = action_count[symbol]; action_count[symbol] = q; } else (q -> count)++; } } /*******************************************************************/ /* We now iterate over the mapping created above and for each */ /* non-terminal A, initialize GOTODEF(A) to the action that is */ /* most frequently defined on A. */ /*******************************************************************/ for ALL_NON_TERMINALS(symbol) { max_count = 0; default_action = 0; for (q = action_count[symbol]; q != NULL; q = q -> next) { if (q -> count > max_count) { max_count = q -> count; default_action = q -> action; } } gotodef[symbol] = default_action; if (default_action > 0) /* A state number? */ goto_count += max_count; else goto_reduce_count += max_count; } /***********************************************************************/ /* We now iterate over the automaton and eliminate all GOTO actions */ /* for which there is a DEFAULT. */ /***********************************************************************/ for ALL_STATES(state_no) { k = 0; go_to = statset[state_no].go_to; for (i = 1; i <= go_to.size; i++) { if (gotodef[GOTO_SYMBOL(go_to, i)] != GOTO_ACTION(go_to, i)) { k++; GOTO_SYMBOL(go_to, k) = GOTO_SYMBOL(go_to, i); GOTO_ACTION(go_to, k) = GOTO_ACTION(go_to, i); } } statset[state_no].go_to.size = k; /* Readjust size */ } sprintf(msg_line, "Number of Goto entries saved by default: %d", goto_count); PRNT(msg_line); sprintf(msg_line, "Number of Goto/Reduce entries saved by default: %d", goto_reduce_count); PRNT(msg_line); num_gotos -= goto_count; num_goto_reduces -= goto_reduce_count; num_entries = num_entries - goto_count - goto_reduce_count; action_count += (num_terminals + 1); ffree(action_count); return; } /***********************************************************************/ /* PROCESS_TABLES: */ /***********************************************************************/ /* Remap symbols, apply transition default actions and call */ /* appropriate table compression routine. */ /***********************************************************************/ void process_tables(void) { int i, j, state_no, rule_no, symbol; struct goto_header_type go_to; struct shift_header_type sh; struct reduce_header_type red; /*******************************************************************/ /* First, we decrease by 1 the constants NUM_SYMBOLS */ /* and NUM_TERMINALS, remove the EMPTY symbol(1) and remap the */ /* other symbols beginning at 1. If default reduction is */ /* requested, we assume a special DEFAULT_SYMBOL with number zero. */ /*******************************************************************/ eoft_image--; accept_image--; if (error_maps_bit) { error_image--; eolt_image--; } num_terminals--; num_symbols--; /***************************************************************/ /* Remap all the symbols used in GOTO and REDUCE actions. */ /* Remap all the symbols used in GD_RANGE. */ /* Remap all the symbols used in the range of SCOPE. */ /* Release space trapped by the maps IN_STAT and FIRST. */ /***************************************************************/ for ALL_STATES(state_no) { go_to = statset[state_no].go_to; for (i = 1; i <= go_to.size; i++) GOTO_SYMBOL(go_to, i)--; red = reduce[state_no]; for (i = 1; i <= red.size; i++) REDUCE_SYMBOL(red, i)--; } for ALL_LA_STATES(state_no) { red = lastats[state_no].reduce; for (i = 1; i <= red.size; i++) REDUCE_SYMBOL(red, i)--; } for (i = 1; i <= gotodom_size; i++) gd_range[i]--; for (i = 1; i <= num_scopes; i++) { scope[i].lhs_symbol--; scope[i].look_ahead--; } for (i = 1; i <= scope_rhs_size; i++) { if (scope_right_side[i] != 0) scope_right_side[i]--; } /*******************************************************************/ /* Remap all symbols in the domain of the Shift maps. */ /*******************************************************************/ for (i = 1; i <= num_shift_maps; i++) { sh = shift[i]; for (j = 1; j <= sh.size; j++) SHIFT_SYMBOL(sh, j)--; } /*******************************************************************/ /* Remap the left-hand side of all the rules. */ /*******************************************************************/ for ALL_RULES(rule_no) rules[rule_no].lhs--; /*******************************************************************/ /* Remap the dot symbols in ITEM_TABLE. */ /*******************************************************************/ if (error_maps_bit) { for ALL_ITEMS(i) item_table[i].symbol--; } /*******************************************************************/ /* We update the SYMNO map. */ /*******************************************************************/ for ALL_SYMBOLS(symbol) symno[symbol] = symno[symbol + 1]; /*******************************************************************/ /* If Goto Default and/or Shift Default were requested, process */ /* appropriately. */ /*******************************************************************/ if (shift_default_bit) compute_shift_default(); if (goto_default_bit) compute_goto_default(); /******************************************************************/ /* Release the pool of temporary space. */ /******************************************************************/ free_temporary_space(); /*****************************************************************/ /* We allocate the necessary structures, open the appropriate */ /* output file and call the appropriate compression routine. */ /*****************************************************************/ if (error_maps_bit) { naction_symbols = (SET_PTR) calloc(num_states + 1, non_term_set_size * sizeof(BOOLEAN_CELL)); if (naction_symbols == NULL) nospace(__FILE__, __LINE__); action_symbols = (SET_PTR) calloc(num_states + 1, term_set_size * sizeof(BOOLEAN_CELL)); if (action_symbols == NULL) nospace(__FILE__, __LINE__); } output_buffer = (char *) calloc(IOBUFFER_SIZE, sizeof(char)); if (output_buffer == NULL) nospace(__FILE__, __LINE__); if ((! c_bit) && (! cpp_bit) && (! java_bit)) { #if defined(C370) && !defined(CW) int size; size = PARSER_LINE_SIZE ; if (record_format != 'F') size += 4; sprintf(msg_line, "w, recfm=%cB, lrecl=%d", record_format, size); if((systab = fopen(tab_file, msg_line)) == NULL) #else if((systab = fopen(tab_file, "w")) == NULL) #endif { fprintf(stderr, "***ERROR: Table file \"%s\" cannot be opened\n", tab_file); exit(12); } } if (table_opt == OPTIMIZE_SPACE) cmprspa(); else if (table_opt == OPTIMIZE_TIME) cmprtim(); if ((! c_bit) && (! cpp_bit) && (! java_bit)) fclose(systab); /*********************************************************************/ /* If printing of the states was requested, print the new mapping */ /* of the states. */ /*********************************************************************/ if (states_bit) { PR_HEADING; fprintf(syslis, "\nMapping of new state numbers into " "original numbers:\n"); for ALL_STATES(i) fprintf(syslis, "\n%5d ==>> %5d",ordered_state[i], state_list[i]); fprintf(syslis,"\n"); } return; } jikespg-1.3/src/reduce.h000066400000000000000000000047471167345774400152560ustar00rootroot00000000000000/* $Id: reduce.h,v 1.2 1999/11/04 14:02:23 shields Exp $ */ /* This software is subject to the terms of the IBM Jikes Compiler License Agreement available at the following URL: http://www.ibm.com/research/jikes. Copyright (C) 1983, 1999, International Business Machines Corporation and others. All Rights Reserved. You must accept the terms of that agreement to use this software. */ #ifndef REDUCE_INCLUDED #define REDUCE_INCLUDED /***************************************************************************/ /* CONFLICT_SYMBOLS is a mapping from each state into a set of terminal */ /* symbols on which an LALR(1) conflict was detected in the state in */ /* question. */ /* */ /* LA_INDEX and LA_SET are temporary look-ahead sets, each of which will */ /* be pointed to by a GOTO action, and the associated set will be */ /* initialized to READ_SET(S), where S is the state identified by the GOTO */ /* action in question. READ_SET(S) is a set of terminals on which an action*/ /* is defined in state S. See COMPUTE_READ for more details. */ /* LA_TOP is used to compute the number of such sets needed. */ /* */ /* The boolean variable NOT_LRK is used to mark whether or not a grammar */ /* is not LR(k) for any k. NOT_LRK is marked true when either: */ /* 1. The grammar contains a nonterminal A such that A =>+rm A */ /* 2. The automaton contains a cycle with each of its edges labeled */ /* with a nullable nonterminal. */ /* (Note that these are not the only conditions under which a grammar is */ /* not LR(k). In fact, it is an undecidable problem.) */ /* The variable HIGHEST_LEVEL is used to indicate the highest number of */ /* lookahead that was necessary to resolve all conflicts for a given */ /* grammar. If we can detect that the grammar is not LALR(k), we set */ /* HIGHEST_LEVEL to INFINITY. */ /***************************************************************************/ extern struct node **conflict_symbols; extern BOOLEAN_CELL *read_set, *la_set; extern int highest_level; extern long la_top; extern short *la_index; extern BOOLEAN not_lrk; #endif /* REDUCE_INCLUDED */ jikespg-1.3/src/remsp.c000066400000000000000000001770761167345774400151360ustar00rootroot00000000000000/* $Id: remsp.c,v 1.2 1999/11/04 14:02:23 shields Exp $ */ /* This software is subject to the terms of the IBM Jikes Compiler License Agreement available at the following URL: http://www.ibm.com/research/jikes. Copyright (C) 1983, 1999, International Business Machines Corporation and others. All Rights Reserved. You must accept the terms of that agreement to use this software. */ static char hostfile[] = __FILE__; #include "common.h" #include "reduce.h" #include "header.h" #define IS_SP_RHS(symbol) (sp_rules[symbol] != NIL) #define IS_SP_RULE(rule_no) (rule_list[rule_no] != OMEGA) static int max_sp_state; static struct action_element { struct action_element *next; short symbol, action; } **new_action; static struct action_element *action_element_pool = NULL; static struct update_action_element { struct update_action_element *next; short symbol, action, state; } **update_action; static struct sp_state_element { struct sp_state_element *next, *link; struct action_element *action_root; struct node *rule_root, *complete_items; short state_number, rule_count, action_count; } **sp_table; static struct sp_state_element *sp_state_root; static short *sp_rules, *stack, *index_of, *next_rule, *rule_list, **sp_action; static BOOLEAN *is_conflict_symbol; static SET_PTR look_ahead; static int top, symbol_root, rule_root; /**********************************************************************/ /* ALLOCATE_ACTION_ELEMENT: */ /**********************************************************************/ /* This function first tries to recycle an action_element node from a */ /* free list. If the list is empty a new node is allocated from */ /* temporary storage. */ /**********************************************************************/ static struct action_element* allocate_action_element(void) { struct action_element *p; p = action_element_pool; if (p != NULL) action_element_pool = p -> next; else { p = (struct action_element *) talloc(sizeof(struct action_element)); if (p == (struct action_element *) NULL) nospace(__FILE__, __LINE__); } return p; } /**********************************************************************/ /* FREE_ACTION_ELEMENTS: */ /**********************************************************************/ /* This routine returns a list of action_element structures to the */ /* free list. */ /**********************************************************************/ static void free_action_elements(struct action_element *head, struct action_element *tail) { tail -> next = action_element_pool; action_element_pool = head; return; } /**********************************************************************/ /* COMPUTE_SP_MAP: */ /**********************************************************************/ /* Compute_sp_map is an instantiation of the digraph algorithm. It */ /* is invoked repeatedly by remove_single_productions to: */ /* */ /* 1) Partially order the right-hand side of all the single */ /* productions (SP) into a list [A1, A2, A3, ..., An] */ /* such that if Ai -> Aj then i < j. */ /* */ /* 2) As a side effect, it uses the ordering above to order all */ /* the SP rules. */ /* */ /**********************************************************************/ static void compute_sp_map(int symbol) { int indx; int i, lhs_symbol, rule_no; stack[++top] = symbol; indx = top; index_of[symbol] = indx; /**********************************************************************/ /* In this instantiation of the digraph algorithm, two symbols (A, B) */ /* are related if A -> B is a SP and A is the right-hand side of */ /* some other SP rule. */ /**********************************************************************/ for (rule_no = sp_rules[symbol]; rule_no != NIL; rule_no = next_rule[rule_no]) { lhs_symbol = rules[rule_no].lhs; if (IS_SP_RHS(lhs_symbol)) { if (index_of[lhs_symbol] == OMEGA) compute_sp_map(lhs_symbol); index_of[symbol] = MIN(index_of[symbol], index_of[lhs_symbol]); } } /**********************************************************************/ /* If the index of symbol is the same index it started with then */ /* symbol if the root of a SCC... */ /**********************************************************************/ if (index_of[symbol] == indx) { /**************************************************************/ /* If symbol is on top of the stack then it is the only */ /* symbol in its SCC (thus it is not part of a cycle). */ /* Note that since remove_single_productions is only invoked */ /* when the input grammar is conflict-free, the graph of */ /* the single productions will never contain any cycle. */ /* Thus, this test will always succeed and all single */ /* productions associated with the symbol being processed */ /* are added to the list of SP rules here... */ /**************************************************************/ if (stack[top] == symbol) { for (rule_no = sp_rules[symbol]; rule_no != NIL; rule_no = next_rule[rule_no]) { if (rule_root == NIL) rule_list[rule_no] = rule_no; else { rule_list[rule_no] = rule_list[rule_root]; rule_list[rule_root] = rule_no; } rule_root = rule_no; } } /**************************************************************/ /* As all SCC contains exactly one symbol (as explained above)*/ /* this loop will always execute exactly once. */ /**************************************************************/ do { i = stack[top--]; index_of[i] = INFINITY; } while(i != symbol); } return; } /**********************************************************************/ /* COMPUTE_SP_ACTION: */ /**********************************************************************/ /* When the parser enters STATE_NO and it is processing SYMBOL, its */ /* next move is ACTION. Given these 3 parameters, compute_sp_action */ /* computes the set of reduce actions that may be executed after */ /* SYMBOL is shifted in STATE_NO. */ /* */ /* NOTE that this algorithm works only for the LALR(1) case. When the */ /* transition on SYMBOL is a lookahead-shift, indicating that the */ /* parser requires extra lookahead on a particular symbol, the set of */ /* reduce actions for that symbol is calculated as the empty set. */ /**********************************************************************/ static void compute_sp_action(short state_no, short symbol, short action) { struct goto_header_type go_to; struct node *item_ptr; int item_no, rule_no, lhs_symbol, i, k; BOOLEAN end_node; struct node *p; go_to = statset[state_no].go_to; if (sp_action[symbol] == NULL) sp_action[symbol] = Allocate_short_array(num_terminals + 1); for ALL_TERMINALS(i) /* initialize sp_action to the empty map */ sp_action[symbol][i] = OMEGA; /**********************************************************************/ /* Note that before this routine is invoked, the global vector */ /* index_of identifies the index of each symbol in the goto map of */ /* state_no. */ /**********************************************************************/ if (is_conflict_symbol[symbol]) /* do nothing */ ; else if (action > 0) /* transition action (shift or goto) */ { for (item_ptr = statset[action].complete_items; item_ptr != NULL; item_ptr = item_ptr -> next) { item_no = item_ptr -> value; rule_no = item_table[item_no].rule_number; lhs_symbol = rules[rule_no].lhs; if (RHS_SIZE(rule_no) == 1 && lhs_symbol != accept_image) { if (slr_bit) { ASSIGN_SET(look_ahead, 0, follow, lhs_symbol); } else { i = index_of[lhs_symbol]; k = GOTO_LAPTR(go_to, i); if (la_index[k] == OMEGA) { int stack_top = 0; la_traverse(state_no, i, &stack_top); } ASSIGN_SET(look_ahead, 0, la_set, k); } RESET_BIT(look_ahead, empty); /* empty not valid look-ahead */ for ALL_TERMINALS(i) { if (IS_ELEMENT(look_ahead, i)) sp_action[symbol][i] = rule_no; } } } /**************************************************************/ /* Remove all lookahead symbols on which conflicts were */ /* detected from consideration. */ /**************************************************************/ for (end_node = ((p = conflict_symbols[action]) == NULL); ! end_node; end_node = (p == conflict_symbols[action])) { p = p -> next; sp_action[symbol][p -> value] = OMEGA; } } else /* read-reduce action */ { rule_no = -action; if (RHS_SIZE(rule_no) == 1) { lhs_symbol = rules[rule_no].lhs; if (slr_bit) { ASSIGN_SET(look_ahead, 0, follow, lhs_symbol); } else { i = index_of[lhs_symbol]; k = GOTO_LAPTR(go_to, i); if (la_index[k] == OMEGA) { int stack_top = 0; la_traverse(state_no, i, &stack_top); } ASSIGN_SET(look_ahead, 0, la_set, k); } RESET_BIT(look_ahead, empty); /* empty not valid look-ahead */ for ALL_TERMINALS(i) { if (IS_ELEMENT(look_ahead, i)) sp_action[symbol][i] = rule_no; } } } return; } /**********************************************************************/ /* SP_DEFAULT_ACTION: */ /**********************************************************************/ /* Sp_default_action takes as parameter a state, state_no and a rule, */ /* rule_no that may be reduce when the parser enters state_no. */ /* Sp_default_action tries to determine the highest rule that may be */ /* reached via a sequence of SP reductions. */ /**********************************************************************/ static short sp_default_action(short state_no, short rule_no) { struct reduce_header_type red; struct goto_header_type go_to; int lhs_symbol, action, i; go_to = statset[state_no].go_to; /**********************************************************************/ /* While the rule we have at hand is a single production, ... */ /**********************************************************************/ while (IS_SP_RULE(rule_no)) { lhs_symbol = rules[rule_no].lhs; for (i = 1; GOTO_SYMBOL(go_to, i) != lhs_symbol; i++) ; action = GOTO_ACTION(go_to, i); if (action < 0) /* goto-reduce action? */ { action = -action; if (RHS_SIZE(action) != 1) break; rule_no = action; } else { int best_rule = OMEGA; /**************************************************************/ /* Enter the state action and look for preferably a SP rule */ /* or some rule with right-hand size 1. */ /**************************************************************/ red = reduce[action]; for (i = 1; i <= red.size; i++) { action = REDUCE_RULE_NO(red, i); if (IS_SP_RULE(action)) { best_rule = action; break; } if (RHS_SIZE(action) == 1) best_rule = action; } if (best_rule == OMEGA) break; rule_no = best_rule; } } return rule_no; } /**********************************************************************/ /* SP_NT_ACTION: */ /**********************************************************************/ /* This routine takes as parameter a state, state_no, a nonterminal, */ /* lhs_symbol (that is the right-hand side of a SP or a rule with */ /* right-hand size 1, but not identified as a SP) on which there is */ /* a transition in state_no and a lookahead symbol la_symbol that may */ /* be processed after taking the transition. It returns the reduce */ /* action that follows the transition if an action on la_symbol is */ /* found, otherwise it returns the most suitable default action. */ /**********************************************************************/ static short sp_nt_action(short state_no, short lhs_symbol, short la_symbol) { struct reduce_header_type red; struct goto_header_type go_to; int action, rule_no, i; go_to = statset[state_no].go_to; for (i = 1; GOTO_SYMBOL(go_to, i) != lhs_symbol; i++) ; action = GOTO_ACTION(go_to, i); if (action < 0) action = -action; else { red = reduce[action]; action = OMEGA; for (i = 1; i <= red.size; i++) { rule_no = REDUCE_RULE_NO(red, i); if (REDUCE_SYMBOL(red, i) == la_symbol) { action = rule_no; break; } else if (action == OMEGA && IS_SP_RULE(rule_no)) action = rule_no; } } return action; } /**********************************************************************/ /* GREATEST_COMMON_ANCESTOR: */ /**********************************************************************/ /* Let BASE_RULE be a rule A -> X. The item [A -> .X] is in STATE1 */ /* and STATE2. After shifting on X (in STATE1 and STATE2), if the */ /* lookahead is LA_SYMBOL then BASE_RULE is reduced. In STATE1, a */ /* sequence of single-production reductions is executed ending with */ /* a reduction of RULE1. In STATE2, a sequence of single-productions */ /* is also executed ending with RULE2. */ /* The goal of this function is to find the greatest ancestor of */ /* BASE_RULE that is also a descendant of both RULE1 and RULE2. */ /**********************************************************************/ static short greatest_common_ancestor(short base_rule, short la_symbol, short state1, short rule1, short state2, short rule2) { int lhs_symbol, act1, act2, rule_no; act1 = base_rule; act2 = base_rule; while (act1 == act2) { rule_no = act1; if (act1 == rule1 || act2 == rule2) break; lhs_symbol = rules[rule_no].lhs; act1 = sp_nt_action(state1, lhs_symbol, la_symbol); act2 = sp_nt_action(state2, lhs_symbol, la_symbol); } return rule_no; } /**********************************************************************/ /* COMPUTE_UPDATE_ACTION: */ /**********************************************************************/ /* In SOURCE_STATE there is a transition on SYMBOL into STATE_NO. */ /* SYMBOL is the right-hand side of a SP rule and the global map */ /* sp_action[SYMBOL] yields a set of update reduce actions that may */ /* follow the transition on SYMBOL into STATE_NO. */ /**********************************************************************/ static void compute_update_actions(short source_state, short state_no, short symbol) { int i, rule_no; struct reduce_header_type red; struct update_action_element *p; red = reduce[state_no]; for (i = 1; i <= red.size; i++) { if (IS_SP_RULE(REDUCE_RULE_NO(red, i))) { rule_no = sp_action[symbol][REDUCE_SYMBOL(red, i)]; if (rule_no == OMEGA) rule_no = sp_default_action(source_state, REDUCE_RULE_NO(red, i)); /**************************************************************/ /* Lookup the update map to see if a previous update was made */ /* in STATE_NO on SYMBOL... */ /**************************************************************/ for (p = update_action[state_no]; p != NULL; p = p -> next) { if (p -> symbol == REDUCE_SYMBOL(red, i)) break; } /**************************************************************/ /* If no previous update action was defined on STATE_NO and */ /* SYMBOL, simply add it. Otherwise, chose as the greatest */ /* common ancestor of the initial reduce action and the two */ /* contending updates as the update action. */ /**************************************************************/ if (p == NULL) { p = (struct update_action_element *) talloc(sizeof(struct update_action_element)); if (p == (struct update_action_element *) NULL) nospace(__FILE__, __LINE__); p -> next = update_action[state_no]; update_action[state_no] = p; p -> symbol = REDUCE_SYMBOL(red, i); p -> action = rule_no; p -> state = source_state; } else if ((rule_no != p -> action) && (p -> action != REDUCE_RULE_NO(red, i))) { p -> action = greatest_common_ancestor(REDUCE_RULE_NO(red, i), REDUCE_SYMBOL(red, i), source_state, rule_no, p -> state, p -> action); } } } return; } /**********************************************************************/ /* SP_STATE_MAP: */ /**********************************************************************/ /* Sp_state_map is invoked to create a new state using the reduce map */ /* sp_symbol[SYMBOL]. The new state will be entered via a transition */ /* on SYMBOL which is the right-hand side of the SP rule of which */ /* ITEM_NO is the final item. */ /* */ /* RULE_HEAD is the root of a list of rules in the global vector */ /* next_rule. This list of rules identifies the range of the reduce */ /* map sp_symbol[SYMBOL]. The value SP_RULE_COUNT is the number of */ /* rules in the list. The value SP_ACTION_COUNT is the number of */ /* actions in the map sp_symbol[SYMBOL]. */ /**********************************************************************/ static short sp_state_map(int rule_head, short item_no, short sp_rule_count, short sp_action_count, short symbol) { struct sp_state_element *state; struct node *p; int rule_no, i; BOOLEAN no_overwrite; unsigned long hash_address; /******************************************************************/ /* These new SP states are defined by their reduce maps. Hash the */ /* reduce map based on the set of rules in its range - simply add */ /* them up and reduce modulo STATE_TABLE_SIZE. */ /******************************************************************/ hash_address = 0; for (rule_no = rule_head; rule_no != NIL; rule_no = next_rule[rule_no]) hash_address += rule_no; hash_address %= STATE_TABLE_SIZE; /******************************************************************/ /* Search the hash table for a compatible state. Two states S1 */ /* and S2 are compatible if */ /* 1) the set of rules in their reduce map is identical. */ /* 2) for each terminal symbol t, either */ /* reduce[S1][t] == reduce[S2][t] or */ /* reduce[S1][t] == OMEGA or */ /* reduce[S2][t] == OMEGA */ /* */ /******************************************************************/ for (state = sp_table[hash_address]; state != NULL; state = state -> link) { if (state -> rule_count == sp_rule_count) /* same # of rules? */ { for (p = state -> rule_root; p != NULL; p = p -> next) { if (next_rule[p -> value] == OMEGA) /* not in list? */ break; } /******************************************************************/ /* If the set of rules are identical, we proceed to compare the */ /* actions for compatibility. The idea is to make sure that all */ /* actions in the hash table do not clash in the actions in the */ /* map sp_action[SYMBOL]. */ /******************************************************************/ if (p == NULL) /* all the rules match? */ { struct action_element *actionp, *action_tail; for (actionp = state -> action_root; actionp != NULL; actionp = actionp -> next) { if (sp_action[symbol][actionp -> symbol] != OMEGA && sp_action[symbol][actionp -> symbol] != actionp -> action) break; } /**************************************************************/ /* If the two states are compatible merge them into the map */ /* sp_action[SYMBOL]. (Note that this effectively destroys */ /* the original map.) Also, keep track of whether or not an */ /* actual merging action was necessary with the boolean */ /* variable no_overwrite. */ /**************************************************************/ if (actionp == NULL) /* compatible states */ { no_overwrite = TRUE; for (actionp = state -> action_root; actionp != NULL; action_tail = actionp, actionp = actionp -> next) { if (sp_action[symbol][actionp -> symbol] == OMEGA) { sp_action[symbol][actionp -> symbol] = actionp -> action; no_overwrite = FALSE; } } /**********************************************************/ /* If the item was not previously associated with this */ /* state, add it. */ /**********************************************************/ for (p = state -> complete_items; p != NULL; p = p -> next) { if (p -> value == item_no) break; } if (p == NULL) { p = Allocate_node(); p -> value = item_no; p -> next = state -> complete_items; state -> complete_items = p; } /**********************************************************/ /* If the two maps are identical (there was no merging), */ /* return the state number otherwise, free the old map */ /* and break out of the search loop. */ /**********************************************************/ if (no_overwrite && state -> action_count == sp_action_count) return state -> state_number; free_action_elements(state -> action_root, action_tail); break; /* for (state = sp_table[hash_address]; ... */ } } } } /******************************************************************/ /* If we did not find a compatible state, construct a new one. */ /* Add it to the list of state and add it to the hash table. */ /******************************************************************/ if (state == NULL) { state = (struct sp_state_element *) talloc(sizeof(struct sp_state_element)); if (state == NULL) nospace(__FILE__, __LINE__); state -> next = sp_state_root; sp_state_root = state; state -> link = sp_table[hash_address]; sp_table[hash_address] = state; max_sp_state++; state -> state_number = max_sp_state; state -> rule_count = sp_rule_count; p = Allocate_node(); p -> value = item_no; p -> next = NULL; state -> complete_items = p; state -> rule_root = NULL; for (rule_no = rule_head; rule_no != NIL; rule_no = next_rule[rule_no]) { p = Allocate_node(); p -> value = rule_no; p -> next = state -> rule_root; state -> rule_root = p; } } /******************************************************************/ /* If the state is new or had its reduce map merged with another */ /* map, we update the reduce map here. */ /******************************************************************/ state -> action_count = sp_action_count; state -> action_root = NULL; for ALL_TERMINALS(i) { struct action_element *actionp; if (sp_action[symbol][i] != OMEGA) { actionp = allocate_action_element(); actionp -> symbol = i; actionp -> action = sp_action[symbol][i]; actionp -> next = state -> action_root; state -> action_root = actionp; } } return state -> state_number; } /*****************************************************************************/ /* REMOVE_SINGLE_PRODUCTIONS: */ /*****************************************************************************/ /* This program is invoked to remove as many single production actions as */ /* possible for a conflict-free automaton. */ /*****************************************************************************/ void remove_single_productions(void) { struct goto_header_type go_to; struct shift_header_type sh; struct reduce_header_type red; struct sp_state_element *state; struct node *p, *rule_tail; int rule_head, sp_rule_count, sp_action_count, rule_no, state_no, symbol, lhs_symbol, action, item_no, i, j; BOOLEAN end_node; short *symbol_list, *shift_transition, *rule_count; short shift_table[SHIFT_TABLE_SIZE]; struct new_shift_element { short link, shift_number; } *new_shift; /******************************************************************/ /* Set up a a pool of temporary space. */ /******************************************************************/ reset_temporary_space(); /******************************************************************/ /* Allocate all other necessary temporary objects. */ /******************************************************************/ sp_rules = Allocate_short_array(num_symbols + 1); stack = Allocate_short_array(num_symbols + 1); index_of = Allocate_short_array(num_symbols + 1); next_rule = Allocate_short_array(num_rules + 1); rule_list = Allocate_short_array(num_rules + 1); symbol_list = Allocate_short_array(num_symbols + 1); shift_transition = Allocate_short_array(num_symbols + 1); rule_count = Allocate_short_array(num_rules + 1); new_shift = (struct new_shift_element *) calloc(max_la_state + 1, sizeof(struct new_shift_element)); if (new_shift == NULL) nospace(__FILE__, __LINE__); look_ahead = (SET_PTR) calloc(1, term_set_size * sizeof(BOOLEAN_CELL)); if (look_ahead == NULL) nospace(__FILE__, __LINE__); sp_action = (short **) calloc(num_symbols + 1, sizeof(short *)); if (sp_action == NULL) nospace(__FILE__, __LINE__); is_conflict_symbol = (BOOLEAN *) calloc(num_symbols + 1, sizeof(BOOLEAN)); if (is_conflict_symbol == NULL) nospace(__FILE__, __LINE__); sp_table = (struct sp_state_element **) calloc(STATE_TABLE_SIZE, sizeof(struct sp_state_element *)); if (sp_table == NULL) nospace(__FILE__, __LINE__); new_action = (struct action_element **) calloc(num_states + 1, sizeof(struct action_element *)); if (new_action == NULL) nospace(__FILE__, __LINE__); update_action = (struct update_action_element **) calloc(num_states + 1, sizeof(struct update_action_element *)); if (update_action == NULL) nospace(__FILE__, __LINE__); /******************************************************************/ /* Initialize all relevant sets and maps to the empty set. */ /******************************************************************/ rule_root = NIL; symbol_root = NIL; for ALL_RULES(i) rule_list[i] = OMEGA; for ALL_SYMBOLS(i) { symbol_list[i] = OMEGA; sp_rules[i] = NIL; sp_action[i] = NULL; } /******************************************************************/ /* Construct a set of all symbols used in the right-hand side of */ /* single production in symbol_list. The variable symbol_root */ /* points to the root of the list. Also, construct a mapping from */ /* each symbol into the set of single productions of which it is */ /* the right-hand side. sp_rules is the base of that map and the */ /* relevant sets are stored in the vector next_rule. */ /******************************************************************/ for ALL_RULES(rule_no) { if (rules[rule_no].sp) { i = rhs_sym[rules[rule_no].rhs]; next_rule[rule_no] = sp_rules[i]; sp_rules[i] = rule_no; if (symbol_list[i] == OMEGA) { symbol_list[i] = symbol_root; symbol_root = i; } } } /******************************************************************/ /* Initialize the index_of vector and clear the stack (top). */ /* Next, iterate over the list of right-hand side symbols used in */ /* single productions and invoke compute_sp_map to partially */ /* order these symbols (based on the ::= (or ->) relationship) as */ /* well as their associated rules. (See compute_sp_map for detail)*/ /* As the list of rules is constructed as a circular list to keep */ /* it in proper order, it is turned into a linear list here. */ /******************************************************************/ for (i = symbol_root; i != NIL; i = symbol_list[i]) index_of[i] = OMEGA; top = 0; for (i = symbol_root; i != NIL; i = symbol_list[i]) { if (index_of[i] == OMEGA) compute_sp_map(i); } if (rule_root != NIL) /* make rule_list non-circular */ { rule_no = rule_root; rule_root = rule_list[rule_no]; rule_list[rule_no] = NIL; } /******************************************************************/ /* Clear out all the sets in sp_rules and using the new revised */ /* list of SP rules mark the new set of right-hand side symbols. */ /* Note this code is important for consistency in case we are */ /* removing single productions in an automaton containing */ /* conflicts. If an automaton does not contain any conflict, the */ /* new set of SP rules is always the same as the initial set. */ /******************************************************************/ for (i = symbol_root; i != NIL; i = symbol_list[i]) sp_rules[i] = NIL; top = 0; for (rule_no = rule_root; rule_no != NIL; rule_no = rule_list[rule_no]) { top++; i = rhs_sym[rules[rule_no].rhs]; sp_rules[i] = OMEGA; } /******************************************************************/ /* Initialize the base of the hash table for the new SP states. */ /* Initialize the root pointer for the list of new states. */ /* Initialize max_sp_state to num_states. It will be incremented */ /* each time a new state is constructed. */ /* Initialize the update_action table. */ /* Initialize the is_conflict_symbol array for non_terminals. */ /* Since nonterminals are not used as lookahead symbols, they are */ /* never involved in conflicts. */ /* Initialize the set/list (symbol_root, symbol_list) to the */ /* empty set/list. */ /******************************************************************/ for (i = 0; i < STATE_TABLE_SIZE; i++) sp_table[i] = NULL; sp_state_root = NULL; max_sp_state = num_states; for ALL_STATES(state_no) update_action[state_no] = NULL; for ALL_NON_TERMINALS(i) is_conflict_symbol[i] = FALSE; symbol_root = NIL; for ALL_SYMBOLS(i) symbol_list[i] = OMEGA; /******************************************************************/ /* Traverse all regular states and process the relevant ones. */ /******************************************************************/ for ALL_STATES(state_no) { struct node *item_ptr; new_action[state_no] = NULL; go_to = statset[state_no].go_to; sh = shift[statset[state_no].shift_number]; /**************************************************************/ /* If the state has no goto actions, it is not considered, as */ /* no single productions could have been introduced in it. */ /* Otherwise, we initialize index_of to the empty map and */ /* presume that symbol_list is initialized to the empty set. */ /**************************************************************/ if (go_to.size > 0) { for ALL_SYMBOLS(i) index_of[i] = OMEGA; for ALL_TERMINALS(i) is_conflict_symbol[i] = FALSE; for (end_node = ((p = conflict_symbols[state_no]) == NULL); ! end_node; end_node = (p == conflict_symbols[state_no])) { p = p -> next; is_conflict_symbol[p -> value] = TRUE; } /**********************************************************/ /* First, use index_of to map each nonterminal symbol on */ /* which there is a transition in state_no into its index */ /* in the goto map of state_no. */ /* Note that this initialization must be executed first */ /* before we process the next loop, because index_of is */ /* a global variable that is used in the routine */ /* compute_sp_action. */ /**********************************************************/ for (i = 1; i <= go_to.size; i++) index_of[GOTO_SYMBOL(go_to, i)] = i; /**********************************************************/ /* Traverse first the goto map, then the shift map and */ /* for each symbol that is the right-hand side of a single*/ /* production on which there is a transition, compute the */ /* lookahead set that can follow this transition and add */ /* the symbol to the set of candidates (in symbol_list). */ /**********************************************************/ for (i = 1; i <= go_to.size; i++) { symbol = GOTO_SYMBOL(go_to, i); if (IS_SP_RHS(symbol)) { compute_sp_action(state_no, symbol, GOTO_ACTION(go_to, i)); symbol_list[symbol] = symbol_root; symbol_root = symbol; } } for (i = 1; i <= sh.size; i++) { symbol = SHIFT_SYMBOL(sh, i); index_of[symbol] = i; if (IS_SP_RHS(symbol)) { compute_sp_action(state_no, symbol, SHIFT_ACTION(sh, i)); symbol_list[symbol] = symbol_root; symbol_root = symbol; } } /**********************************************************/ /* We now traverse the set of single productions in order */ /* and for each rule that was introduced through closure */ /* in the state (there is an action on both the left- and */ /* right-hand side)... */ /**********************************************************/ for (rule_no = rule_root; rule_no != NIL; rule_no = rule_list[rule_no]) { symbol = rhs_sym[rules[rule_no].rhs]; if (symbol_list[symbol] != OMEGA) { lhs_symbol = rules[rule_no].lhs; if (index_of[lhs_symbol] != OMEGA) { if (symbol_list[lhs_symbol] == OMEGA) { compute_sp_action(state_no, lhs_symbol, GOTO_ACTION(go_to, index_of[lhs_symbol])); symbol_list[lhs_symbol] = symbol_root; symbol_root = lhs_symbol; } /******************************************************/ /* Copy all reduce actions defined after the */ /* transition on the left-hand side into the */ /* corresponding action defined after the transition */ /* on the right-hand side. If an action is defined */ /* for the left-hand side - */ /* */ /* sp_action[lhs_symbol][i] != OMEGA */ /* */ /* - but not for the right-hand side - */ /* */ /* sp_action[symbol][i] == OMEGA */ /* */ /* it is an indication that after the transition on */ /* symbol, the action on i is a lookahead shift. In */ /* that case, no action is copied. */ /******************************************************/ for ALL_TERMINALS(i) { if (sp_action[lhs_symbol][i] != OMEGA && sp_action[symbol][i] != OMEGA) sp_action[symbol][i] = sp_action[lhs_symbol][i]; } } } } /**********************************************************/ /* For each symbol that is the right-hand side of some SP */ /* for which a reduce map is defined, we either construct */ /* a new state if the transition is into a final state, */ /* or we update the relevant reduce action of the state */ /* into which the transition is made, otherwise. */ /* */ /* When execution of this loop is terminated the set */ /* symbol_root/symbol_list is reinitialize to the empty */ /* set. */ /**********************************************************/ for (symbol = symbol_root; symbol != NIL; symbol_list[symbol] = OMEGA, symbol = symbol_root) { symbol_root = symbol_list[symbol]; if (IS_SP_RHS(symbol)) { if (symbol IS_A_TERMINAL) action = SHIFT_ACTION(sh, index_of[symbol]); else action = GOTO_ACTION(go_to, index_of[symbol]); /******************************************************/ /* If the transition is a lookahead shift, do nothing.*/ /* If the action is a goto- or shift-reduce, compute */ /* the relevant rule and item involved. */ /* Otherwise, the action is a shift or a goto. If the */ /* transition is into a final state then it is */ /* processed as the case of read-reduce above. If */ /* not, we invoke compute_update_actions to update */ /* the relevant actions. */ /******************************************************/ if (action > num_states) /* lookahead shift */ rule_no = OMEGA; else if (action < 0) /* read-reduce action */ { rule_no = -action; item_no = adequate_item[rule_no] -> value; } else /* transition action */ { item_ptr = statset[action].kernel_items; item_no = item_ptr -> value; if ((item_ptr -> next == NULL) && (item_table[item_no].symbol == empty)) rule_no = item_table[item_no].rule_number; else { compute_update_actions(state_no, action, symbol); rule_no = OMEGA; } } /******************************************************/ /* If we have a valid SP rule we first construct the */ /* set of rules in the range of the reduce map of the */ /* right-hand side of the rule. If that set contains */ /* a single rule then the action on the right-hand */ /* side is redefined as the same action on the left- */ /* hand side of the rule in question. Otherwise, we */ /* create a new state for the final item of the SP */ /* rule consisting of the reduce map associated with */ /* the right-hand side of the SP rule and the new */ /* action on the right-hand side is a transition into */ /* this new state. */ /******************************************************/ if (rule_no != OMEGA) { if (IS_SP_RULE(rule_no)) { struct action_element *p; sp_rule_count = 0; sp_action_count = 0; rule_head = NIL; for ALL_RULES(i) next_rule[i] = OMEGA; for ALL_TERMINALS(i) { rule_no = sp_action[symbol][i]; if (rule_no != OMEGA) { sp_action_count++; if (next_rule[rule_no] == OMEGA) { sp_rule_count++; next_rule[rule_no] = rule_head; rule_head = rule_no; } } } if (sp_rule_count == 1 && IS_SP_RULE(rule_head)) { lhs_symbol = rules[rule_head].lhs; action = GOTO_ACTION(go_to, index_of[lhs_symbol]); } else { action = sp_state_map(rule_head, item_no, sp_rule_count, sp_action_count, symbol); } p = allocate_action_element(); p -> symbol = symbol; p -> action = action; p -> next = new_action[state_no]; new_action[state_no] = p; } } } } } } /* for ALL_STATES(state_no) */ /******************************************************************/ /* We are now ready to extend all global maps based on states and */ /* permanently install the new states. */ /******************************************************************/ statset = (struct statset_type *) realloc(statset, (max_sp_state + 1) * sizeof(struct statset_type)); if (statset == NULL) nospace(__FILE__, __LINE__); reduce = (struct reduce_header_type *) realloc(reduce, (max_sp_state + 1) * sizeof(struct reduce_header_type)); if (reduce == NULL) nospace(__FILE__, __LINE__); if (gd_index != NULL) /* see routine PRODUCE */ { gd_index = (short *) realloc(gd_index, (max_sp_state + 2) * sizeof(short)); if (gd_index == NULL) nospace(__FILE__, __LINE__); /**************************************************************/ /* Each element gd_index[i] points to the starting location */ /* of a slice in another array. The last element of the slice */ /* can be computed as (gd_index[i+1] - 1). After extending */ /* gd_index, we set each new element to point to the same */ /* index as its previous element, making it point to a null */ /* slice. */ /**************************************************************/ for (state_no = num_states + 2; state_no <= max_sp_state + 1; state_no++) gd_index[state_no] = gd_index[state_no - 1]; } in_stat = (struct node **) realloc(in_stat, (max_sp_state + 1) * sizeof(struct node *)); if (in_stat == NULL) nospace(__FILE__, __LINE__); for (state_no = num_states + 1; state_no <= max_sp_state; state_no++) in_stat[state_no] = NULL; /******************************************************************/ /* We now adjust all references to a lookahead state. The idea is */ /* offset the number associated with each lookahead state by the */ /* number of new SP states that were added. */ /******************************************************************/ for (j = 1; j <= num_shift_maps; j++) { sh = shift[j]; for (i = 1; i <= sh.size; i++) { if (SHIFT_ACTION(sh, i) > num_states) SHIFT_ACTION(sh, i) += (max_sp_state - num_states); } } for (state_no = num_states + 1; state_no <= max_la_state; state_no++) { if (lastats[state_no].in_state > num_states) lastats[state_no].in_state += (max_sp_state - num_states); } lastats -= (max_sp_state - num_states); max_la_state += (max_sp_state - num_states); SHORT_CHECK(max_la_state); /******************************************************************/ /* We now permanently construct all the new SP states. */ /******************************************************************/ for (state = sp_state_root; state != NULL; state = state -> next) { struct action_element *actionp; int default_rule, reduce_size; state_no = state -> state_number; /**************************************************************/ /* These states are identified as special SP states since */ /* they have no kernel items. They also have no goto and */ /* shift actions. */ /**************************************************************/ statset[state_no].kernel_items = NULL; statset[state_no].complete_items = state -> complete_items; statset[state_no].go_to.size = 0; statset[state_no].go_to.map = NULL; statset[state_no].shift_number = 0; /**************************************************************/ /* Count the number of actions defined on each rule in the */ /* range of the reduce map. */ /**************************************************************/ for (p = state -> rule_root; p != NULL; p = p -> next) rule_count[p -> value] = 0; for (actionp = state -> action_root; actionp != NULL; actionp = actionp -> next) rule_count[actionp -> action]++; /**************************************************************/ /* Count the total number of reduce actions in the reduce map */ /* and calculate the default. */ /**************************************************************/ reduce_size = 0; sp_rule_count = 0; for (p = state -> rule_root; p != NULL; rule_tail = p, p = p -> next) { reduce_size += rule_count[p -> value]; if (rule_count[p -> value] > sp_rule_count) { sp_rule_count = rule_count[p -> value]; default_rule = p -> value; } } free_nodes(state -> rule_root, rule_tail); /**************************************************************/ /* Construct a permanent reduce map for this SP state. */ /**************************************************************/ num_reductions += reduce_size; red = Allocate_reduce_map(reduce_size); reduce[state_no] = red; REDUCE_SYMBOL(red, 0) = DEFAULT_SYMBOL; REDUCE_RULE_NO(red, 0) = default_rule; for (actionp = state -> action_root; actionp != NULL; actionp = actionp -> next) { REDUCE_SYMBOL(red, reduce_size) = actionp -> symbol; REDUCE_RULE_NO(red, reduce_size) = actionp -> action; reduce_size--; } } /******************************************************************/ /* We are now ready to update some old actions and add new ones. */ /* This may require that we create new shift maps. We */ /* initialize top to 0 so we can use it as an index to allocate */ /* elements from new_shift. We also initialize all the elements */ /* of shift_table to NIL. Shift_table will be used as the base of */ /* a hash table for the new shift maps. */ /******************************************************************/ top = 0; for (i = 0; i <= SHIFT_TABLE_UBOUND; i++) shift_table[i] = NIL; /******************************************************************/ /* At most, the shift array contains 1..num_states elements. As, */ /* each of these elements might be (theoretically) replaced by a */ /* new one, we need to double its size. */ /******************************************************************/ shift = (struct shift_header_type *) realloc(shift, 2 * (num_states + 1) * sizeof(struct shift_header_type)); if (shift == NULL) nospace(__FILE__, __LINE__); /******************************************************************/ /* For each state with updates or new actions, take appropriate */ /* actions. */ /******************************************************************/ for ALL_STATES(state_no) { BOOLEAN any_shift_action; /**************************************************************/ /* Update reduce actions for final items of single productions*/ /* that are in non-final states. */ /**************************************************************/ if (update_action[state_no] != NULL) { struct update_action_element *p; red = reduce[state_no]; for (i = 1; i <= red.size; i++) index_of[REDUCE_SYMBOL(red, i)] = i; for (p = update_action[state_no]; p != NULL; p = p -> next) REDUCE_RULE_NO(red, index_of[p -> symbol]) = p -> action; } /**************************************************************/ /* Update initial automaton with transitions into new SP */ /* states. */ /**************************************************************/ if (new_action[state_no] != NULL) { struct action_element *p; /**********************************************************/ /* Mark the index of each symbol on which there is a */ /* transition and copy the shift map into the vector */ /* shift_transition. */ /**********************************************************/ go_to = statset[state_no].go_to; for (i = 1; i <= go_to.size; i++) index_of[GOTO_SYMBOL(go_to, i)] = i; sh = shift[statset[state_no].shift_number]; for (i = 1; i <= sh.size; i++) { index_of[SHIFT_SYMBOL(sh, i)] = i; shift_transition[SHIFT_SYMBOL(sh, i)] = SHIFT_ACTION(sh, i); } /**********************************************************/ /* Iterate over the new action and update the goto map */ /* directly for goto actions but update shift_transition */ /* for shift actions. Also, keep track as to whether or */ /* not there were any shift transitions at all... */ /**********************************************************/ any_shift_action = FALSE; for (p = new_action[state_no]; p != NULL; p = p -> next) { if (p -> symbol IS_A_NON_TERMINAL) { if (GOTO_ACTION(go_to, index_of[p -> symbol]) < 0 && p -> action > 0) { num_goto_reduces--; num_gotos++; } GOTO_ACTION(go_to, index_of[p -> symbol]) = p -> action; } else { if (SHIFT_ACTION(sh, index_of[p -> symbol]) < 0 && p -> action > 0) { num_shift_reduces--; num_shifts++; } shift_transition[p -> symbol] = p -> action; any_shift_action = TRUE; } } /**********************************************************/ /* If there were any shift actions, a new shift map may */ /* have been created. Hash shift_transition into the */ /* shift hash table. */ /**********************************************************/ if (any_shift_action) { struct shift_header_type sh2; unsigned long hash_address; hash_address = sh.size; for (i = 1; i <= sh.size; i++) /* Compute Hash location */ hash_address += SHIFT_SYMBOL(sh, i); hash_address %= SHIFT_TABLE_SIZE; /**************************************************************/ /* Search HASH_ADDRESS location for shift map that matches */ /* the shift map in shift_transition. If a match is found */ /* we leave the loop prematurely, the search index j is not */ /* NIL, and it identifies the shift map in the hash table */ /* that matched the shift_transition. */ /**************************************************************/ for (j = shift_table[hash_address]; j != NIL; j = new_shift[j].link) { sh2 = shift[new_shift[j].shift_number]; if (sh.size == sh2.size) { for (i = 1; i <= sh.size; i++) if (SHIFT_ACTION(sh2, i) != shift_transition[SHIFT_SYMBOL(sh2, i)]) break; if (i > sh.size) break; /* for (j = shift_table[ ... */ } } /**************************************************************/ /* If j == NIL, the map at hand had not yet being inserted in */ /* the table, it is inserted. Otherwise, we have a match, */ /* and STATE_NO is reset to share the shift map previously */ /* inserted that matches its shift map. */ /**************************************************************/ if (j == NIL) { sh2 = Allocate_shift_map(sh.size); for (i = 1; i <= sh.size; i++) { symbol = SHIFT_SYMBOL(sh, i); SHIFT_SYMBOL(sh2, i) = symbol; SHIFT_ACTION(sh2, i) = shift_transition[symbol]; } num_shift_maps++; shift[num_shift_maps] = sh2; statset[state_no].shift_number = num_shift_maps; top++; new_shift[top].shift_number = num_shift_maps; new_shift[top].link = shift_table[hash_address]; shift_table[hash_address] = top; } else { statset[state_no].shift_number = new_shift[j].shift_number; } } } } /******************************************************************/ /* Free all nodes used in the construction of the conflict_symbols*/ /* map as this map is no longer useful and its size is based on */ /* the base value of num_states. */ /******************************************************************/ for ALL_STATES(state_no) { if (conflict_symbols[state_no] != NULL) { p = conflict_symbols[state_no] -> next; free_nodes(p, conflict_symbols[state_no]); } } /******************************************************************/ /* All updates have now been made, adjust the number of regular */ /* states to include the new SP states. */ /******************************************************************/ num_states = max_sp_state; /******************************************************************/ /* Free all temporary space allocated earlier. */ /******************************************************************/ ffree(sp_rules); ffree(stack); ffree(index_of); ffree(next_rule); ffree(rule_list); ffree(symbol_list); ffree(shift_transition); ffree(rule_count); ffree(new_shift); ffree(look_ahead); for ALL_SYMBOLS(i) { if (sp_action[i] != NULL) { ffree(sp_action[i]); } } ffree(sp_action); ffree(is_conflict_symbol); ffree(sp_table); ffree(new_action); ffree(update_action); return; } jikespg-1.3/src/resolve.c000066400000000000000000003101221167345774400154440ustar00rootroot00000000000000/* $Id: resolve.c,v 1.2 1999/11/04 14:02:23 shields Exp $ */ /* This software is subject to the terms of the IBM Jikes Compiler License Agreement available at the following URL: http://www.ibm.com/research/jikes. Copyright (C) 1983, 1999, International Business Machines Corporation and others. All Rights Reserved. You must accept the terms of that agreement to use this software. */ static char hostfile[] = __FILE__; #include "common.h" #include "reduce.h" #include "header.h" /***********************************************************************/ /* VISITED is a structure used to mark state-symbol pairs that have */ /* been visited in the process of computing follow-sources for a */ /* given action in conflict. */ /* The field MAP is an array indexable by the states 1..NUM_STATES; */ /* each element of which points to a set (list) of symbols. Thus, for */ /* a given state S, and for all symbol X in the list MAP[S], [S,X] */ /* has been visited. For efficiency, the fields LIST and ROOT are used */ /* to store the set (list) of indexed elements of MAP that are not */ /* NULL. */ /* See routines MARK_VISITED, WAS_VISITED, CLEAR_VISITED, */ /* INIT_LALRK_PROCESS, EXIT_PROCESS */ /***********************************************************************/ static struct visited_element { struct node **map; short *list, root; } visited; /***********************************************************************/ /* Given a set of actions that are in conflict on a given symbol, the */ /* structure SOURCES_ELEMENT is used to store a mapping from each */ /* such action into a set of configurations that can be reached */ /* following execution of the action in question up to the point where */ /* the automaton is about to shift the conflict symbol. */ /* The field CONFIGS is an array indexable by actions which are */ /* encoded as follows: */ /* 1. shift-reduce [-NUM_RULES..-1] */ /* 2. reduce [0..NUM_RULES] */ /* 3. shift [NUM_RULES+1..NUM_STATES+1]. */ /* Each element of CONFIGS points to a set (sorted list) of */ /* configurations. For efficiency, the fields LIST and ROOT are used */ /* to store the set (list) of indexed elements of CONFIGS that are not */ /* NULL. */ /* See routines ALLOCATE_SOURCES, FREE_SOURCES, CLEAR_SOURCES, */ /* ADD_CONFIGS, UNION_CONFIG_SETS. */ /* See STATE_TO_RESOLVE_CONFLICTS for an explanation of STACK_SEEN. */ /* */ /* A configuration is a stack of states that represents a certain path */ /* in the automaton. The stack is implemented as a list of */ /* STACK_ELEMENT nodes linked through the field PREVIOUS. */ /* A set/list of configurations is linked through the field NEXT. */ /* When attempting to resolve conflicts we try to make sure that the */ /* set of configurations associated with each action is unique. This */ /* is achieved by throwing these configurations into a set and making */ /* sure that there are no duplicates. The field LINK is used for that */ /* purpose (see routine STACK_WAS_SEEN). The field STATE_NUMBER is */ /* obviously used to store the number of a state in the automaton. The */ /* field SIZE holds index of the node within the stack. Thus, for the */ /* first element of the stack this field represents the number of */ /* elements in the stack; for the last element, this field holds the */ /* value 1. */ /* See routines ALLOCATE_STACK_ELEMENT, FREE_STACK_ELEMENT, */ /* ADD_DANGLING_STACK, FREE_DANGLING_STACK. */ /***********************************************************************/ static struct sources_element { struct stack_element **configs, **stack_seen; short *list, root; } sources; struct stack_element { struct stack_element *previous, *next, *link; short state_number, size; }; static struct stack_element *stack_pool = NULL, *dangling_stacks = NULL; /***********************************************************************/ /* The structure STATE_ELEMENT is used to construct lookahead states. */ /* LA_STATE_ROOT point to a list of lookahead states using the LINK */ /* field. The field NEXT_SHIFT is used to hash the new shift maps */ /* associated with lookahead states. The field IN_STATE identifies the */ /* state that shifted into the lookahead state in question. The field */ /* SYMBOL identifies the symbol on shift the transition was made into */ /* the lookahead state in question. The remaining fields are */ /* self-explanatory. */ /***********************************************************************/ struct state_element { struct state_element *link, *next_shift; struct reduce_header_type reduce; struct shift_header_type shift; short in_state, symbol, state_number, shift_number; }; static struct state_element *la_state_root = NULL; /***********************************************************************/ /* The structures SR_CONFLICT_ELEMENT and RR_CONFLICT_ELEMENT are used */ /* th store conflict information. CONFLICT_ELEMENT_POOL is used to */ /* keep track of a pool conflict element structures (SR or RR) that */ /* are available for allocation. */ /* See routines ALLOCATE_CONFLICT_ELEMENT and FREE_CONFLICT_ELEMENTS. */ /***********************************************************************/ struct sr_conflict_element { struct sr_conflict_element *next; short state_number, item, symbol; }; static struct sr_conflict_element *sr_conflict_root; struct rr_conflict_element { struct rr_conflict_element *next; short symbol, item1, item2; }; static struct rr_conflict_element *rr_conflict_root; static void *conflict_element_pool = NULL; /***********************************************************************/ /* NT_ITEMS and ITEM_LIST are used to construct a mapping from each */ /* nonterminal into the set of items of which the nonterminal in */ /* question is the dot symbol. See CONFLICTS_INITIALIZATION. */ /***********************************************************************/ static short *nt_items = NULL, *item_list = NULL; /***********************************************************************/ /* LALR_VISITED is used to keep track of (state, nonterminal) pairs */ /* that are visited in tracing the path of a lalr conflict.SLR_VISITED */ /* is similarly used to keep track of nonterminal symbols that are */ /* visited in tracing the path of an slr conflict. SYMBOL_SEEN is used */ /* to keep track of nonterminal symbols that are visited in tracing a */ /* path to the start state (root). */ /* */ /* CYCLIC is a boolean vector used to identify states that can enter */ /* a cycle of transitions on nullable nonterminals. */ /* As the computation of CYCLIC requires a modified version of the */ /* digraph algorithm, the variables STACK, INDEX_OF and TOP are used */ /* for that algorithm. */ /* */ /* RMPSELF is a boolean vector that indicates whether or not a given */ /* non-terminal can right-most produce itself. It is only constructed */ /* when LALR_LEVEL > 1. */ /***********************************************************************/ static BOOLEAN *lalr_visited, *slr_visited, *symbol_seen, *cyclic, *rmpself; static short *stack, *index_of, top; static struct state_element **shift_table; /*******************************************************************/ /* ALLOCATE_CONFLICT_ELEMENT: */ /*******************************************************************/ /* This function allocates a conflict_element (sr or rr) structure */ /* & returns a pointer to it. If there are nodes in the free pool, */ /* one of them is returned. Otherwise, a new node is allocated */ /* from the temporary storage pool. */ /*******************************************************************/ static void *allocate_conflict_element(void) { void *p; p = conflict_element_pool; if (p != NULL) conflict_element_pool = ((struct sr_conflict_element *) p) -> next; else { p = (void *) talloc(MAX(sizeof(struct sr_conflict_element), sizeof(struct rr_conflict_element))); if (p == NULL) nospace(__FILE__, __LINE__); } return p; } /**********************************************************************/ /* FREE_CONFLICT_ELEMENTS: */ /**********************************************************************/ /* This routine returns a list of conflict_element (sr/rr)structures */ /* to the free pool. */ /**********************************************************************/ static void free_conflict_elements(void *head, void *tail) { ((struct sr_conflict_element *) tail) -> next = (struct sr_conflict_element *) conflict_element_pool; conflict_element_pool = head; return; } /*******************************************************************/ /* ALLOCATE_STACK_ELEMENT: */ /*******************************************************************/ /* This function allocates a stack_element structure and returns a */ /* pointer to it. If there are nodes in the free pool, one of them */ /* is returned. Otherwise, a new node is allocated from the */ /* temporary storage pool. */ /*******************************************************************/ static struct stack_element *allocate_stack_element(void) { struct stack_element *p; p = stack_pool; if (p != NULL) stack_pool = p -> next; else { p = (struct stack_element *) talloc(sizeof(struct stack_element)); if (p == NULL) nospace(__FILE__, __LINE__); } return p; } /**********************************************************************/ /* FREE_STACK_ELEMENTS: */ /**********************************************************************/ /* This routine returns a list of stack_element structures to the */ /* free pool. */ /**********************************************************************/ static void free_stack_elements(struct stack_element *head, struct stack_element *tail) { tail -> next = stack_pool; stack_pool = head; return; } /***************************************************************************/ /* ADD_DANGLING_STACK_ELEMENT: */ /***************************************************************************/ /* When an allocated stack_element structure is not directly associated */ /* with an action, it is added to a circular list of dangling stack_element*/ /* nodes so that its space can be reclaimed. */ /***************************************************************************/ static void add_dangling_stack_element(struct stack_element *s) { if (dangling_stacks == NULL) s -> next = s; else { s -> next = dangling_stacks -> next; dangling_stacks -> next = s; } dangling_stacks = s; return; } /***************************************************************************/ /* FREE_DANGLING_STACK_ELEMENTS: */ /***************************************************************************/ /* This function is invoked to free up all dangling stack_element nodes */ /* and reset the dangling stack list. */ /* Recall that the dangling stack list is circular. */ /***************************************************************************/ static void free_dangling_stack_elements(void) { struct stack_element *tail; if (dangling_stacks != NULL) { tail = dangling_stacks; free_stack_elements(dangling_stacks -> next, tail); dangling_stacks = NULL; } return; } /***************************************************************************/ /* ALLOCATE_SOURCES: */ /***************************************************************************/ /* This function allocates and initializes a SOURCE_ELEMENT map. */ /* See definition of SOURCE_ELEMENT above. */ /***************************************************************************/ static struct sources_element allocate_sources(void) { struct sources_element sources; sources.configs = (struct stack_element **) calloc(num_rules + num_rules + num_states + 1, sizeof(struct stack_element *)); if (sources.configs == NULL) nospace(__FILE__, __LINE__); sources.configs += num_rules; sources.stack_seen = (struct stack_element **) calloc(STATE_TABLE_SIZE, sizeof(struct stack_element *)); if (sources.stack_seen == NULL) nospace(__FILE__, __LINE__); sources.list = Allocate_short_array(num_rules + num_rules + num_states + 1); sources.list += num_rules; sources.root = NIL; return sources; } /***************************************************************************/ /* CLEAR_SOURCES: */ /***************************************************************************/ /* This function takes as argument a SOURCES_ELEMENT structure which it */ /* resets to the empty map. */ /* See definition of SOURCE_ELEMENT above. */ /***************************************************************************/ static struct sources_element clear_sources(struct sources_element sources) { struct stack_element *p, *tail; int act, i; for (act = sources.root; act != NIL; act = sources.list[act]) { for (p = sources.configs[act]; p != NULL; tail = p, p = p -> next) ; free_stack_elements(sources.configs[act], tail); sources.configs[act] = NULL; } sources.root = NIL; return sources; } /***************************************************************************/ /* FREE_SOURCES: */ /***************************************************************************/ /* This function takes as argument a SOURCES_ELEMENT structure. First, it */ /* clears it to reclaim all space that was used by STACK_ELEMENTs and then */ /* it frees the array space used as a base to construct the map. */ /***************************************************************************/ static void free_sources(struct sources_element sources) { sources = clear_sources(sources); sources.configs -= num_rules; ffree(sources.configs); ffree(sources.stack_seen); sources.list -= num_rules; ffree(sources.list); return; } /***************************************************************************/ /* UNION_CONFIG_SETS: */ /***************************************************************************/ /* This function takes as argument two pointers to sorted lists of stacks. */ /* It merges the lists in the proper order and returns the resulting list. */ /***************************************************************************/ static struct stack_element *union_config_sets(struct stack_element *root1, struct stack_element *root2) { struct stack_element *p1, *p2, *root, *tail; root = NULL; /*******************************************************************/ /* This loop iterates over both lists until one (or both) has been */ /* completely processed. Each time around the loop, a stack is */ /* removed from one of the lists and possibly added to the new */ /* list. The new list is initially kept as a circular list to */ /* preserve the sorted ordering in which elements are added to it. */ /*******************************************************************/ while (root1 != NULL && root2 != NULL) { /***************************************************************/ /* Compare the two stacks in front of the lists for equality. */ /* We exit this loop when we encounter the end of one (or both)*/ /* of the stacks or two elements in them that are not the same.*/ /***************************************************************/ for (p1 = root1, p2 = root2; p1 != NULL && p2 != NULL; p1 = p1 -> previous, p2 = p2 -> previous) { if (p1 -> state_number != p2 -> state_number) break; } /***************************************************************/ /* We now have 3 cases to consider: */ /* 1. The two stacks are equal? Discard one! */ /* 2. List 1 stack is prefix of list 2 stack (p1 == NULL)? */ /* or list 1 stack is less than list 2 stack? */ /* Remove list 1 stack and add it to new list. */ /* 3. List 2 stack is either a prefix of list 1 stack, or */ /* it is smaller! */ /* Remove list 2 stack and add it to new list. */ /***************************************************************/ if (p1 == p2) /* are both p1 and p2 NULL? */ { p2 = root2; root2 = root2 -> next; add_dangling_stack_element(p2); } else if ((p1 == NULL) || ((p2 != NULL) && (p1 -> state_number < p2 -> state_number))) { p1 = root1; root1 = root1 -> next; if (root == NULL) p1 -> next = p1; else { p1 -> next = root -> next; root -> next = p1; } root = p1; } else { p2 = root2; root2 = root2 -> next; if (root == NULL) p2 -> next = p2; else { p2 -> next = root -> next; root -> next = p2; } root = p2; } } /*******************************************************************/ /* At this stage, at least one (or both) list has been expended */ /* (or was empty to start with). */ /* If the new list is not empty, turn it into a linear list and */ /* append the unexpended list to it, if any. */ /* Otherwise, set the new list to the nonempty list if any! */ /*******************************************************************/ if (root != NULL) { tail = root; root = root -> next; tail -> next = (root1 == NULL ? root2 : root1); } else root = (root1 == NULL ? root2 : root1); return root; } /***************************************************************************/ /* ADD_CONFIGS: */ /***************************************************************************/ /* This function takes as argument a SOURCES_ELEMENT map, an ACTION and a */ /* set (sorted list) of configurations. It adds the set of configurations */ /* to the previous set of configurations associated with the ACTION in the */ /* SOURCES_ELEMENT map. */ /***************************************************************************/ static struct sources_element add_configs(struct sources_element sources, int action, struct stack_element *config_root) { if (config_root == NULL) /* The new set is empty? Do nothing */ return sources; if (sources.configs[action] == NULL) /* The previous was empty? */ { sources.list[action] = sources.root; sources.root = action; } sources.configs[action] = union_config_sets(sources.configs[action], config_root); return sources; } /***************************************************************************/ /* CLEAR_VISITED: */ /***************************************************************************/ /* This function clears out all external space used by the VISITED set and */ /* resets VISITED to the empty set. */ /***************************************************************************/ static void clear_visited(void) { struct node *p, *tail; int state_no; for (state_no = visited.root; state_no != NIL; state_no = visited.list[state_no]) { for (p = visited.map[state_no]; p != NULL; tail = p, p = p -> next) ; free_nodes(visited.map[state_no], tail); visited.map[state_no] = NULL; } visited.root = NIL; return; } /***************************************************************************/ /* WAS_VISITED: */ /***************************************************************************/ /* This boolean function checks whether or not a given pair [state, symbol]*/ /* was already inserted in the VISITED set. */ /***************************************************************************/ static BOOLEAN was_visited(int state_no, int symbol) { struct node *p; for (p = visited.map[state_no]; p != NULL; p = p -> next) { if (p -> value == symbol) break; } return (p != NULL); } /***************************************************************************/ /* MARK_VISITED: */ /***************************************************************************/ /* This function inserts a given pair [state, symbol] into the VISITED set.*/ /***************************************************************************/ static void mark_visited(int state_no, int symbol) { struct node *p; if (visited.map[state_no] == NULL) /* 1st time we see state_no? */ { visited.list[state_no] = visited.root; visited.root = state_no; } p = Allocate_node(); p -> value = symbol; p -> next = visited.map[state_no]; visited.map[state_no] = p; return; } /***********************************************************************/ /* COMPUTE_CYCLIC: */ /***********************************************************************/ /* This procedure is a modified instantiation of the digraph algorithm */ /* to compute the CYCLIC set of states. */ /***********************************************************************/ static void compute_cyclic(short state_no) { int indx; struct goto_header_type go_to; int symbol, act, i; stack[++top] = state_no; indx = top; cyclic[state_no] = FALSE; index_of[state_no] = indx; go_to = statset[state_no].go_to; for (i = 1; i <= go_to.size; i++) { symbol = GOTO_SYMBOL(go_to, i); act = GOTO_ACTION(go_to, i); if (act > 0 && null_nt[symbol]) { /* We have a transition on a nullable nonterminal? */ if (index_of[act] == OMEGA) compute_cyclic(act); else if (index_of[act] != INFINITY) cyclic[state_no] = TRUE; cyclic[state_no] = cyclic[state_no] || cyclic[act]; index_of[state_no] = MIN(index_of[state_no], index_of[act]); } } if (index_of[state_no] == indx) { do { act = stack[top--]; index_of[act] = INFINITY; } while(act != state_no); } return; } /***********************************************************************/ /* TRACE_ROOT: */ /***********************************************************************/ /* In tracing an error, we will be moving backward in the state */ /* automaton looking for items with the conflict symbol as look-ahead. */ /* In the case of SLR, we may have to analoguously look at an */ /* arbitrary set of items involved. In moving around these graphs, it */ /* is possible to encounter a cycle, in which case, we simply want to */ /* back out of the cycle and try another path. We therefore need to */ /* keep track of which nodes have already been visited. For LALR */ /* conflicts, we use the LA_PTR field of the GOTO_ELEMENTs as an index */ /* to a BOOLEAN array LALR_VISITED. For SLR conflicts, a boolean */ /* array, SLR_VISITED, indexable by non-terminals, is used. For */ /* trace-backs to the root item, the boolean array SYMBOL_SEEN, also */ /* also indexable by non-terminals, is used. */ /***********************************************************************/ static BOOLEAN trace_root(int lhs_symbol) { int item; if (lhs_symbol == accept_image) return(TRUE); if (symbol_seen[lhs_symbol]) return(FALSE); symbol_seen[lhs_symbol] = TRUE; for (item = nt_items[lhs_symbol]; item != NIL; item = item_list[item]) { if (trace_root(rules[item_table[item].rule_number].lhs)) { print_item(item); return(TRUE); } } return(FALSE); } /***********************************************************************/ /* PRINT_ROOT_PATH: */ /***********************************************************************/ /* The procedure below is invoked to retrace a path from the initial */ /* item to a given item (ITEM_NO) passed to it as argument. */ /***********************************************************************/ static void print_root_path(int item_no) { symbol_seen = Allocate_boolean_array(num_non_terminals); symbol_seen -= (num_terminals + 1); if (trace_root(rules[item_table[item_no].rule_number].lhs)) { fprintf(syslis, "\n"); /* Leave one blank line after root trace. */ ENDPAGE_CHECK; } symbol_seen += (num_terminals + 1); ffree(symbol_seen); return; } /***********************************************************************/ /* LALR_PATH_RETRACED: */ /***********************************************************************/ /* This procedure takes as argument, a state number, STATE_NO, an */ /* index into the goto map of state_no, GOTO_INDX, which identifies a */ /* starting point for a search for the CONFLICT_SYMBOL. It attempts to */ /* find a path in the automaton (from the starting point) that leads */ /* to a state where the conflict symbol can be read. If a path is */ /* found, all items along the path are printed and SUCCESS is returned.*/ /* Otherwise, FAILURE is returned. */ /***********************************************************************/ static BOOLEAN lalr_path_retraced(int state_no, int goto_indx, int conflict_symbol) { int symbol, item, state, i; struct goto_header_type go_to; struct node *p, *q, *tail, *w; BOOLEAN found; go_to = statset[state_no].go_to; lalr_visited[GOTO_LAPTR(go_to, goto_indx)] = TRUE; found = FALSE; state = GOTO_ACTION(go_to, goto_indx); for (p = (state > 0 ? statset[state].kernel_items : adequate_item[-state]); (p != NULL) && (! found); p = p -> next) { item = p -> value - 1; if IS_IN_SET(first, item_table[item].suffix_index, conflict_symbol) { /* Conflict_symbol can be read in state? */ if (trace_opt == TRACE_FULL) print_root_path(item); found = TRUE; } else if IS_IN_SET(first, item_table[item].suffix_index, empty) { symbol = rules[item_table[item].rule_number].lhs; w = lpgaccess(state_no, item); for (q = w; q != NULL; tail = q, q = q -> next) { go_to = statset[q -> value].go_to; for (i = 1; GOTO_SYMBOL(go_to, i) != symbol; i++) ; if (! lalr_visited[GOTO_LAPTR(go_to, i)]) { if (lalr_path_retraced(q -> value, i, conflict_symbol)) { found = TRUE; break; } } } for (; q != NULL; tail = q, q = q -> next) ; free_nodes(w, tail); } } if (found) print_item(item); return(found); } /***********************************************************************/ /* PRINT_RELEVANT_LALR_ITEMS: */ /***********************************************************************/ /* In this procedure, we attempt to retrace an LALR conflict path */ /* (there may be more than one) of CONFLICT_SYMBOL in the state */ /* automaton that led to ITEM_NO in state STATE_NO. */ /***********************************************************************/ static void print_relevant_lalr_items(int state_no, int item_no, int conflict_symbol) { int lhs_symbol, i; struct node *p, *tail, *v; lhs_symbol = rules[item_table[item_no].rule_number].lhs; if (lhs_symbol == accept_image) return; lalr_visited = Allocate_boolean_array(la_top + 1); v = lpgaccess(state_no, item_no); for (p = v; p != NULL; tail = p, p = p -> next) { struct goto_header_type go_to; go_to = statset[p -> value].go_to; for (i = 1; GOTO_SYMBOL(go_to, i) != lhs_symbol; i++) ; if (lalr_path_retraced(p -> value, i, conflict_symbol)) break; } for (; p != NULL; tail = p, p = p -> next) ; free_nodes(v, tail); ffree(lalr_visited); return; } /***********************************************************************/ /* SLR_TRACE: */ /***********************************************************************/ /* The procedure below is invoked to retrace a path that may have */ /* introduced the CONFLICT_SYMBOL in the FOLLOW set of the nonterminal */ /* that produces ITEM_NO. Note that such a path must exist. */ /***********************************************************************/ static BOOLEAN slr_trace(int lhs_symbol, int conflict_symbol) { int item; if (slr_visited[lhs_symbol]) return(FALSE); slr_visited[lhs_symbol] = TRUE; for (item = nt_items[lhs_symbol]; item != NIL; item = item_list[item]) { if IS_IN_SET(first, item_table[item].suffix_index, conflict_symbol) { if (trace_opt == TRACE_FULL) print_root_path(item); break; } if IS_IN_SET(first, item_table[item].suffix_index, empty) { if (slr_trace(rules[item_table[item].rule_number].lhs, conflict_symbol)) break; } } if (item != NIL) { print_item(item); return(TRUE); } else return(FALSE); } /***********************************************************************/ /* PRINT_RELEVANT_SLR_ITEMS: */ /***********************************************************************/ /* This procedure is invoked to print an SLR path of items that leads */ /* to the conflict symbol. */ /***********************************************************************/ static void print_relevant_slr_items(int item_no, int conflict_symbol) { slr_visited = Allocate_boolean_array(num_non_terminals); slr_visited -= (num_terminals + 1); if (slr_trace(rules[item_table[item_no].rule_number].lhs, conflict_symbol)) ; slr_visited += (num_terminals + 1); ffree(slr_visited); return; } /***********************************************************************/ /* CONFLICTS_INITIALIZATION: */ /***********************************************************************/ /* This routine is invoked when a grammar contains conflicts, and the */ /* first conflict is detected. */ /***********************************************************************/ static void conflicts_initialization(void) { int i; /*******************************************************************/ /* NT_ITEMS and ITEM_LIST are used in reporting SLR conflicts, and */ /* in recreating paths from the Start item. See the routines */ /* PRINT_RELEVANT_SLR_ITEMS and PRINT_ROOT_PATH. */ /*******************************************************************/ nt_items = Allocate_short_array(num_non_terminals); nt_items -= (num_terminals + 1); item_list = Allocate_short_array(num_items + 1); i = (PRINT_LINE_SIZE - 11) / 2 - 1; PR_HEADING; fill_in(msg_line, i, '-'); fprintf(syslis, "\n%s CONFLICTS %s\n", msg_line, msg_line); output_line_no += 2; /***********************************************************************/ /* SLR conflicts may be caused by a symbol in the FOLLOW set of a */ /* left hand side, which is not actually in the LALR look-ahead set in */ /* that context. Therefore, there may not exist a path in the state */ /* automaton from the state where the conflict was detected to another */ /* state where it was introduced. In such a case, we try to retrace a */ /* path that contributed the conflict-symbol to the FOLLOW set via a */ /* sequence of productions. */ /* */ /* To assist in this task, we build below a map from each non-terminal */ /* A to the set of items of which A is the dot SYMBOL. I.e., all items */ /* of the form [x .A y] where x and y are arbitrary strings, and A is */ /* a non-terminal. This map is also used in retracing a path from the */ /* Start item to any other item. */ /***********************************************************************/ for ALL_NON_TERMINALS(i) nt_items[i] = NIL; for ALL_ITEMS(i) { if (item_table[i].symbol IS_A_NON_TERMINAL) { item_list[i] = nt_items[item_table[i].symbol]; nt_items[item_table[i].symbol] = i; } } return; } /***********************************************************************/ /* PROCESS_CONFLICTS: */ /***********************************************************************/ /* If conflicts are detected, tehy are placed in two lists headed by */ /* SR_CONFLICT_ROOT and RR_CONFLICT_ROOT. We scan these lists, and */ /* report the conflicts. */ /***********************************************************************/ static void process_conflicts(int state_no) { int symbol, rule_no, n; char temp[SYMBOL_SIZE + 1]; if (nt_items == NULL) conflicts_initialization(); print_state(state_no); /* Print state containing conflicts */ /*******************************************************************/ /* Process shift-reduce conflicts. */ /*******************************************************************/ if (sr_conflict_root != NULL) { struct sr_conflict_element *p, *tail; for (p = sr_conflict_root; p != NULL; tail = p, p = p -> next) { symbol = p -> symbol; rule_no = item_table[p -> item].rule_number; restore_symbol(temp, RETRIEVE_STRING(symbol)); printf("*** Shift/reduce conflict on \"%s\" with rule %d\n", temp, rule_no); fprintf(syslis, "\n*** Shift/reduce conflict on \"%s\" with rule %d\n", temp, rule_no); if (trace_opt != NOTRACE) { if (! slr_bit) print_relevant_lalr_items(state_no, p -> item, symbol); else print_relevant_slr_items(p -> item, symbol); print_item(p -> item); } } free_conflict_elements(sr_conflict_root, tail); } /*******************************************************************/ /* Process reduce-reduce conflicts. */ /*******************************************************************/ if (rr_conflict_root != NULL) { struct rr_conflict_element *p, *tail; for (p = rr_conflict_root; p != NULL; tail = p, p = p -> next) { symbol = p -> symbol; n = item_table[p -> item1].rule_number; rule_no = item_table[p -> item2].rule_number; restore_symbol(temp, RETRIEVE_STRING(symbol)); printf("*** Reduce/reduce conflict " "on \"%s\" between rule %d and %d\n", temp, n, rule_no); fprintf(syslis, "\n*** Reduce/reduce conflict " "on \"%s\" between rule %d and %d\n", temp, n, rule_no); output_line_no +=2; if (trace_opt != NOTRACE) { if (! slr_bit) print_relevant_lalr_items(state_no, p -> item1, symbol); else print_relevant_slr_items(p -> item1, symbol); print_item(p -> item1); fill_in(msg_line, PRINT_LINE_SIZE - 3, '-'); fprintf(syslis,"\n%s",msg_line); ENDPAGE_CHECK; if (! slr_bit) print_relevant_lalr_items(state_no, p -> item2, symbol); else print_relevant_slr_items(p -> item2, symbol); print_item(p -> item2); } } free_conflict_elements(rr_conflict_root, tail); } return; } /***********************************************************************/ /* ADD_CONFLICT_SYMBOL: */ /***********************************************************************/ /* Add SYMBOL to the set of symbols CONFLICT_SYMBOLS[STATE_NO]. */ /***********************************************************************/ static void add_conflict_symbol(int state_no, int symbol) { struct node *p; p = Allocate_node(); p -> value = symbol; if (conflict_symbols[state_no] == NULL) p -> next = p; else { p -> next = conflict_symbols[state_no] -> next; conflict_symbols[state_no] -> next = p; } conflict_symbols[state_no] = p; return; } /***********************************************************************/ /* FOLLOW_SOURCES: */ /***********************************************************************/ /* This function takes as argument a configuration STACK, a SYMBOL on */ /* which a transition can be made in the configuration and a terminal */ /* lookahead symbol, LA_SYMBOL. It executes the transition on SYMBOL */ /* and simulates all paths taken in the automaton after that transition*/ /* until new state(s) are reached where a transition is possible on */ /* the lookahead symbol. It then returns the new set of configurations */ /* found on which a transition on LA_SYMBOL is possible. */ /***********************************************************************/ static struct stack_element *follow_sources(struct stack_element *stack, int symbol, int la_symbol) { struct shift_header_type sh; struct goto_header_type go_to; struct stack_element *configs, *q; struct node *item_ptr; int item_no, state_no, rule_no, lhs_symbol, act, i; configs = NULL; /* Initialize the output set of configurations */ /*******************************************************************/ /* If the starting configuration consists of a single state and */ /* the initial [state, symbol] pair has already been visited, */ /* return the null set. Otherwise, mark the pair visited and ... */ /*******************************************************************/ state_no = stack -> state_number; if (stack -> size == 1) { if (was_visited(state_no, symbol) || (state_no == 1 && symbol == accept_image)) return configs; mark_visited(state_no, symbol); } /*******************************************************************/ /* Find the transition defined on the symbol... */ /* If the SYMBOL is a nonterminal and we can determine that the */ /* lookahead symbol (LA_SYMBOL) cannot possibly follow the */ /* nonterminal in question in this context, we simply abandon the */ /* search and return the NULL set. */ /*******************************************************************/ if (symbol IS_A_NON_TERMINAL) { go_to = statset[state_no].go_to; for (i = 1; GOTO_SYMBOL(go_to, i) != symbol; i++) ; if (la_index[GOTO_LAPTR(go_to, i)] == OMEGA) { int stack_top = 0; la_traverse(state_no, i, &stack_top); } if (! IS_IN_SET(la_set, GOTO_LAPTR(go_to, i), la_symbol)) return configs; act = GOTO_ACTION(go_to, i); } else { sh = shift[statset[state_no].shift_number]; for (i = 1; SHIFT_SYMBOL(sh, i) != symbol; i++) ; act = SHIFT_ACTION(sh, i); } /*******************************************************************/ /* If the ACTion on the symbol is a shift or a goto, ... */ /*******************************************************************/ if (act > 0) { /***************************************************************/ /* We check to see if the new state contains an action on the */ /* lookahead symbol. If that's the case then we create a new */ /* configuration by appending ACT to the starting configuration*/ /* and add this newly formed configuration to the set(list) of */ /* configurations... */ /***************************************************************/ sh = shift[statset[act].shift_number]; for (i = 1; i <= sh.size; i++) { if (SHIFT_SYMBOL(sh, i) == la_symbol) break; } if (i <= sh.size) /* there is a transition on la_symbol in act */ { q = allocate_stack_element(); q -> state_number = act; q -> size = stack -> size + 1; q -> previous = stack; q -> next = NULL; configs = q; } /***************************************************************/ /* If the new state cannot get into a cycle of null */ /* transitions, we check to see if it contains any transition */ /* on a nullable nonterminal. For each such transition, we */ /* append the new state to the stack and recursively invoke */ /* FOLLOW_SOURCES to check if a transition on LA_SYMBOL cannot */ /* follow such a null transition. */ /***************************************************************/ if (! cyclic[act]) { go_to = statset[act].go_to; for (i = 1; i <= go_to.size; i++) { symbol = GOTO_SYMBOL(go_to, i); if (null_nt[symbol]) { struct stack_element *new_configs; q = allocate_stack_element(); q -> state_number = act; q -> size = stack -> size + 1; q -> previous = stack; q -> next = NULL; new_configs = follow_sources(q, symbol, la_symbol); if (new_configs == NULL) free_stack_elements(q, q); else { add_dangling_stack_element(q); configs = union_config_sets(configs, new_configs); } } } } } /*******************************************************************/ /* We now iterate over the kernel set of items associated with the */ /* ACTion defined on SYMBOL... */ /*******************************************************************/ for (item_ptr = (act > 0 ? statset[act].kernel_items : adequate_item[-act]); item_ptr != NULL; item_ptr = item_ptr -> next) { item_no = item_ptr -> value; /***************************************************************/ /* For each item that is a final item whose left-hand side */ /* is neither the starting symbol nor a symbol that can */ /* right-most produce itself... */ /***************************************************************/ if (item_table[item_no].symbol == empty) { rule_no = item_table[item_no].rule_number; lhs_symbol = rules[rule_no].lhs; if (lhs_symbol != accept_image && ! rmpself[lhs_symbol]) { /*******************************************************/ /* If the length of the prefix of the item preceeding */ /* the dot is shorter that the length of the stack, we */ /* retrace the item's path within the stack and */ /* invoke FOLLOW_SOURCES with the prefix of the stack */ /* where the item was introduced through closure, the */ /* left-hand side of the item and the lookahead symbol.*/ /*******************************************************/ if (item_table[item_no].dot < stack -> size) { q = stack; for (i = 1; i < item_table[item_no].dot; i++) q = q -> previous; q = follow_sources(q, lhs_symbol, la_symbol); configs = union_config_sets(configs, q); } else { struct node *v, *p, *tail; /***************************************************/ /* Compute the item in the root state of the stack,*/ /* and find the root state... */ /***************************************************/ item_no -= stack -> size; for (q = stack; q -> size != 1; q = q -> previous) ; /***************************************************/ /* We are now back in the main automaton, find all */ /* sources where the item was introduced through */ /* closure start a new configuration and invoke */ /* FOLLOW_SOURCES with the appropriate arguments to*/ /* calculate the set of configurations associated */ /* with these sources. */ /***************************************************/ v = lpgaccess(q -> state_number, item_no); for (p = v; p != NULL; tail = p, p = p -> next) { struct stack_element *new_configs; q = allocate_stack_element(); q -> state_number = p -> value; q -> size = 1; q -> previous = NULL; q -> next = NULL; new_configs = follow_sources(q, lhs_symbol, la_symbol); if (new_configs == NULL) free_stack_elements(q, q); else { add_dangling_stack_element(q); configs = union_config_sets(configs, new_configs); } } free_nodes(v, tail); } } } } return configs; } /***********************************************************************/ /* NEXT_LA: */ /***********************************************************************/ /* This function has a similar structure as FOLLOW_SOURCES. But, */ /* instead of computing configurations that can be reached, it */ /* computes lookahead symbols that can be reached. It takes as */ /* argument a configuration STACK, a SYMBOL on which a transition can */ /* be made in the configuration and a set variable, LOOK_AHEAD, where */ /* the result is to be stored. When NEXT_LA is invoked from the */ /* outside, LOOK_AHEAD is assumed to be initialized to the empty set. */ /* NEXT_LA first executes the transition on SYMBOL and thereafter, all */ /* terminal symbols that can be read are added to LOOKAHEAD. */ /***********************************************************************/ static void next_la(struct stack_element *stack, int symbol, SET_PTR look_ahead) { struct shift_header_type sh; struct goto_header_type go_to; struct stack_element *q; struct node *item_ptr; int item_no, state_no, rule_no, lhs_symbol, act, i; /*******************************************************************/ /* The only symbol that can follow the end-of-file symbol is the */ /* end-of-file symbol. */ /*******************************************************************/ if (symbol == eoft_image) { SET_BIT_IN(look_ahead, 0, eoft_image); return; } state_no = stack -> state_number; /*******************************************************************/ /* Find the transition defined on the symbol... */ /*******************************************************************/ if (symbol IS_A_NON_TERMINAL) { go_to = statset[state_no].go_to; for (i = 1; GOTO_SYMBOL(go_to, i) != symbol; i++) ; act = GOTO_ACTION(go_to, i); } else { sh = shift[statset[state_no].shift_number]; for (i = 1; SHIFT_SYMBOL(sh, i) != symbol; i++) ; act = SHIFT_ACTION(sh, i); } /*******************************************************************/ /* If the ACTion on the symbol is a shift or a goto, then all */ /* terminal symbols that can be read in ACT are added to */ /* LOOK_AHEAD. */ /*******************************************************************/ if (act > 0) { SET_UNION(look_ahead, 0, read_set, act); } /*******************************************************************/ /* We now iterate over the kernel set of items associated with the */ /* ACTion defined on SYMBOL... */ /* Recall that the READ_SET of ACT is but the union of the FIRST */ /* map defined on the suffixes of the items in the kernel of ACT. */ /*******************************************************************/ for (item_ptr = (act > 0 ? statset[act].kernel_items : adequate_item[-act]); item_ptr != NULL; item_ptr = item_ptr -> next) { item_no = item_ptr -> value; /***************************************************************/ /* For each item that is a final item whose left-hand side */ /* is neither the starting symbol nor a symbol that can */ /* right-most produce itself... */ /***************************************************************/ if (IS_IN_SET(first, item_table[item_no - 1].suffix_index, empty)) { rule_no = item_table[item_no].rule_number; lhs_symbol = rules[rule_no].lhs; if (lhs_symbol != accept_image && ! rmpself[lhs_symbol]) { /*******************************************************/ /* If the length of the prefix of the item preceeding */ /* the dot is shorter that the length of the stack, we */ /* retrace the item's path within the stack and */ /* invoke NEXT_LA with the prefix of the stack */ /* where the item was introduced through closure, the */ /* left-hand side of the item and LOOK_AHEAD. */ /*******************************************************/ if (item_table[item_no].dot < stack -> size) { q = stack; for (i = 1; i < item_table[item_no].dot; i++) q = q -> previous; next_la(q, lhs_symbol, look_ahead); } else { struct node *v, *p, *tail; /***************************************************/ /* Compute the item in the root state of the stack,*/ /* and find the root state... */ /***************************************************/ item_no -= stack -> size; for (q = stack; q -> size != 1; q = q -> previous) ; /***************************************************/ /* We are now back in the main automaton, find all */ /* sources where the item was introduced through */ /* closure and add all terminal symbols in the */ /* follow set of the left-hand side symbol in each */ /* source to LOOK_AHEAD. */ /***************************************************/ v = lpgaccess(q -> state_number, item_no); for (p = v; p != NULL; tail = p, p = p -> next) { go_to = statset[p -> value].go_to; for (i = 1; GOTO_SYMBOL(go_to, i) != lhs_symbol; i++) ; /***********************************************/ /* If look-ahead after left hand side is not */ /* yet computed,call LA_TRAVERSE to compute it.*/ /***********************************************/ if (la_index[GOTO_LAPTR(go_to, i)] == OMEGA) { int stack_top = 0; la_traverse(p -> value, i, &stack_top); } SET_UNION(look_ahead, 0, la_set, GOTO_LAPTR(go_to, i)); } free_nodes(v, tail); } } } } return; } /***********************************************************************/ /* STACK_WAS_SEEN: */ /***********************************************************************/ /* This function takes as argument an array, STACK_SEEN, with */ /* STATE_TABLE_SIZE elements (indexable in the range */ /* 0..STATE_TABLE_SIZE-1) which is the base of a hash table and a */ /* STACK. It searches the hash table to see if it already contained */ /* the stack in question. If yes, it returns TRUE. Otherwise, it */ /* inserts the stack into the table and returns FALSE. */ /***********************************************************************/ static BOOLEAN stack_was_seen(struct stack_element **stack_seen, struct stack_element *stack) { unsigned long hash_address; struct stack_element *p, *q, *r; hash_address = stack -> size; /* Initialize hash address */ for (p = stack; p != NULL; p = p -> previous) hash_address += p -> state_number; hash_address %= STATE_TABLE_SIZE; for (p = stack_seen[hash_address]; p != NULL; p = p -> link) { if (stack -> size == p -> size) { for (q = stack, r = p; q != NULL; q = q -> previous, r = r -> previous) { if (q -> state_number != r -> state_number) break; } if (q == NULL) return TRUE; } } stack -> link = stack_seen[hash_address]; stack_seen[hash_address] = stack; return FALSE; } /***********************************************************************/ /* STATE_TO_RESOLVE_CONFLICTS: */ /***********************************************************************/ /* STATE_TO_RESOLVE_CONFLICTS is a function that attempts to resolve */ /* conflicts by doing more look-ahead. If the conflict resolution */ /* is successful, then a new state is created and returned; otherwise, */ /* the NULL pointer is returned. */ /***********************************************************************/ static struct state_element *state_to_resolve_conflicts (struct sources_element sources, int la_symbol, int level) { struct sources_element new_sources; struct node **action, *p, *tail; short *symbol_list, *action_list, *rule_count, symbol_root, shift_root, reduce_root; SET_PTR look_ahead; struct stack_element *stack; struct state_element **la_shift_state, *state; int num_shift_actions, num_reduce_actions, default_rule, count, i, symbol, act; new_sources = allocate_sources(); action = (struct node **) calloc(num_terminals + 1, sizeof(struct node *)); if (action == NULL) nospace(__FILE__, __LINE__); symbol_list = Allocate_short_array(num_terminals + 1); action_list = Allocate_short_array(num_terminals + 1); rule_count = Allocate_short_array(num_rules + 1); look_ahead = (SET_PTR) calloc(1, term_set_size * sizeof(BOOLEAN_CELL)); if (look_ahead == NULL) nospace(__FILE__, __LINE__); la_shift_state = (struct state_element **) calloc(num_terminals + 1, sizeof(struct state_element *)); if (la_shift_state == NULL) nospace(__FILE__, __LINE__); /*******************************************************************/ /* Initialize new lookahead state. Initialize counters. Check and */ /* adjust HIGHEST_LEVEL reached so far, if necessary. */ /*******************************************************************/ state = NULL; num_shift_actions = 0; num_reduce_actions = 0; shift_root = NIL; reduce_root = NIL; if (level > highest_level) highest_level = level; /*******************************************************************/ /* One of the parameters received is a SOURCES map whose domain is */ /* a set of actions and each of these actions is mapped into a set */ /* of configurations that can be reached after that action is */ /* executed (in the state where the conflicts were detected). */ /* In this loop, we compute an ACTION map which maps each each */ /* terminal symbol into 0 or more actions in the domain of SOURCES.*/ /* */ /* NOTE in a sources map, if a configuration is associated with */ /* more than one action then the grammar is not LALR(k) for any k. */ /* We check for that condition below. However, this check is there */ /* for purely cosmetic reason. It is not necessary for the */ /* algorithm to work correctly and its removal will speed up this */ /* loop somewhat (for conflict-less input). */ /* The first loop below initializes the hash table used for */ /* lookups ... */ /*******************************************************************/ for (i = 0; i < STATE_TABLE_SIZE; i++) sources.stack_seen[i] = NULL; symbol_root = NIL; for (act = sources.root; act != NIL; act = sources.list[act]) { /***************************************************************/ /* For each action we iterate over its associated set of */ /* configurations and invoke NEXT_LA to compute the lookahead */ /* set for that configuration. These lookahead sets are in */ /* turn unioned together to form a lookahead set for the */ /* action in question. */ /***************************************************************/ INIT_SET(look_ahead); for (stack = sources.configs[act]; stack != NULL; stack = stack -> next) { if (stack_was_seen(sources.stack_seen, stack)) {/* This is the superfluous code mentioned above! */ highest_level = INFINITY; goto clean_up_and_return; } next_la(stack, la_symbol, look_ahead); } RESET_BIT(look_ahead, empty); /* EMPTY never in LA set */ /***************************************************************/ /* For each lookahead symbol computed for this action, add an */ /* action to the ACTION map and keep track of the symbols on */ /* which any action is defined. */ /* If new conflicts are detected and we are already at the */ /* lookahead level requested, we terminate the computation... */ /***************************************************************/ count = 0; for ALL_TERMINALS(symbol) { if (IS_ELEMENT(look_ahead, symbol)) { count++; if (action[symbol] == NULL) { symbol_list[symbol] = symbol_root; symbol_root = symbol; } else if (level == lalr_level) goto clean_up_and_return; p = Allocate_node(); p -> value = act; p -> next = action[symbol]; action[symbol] = p; } } /***************************************************************/ /* If the action in question is a reduction then we keep track */ /* of how many times it was used. */ /***************************************************************/ if (act >= 0 && act <= num_rules) rule_count[act] = count; } /*******************************************************************/ /* We now iterate over the symbols on which actions are defined. */ /* If we detect conflicts on any symbol, we compute new sources */ /* and try to recover by computing more lookahead. Otherwise, we */ /* update the counts and create two lists: a list of symbols on */ /* which shift actions are defined and a list of symbols on which */ /* reduce actions are defined. */ /*******************************************************************/ for (symbol = symbol_root; symbol != NIL; symbol = symbol_list[symbol]) { /***************************************************************/ /* We have four cases to consider: */ /* 1. There are conflicts on SYMBOL */ /* 2. The action on SYMBOL is a shift-reduce */ /* 3. The action on SYMBOL is a shift */ /* 4. The action on SYMBOL is a reduce */ /***************************************************************/ if (action[symbol] -> next != NULL) { new_sources = clear_sources(new_sources); for (p = action[symbol]; p != NULL; tail = p, p = p -> next) { act = p -> value; if (act >= 0 && act <= num_rules) rule_count[act]--; clear_visited(); for (stack = sources.configs[act]; stack != NULL; stack = stack -> next) { struct stack_element *new_configs; new_configs = follow_sources(stack, la_symbol, symbol); new_sources = add_configs(new_sources, act, new_configs); } } free_nodes(action[symbol], tail); action[symbol] = NULL; state = state_to_resolve_conflicts(new_sources, symbol, level + 1); if (state == NULL) goto clean_up_and_return; la_shift_state[symbol] = state; p = Allocate_node(); p -> value = state -> state_number; p -> next = NULL; action[symbol] = p; num_shift_actions++; action_list[symbol] = shift_root; shift_root = symbol; } else if (action[symbol] -> value < 0) { num_shift_actions++; action_list[symbol] = shift_root; shift_root = symbol; } else if (action[symbol] -> value > num_rules) { num_shift_actions++; (action[symbol] -> value) -= num_rules; action_list[symbol] = shift_root; shift_root = symbol; } else { num_reduce_actions++; action_list[symbol] = reduce_root; reduce_root = symbol; } } /*******************************************************************/ /* We now iterate over the reduce actions in the domain of sources */ /* and compute a default action. */ /*******************************************************************/ default_rule = OMEGA; count = 0; for (act = sources.root; act != NIL; act = sources.list[act]) { if (act >= 0 && act <= num_rules) { if (rule_count[act] > count) { count = rule_count[act]; default_rule = act; } } } /*******************************************************************/ /* By now, we are ready to create a new look-ahead state. The */ /* actions for the state are in the ACTION vector, and the */ /* constants: NUM_SHIFT_ACTIONS and NUM_REDUCE_ACTIONS indicate */ /* the number of shift and reduce actions in the ACTION vector. */ /* Note that the IN_STATE field of each look-ahead state created */ /* is initially set to the number associated with that state. If */ /* all the conflicts detected in the state, S, that requested the */ /* creation of a look-ahead state are resolved, then this field */ /* is updated with S. */ /* Otherwise, this field indicates that this look-ahead state is */ /* dangling - no other state point to it. */ /*******************************************************************/ state = (struct state_element *) talloc(sizeof(struct state_element)); if (state == (struct state_element *) NULL) nospace(__FILE__, __LINE__); state -> link = la_state_root; la_state_root = state; max_la_state++; SHORT_CHECK(max_la_state); state -> symbol = la_symbol; state -> state_number = max_la_state; state -> in_state = max_la_state; /* Initialize it to something! */ /*******************************************************************/ /* If there are any shift-actions in this state, we create a shift */ /* map for them if one does not yet exist, otherwise, we reuse the */ /* old existing one. */ /*******************************************************************/ if (num_shift_actions > 0) { unsigned long hash_address; struct shift_header_type sh; struct state_element *p; /***************************************************************/ /* In this loop, we compute the hash address as the number of */ /* shift actions, plus the sum of all the symbols on which a */ /* shift action is defined. As a side effect, we also take */ /* care of some other issues. Shift actions which were encoded */ /* to distinguish them from reduces action are decoded. */ /* The counters for shift and shift-reduce actions are updated.*/ /* For all Shift actions to look-ahead states, the IN_STATE */ /* field of these look-ahead target states are updated. */ /***************************************************************/ hash_address = num_shift_actions; /* Initialize hash address */ for (symbol = shift_root; symbol != NIL; symbol = action_list[symbol]) { hash_address += symbol; if (action[symbol] -> value < 0) num_shift_reduces++; else if (action[symbol] -> value <= num_states) num_shifts++; else /* lookahead-shift */ la_shift_state[symbol] -> in_state = max_la_state; } hash_address %= SHIFT_TABLE_SIZE; /***************************************************************/ /* Search list associated with HASH_ADDRESS, and if the shift */ /* map in question is found, update the SHIFT, and SHIFT_NUMBER*/ /* fields of the new Look-Ahead State. */ /***************************************************************/ for (p = shift_table[hash_address]; p != NULL; p = p -> next_shift) { /* Search hash table for shift map */ sh = p -> shift; if (sh.size == num_shift_actions) { for (i = 1; i <= num_shift_actions; i++) { /* compare shift maps */ if (SHIFT_ACTION(sh, i) != action[SHIFT_SYMBOL(sh, i)] -> value) break; } if (i > num_shift_actions) /* are they equal ? */ { state -> shift = sh; state -> shift_number = p -> shift_number; break; } } } /***************************************************************/ /* Shift map was not found. We have to create a new one and */ /* insert it into the table. */ /***************************************************************/ if (p == NULL) { num_shift_maps++; sh = Allocate_shift_map(num_shift_actions); state -> shift = sh; state -> shift_number = num_shift_maps; state -> next_shift = shift_table[hash_address]; shift_table[hash_address] = state; for (symbol = shift_root, i = 1; symbol != NIL; symbol = action_list[symbol], i++) { SHIFT_SYMBOL(sh, i) = symbol; SHIFT_ACTION(sh, i) = action[symbol] -> value; } } } else { state -> shift.size = 0; state -> shift_number = 0; } /*******************************************************************/ /* Construct Reduce map. */ /* When SPACE or TIME tables are requested, no default actions are */ /* taken. */ /*******************************************************************/ Build_reduce_map: { struct reduce_header_type red; int i; if (default_rule != OMEGA && table_opt != OPTIMIZE_TIME && table_opt != OPTIMIZE_SPACE && default_opt != 0) num_reduce_actions -= rule_count[default_rule]; num_reductions += num_reduce_actions; red = Allocate_reduce_map(num_reduce_actions); state -> reduce = red; for (symbol = reduce_root, i = 1; symbol != NIL; symbol = action_list[symbol]) { if (default_opt == 0 || action[symbol] -> value != default_rule || table_opt == OPTIMIZE_TIME || table_opt == OPTIMIZE_SPACE) { REDUCE_SYMBOL (red, i) = symbol; REDUCE_RULE_NO(red, i) = action[symbol] -> value; i++; } } REDUCE_SYMBOL(red, 0) = DEFAULT_SYMBOL; if (default_opt > 0) REDUCE_RULE_NO(red, 0) = default_rule; else REDUCE_RULE_NO(red, 0) = OMEGA; } /*******************************************************************/ /* Release all space allocated to process this lookahead state and */ /* return. */ /*******************************************************************/ clean_up_and_return: free_sources(new_sources); for (symbol = symbol_root; symbol != NIL; symbol = symbol_list[symbol]) { for (p = action[symbol]; p != NULL; tail = p, p = p -> next) ; if (action[symbol] != NULL) free_nodes(action[symbol], tail); } ffree(action); ffree(symbol_list); ffree(action_list); ffree(rule_count); ffree(look_ahead); ffree(la_shift_state); return state; } /***********************************************************************/ /* INIT_RMPSELF: */ /***********************************************************************/ /* This procedure is invoked when LALR_LEVEL > 1 to construct the */ /* RMPSELF set which identifies the nonterminals that can right-most */ /* produce themselves. It takes as argumen the map PRODUCES which */ /* identifies for each nonterminal the set of nonterminals that it can */ /* right-most produce. */ /***********************************************************************/ void init_rmpself(SET_PTR produces) { int nt; rmpself = Allocate_boolean_array(num_non_terminals); rmpself -= (num_terminals + 1); /*******************************************************************/ /* Note that each element of the map produces is a boolean vector */ /* that is indexable in the range 1..num_non_terminals. Since each */ /* nonterminal is offset by the value num_terminals (to distinguish*/ /* it from the terminals),it must therefore be adjusted accordingly*/ /* when dereferencing an element in the range of the produces map. */ /*******************************************************************/ for ALL_NON_TERMINALS(nt) rmpself[nt] = IS_IN_NTSET(produces, nt, nt - num_terminals); return; } /***********************************************************************/ /* INIT_LALRK_PROCESS: */ /***********************************************************************/ /* If LALR(k), k > 1, is requested, we may have to create more shift */ /* maps. Initialize SHIFT_TABLE. Note that each element of SHIFT_TABLE */ /* is automatically initialized to NULL by CALLOC. */ /* (See STATE_TO_RESOLVE_CONFLICTS) */ /* Second, we check whether or not the grammar is not LR(k) for any k */ /* because there exist a nonterminal A such that */ /* */ /* A =>+rm A */ /* */ /* Finally, allocate and compute the CYCLIC vector which identifies */ /* states that can enter a cycle via transitions on nullable */ /* nonterminals. If such a cyle exists, the grammar can also be */ /* claimed to be not LR(k) for any k. */ /***********************************************************************/ void init_lalrk_process(void) { int state_no, symbol; not_lrk = FALSE; if (lalr_level > 1) { shift_table = (struct state_element **) calloc(SHIFT_TABLE_SIZE, sizeof(struct state_element *)); if (shift_table == NULL) nospace(__FILE__, __LINE__); for ALL_NON_TERMINALS(symbol) not_lrk = not_lrk || rmpself[symbol]; cyclic = Allocate_boolean_array(num_states + 1); index_of = Allocate_short_array(num_states + 1); stack = Allocate_short_array(num_states + 1); for ALL_STATES(state_no) index_of[state_no] = OMEGA; top = 0; for ALL_STATES(state_no) { if (index_of[state_no] == OMEGA) compute_cyclic(state_no); not_lrk = not_lrk || cyclic[state_no]; } ffree(stack); ffree(index_of); sources = allocate_sources(); visited.map = (struct node **) calloc(num_states + 1, sizeof(struct node *)); if (visited.map == NULL) nospace(__FILE__, __LINE__); visited.list = Allocate_short_array(num_states + 1); visited.root = NIL; } return; } /***********************************************************************/ /* EXIT_LALRK_PROCESS: */ /***********************************************************************/ /* Free all support structures that were allocated to help compute */ /* additional lookahead. */ /***********************************************************************/ void exit_lalrk_process(void) { if (lalr_level > 1) { rmpself += (num_terminals + 1); ffree(rmpself); ffree(shift_table); ffree(cyclic); free_sources(sources); clear_visited(); ffree(visited.map); ffree(visited.list); } return; } /***********************************************************************/ /* FREE_CONFLICT_SPACE */ /***********************************************************************/ /* If we had to report conflicts, free the SLR support structures. */ /***********************************************************************/ void free_conflict_space(void) { if (nt_items != NULL) { nt_items += (num_terminals + 1); ffree(nt_items); ffree(item_list); } return; } /***********************************************************************/ /* RESOLVE_CONFLICTS: */ /***********************************************************************/ /* If conflicts were detected and LALR(k) processing was requested, */ /* where k > 1, then we attempt to resolve the conflicts by computing */ /* more lookaheads. Shift-Reduce conflicts are processed first, */ /* followed by Reduce-Reduce conflicts. */ /***********************************************************************/ void resolve_conflicts(int state_no, struct node **action, short *symbol_list, int symbol_root) { struct shift_header_type sh; struct node *p, *tail; struct stack_element *q; struct state_element *state; int i, act, item_no, lhs_symbol, symbol; /*******************************************************************/ /* Note that a shift action to a state "S" is encoded with the */ /* value (S+NUM_RULES) to help distinguish it from reduce actions. */ /* Reduce actions lie in the range [0..NUM_RULES]. Shift-reduce */ /* actions lie in the range [-NUM_RULES..-1]. */ /*******************************************************************/ sr_conflict_root = NULL; sh = shift[statset[state_no].shift_number]; for (i = 1; i <= sh.size; i++) { symbol = SHIFT_SYMBOL(sh, i); if (single_productions_bit && action[symbol] != NULL) add_conflict_symbol(state_no, symbol); if (lalr_level > 1 && action[symbol] != NULL) { sources = clear_sources(sources); q = allocate_stack_element(); q -> state_number = state_no; q -> size = 1; q -> previous = NULL; q -> next = NULL; act = SHIFT_ACTION(sh, i); if (act > 0) sources = add_configs(sources, act + num_rules, q); else sources = add_configs(sources, act, q); for (p = action[symbol]; p != NULL; tail = p, p = p -> next) { struct stack_element *new_configs; struct node *v, *s; item_no = p -> value; act = item_table[item_no].rule_number; lhs_symbol = rules[act].lhs; clear_visited(); v = lpgaccess(state_no, item_no); for (s = v; s != NULL; tail = s, s = s -> next) { q = allocate_stack_element(); q -> state_number = s -> value; q -> size = 1; q -> previous = NULL; q -> next = NULL; new_configs = follow_sources(q, lhs_symbol, symbol); if (new_configs == NULL) free_stack_elements(q, q); else { add_dangling_stack_element(q); sources = add_configs(sources, act, new_configs); } } free_nodes(v, tail); } /***************************************************************/ /* The function STATE_TO_RESOLVE_CONFLICTS returns a pointer */ /* value to a STATE_ELEMENT which has been constructed to */ /* resolve the conflicts in question. If the value returned by */ /* that function is NULL, then it was not possible to resolve */ /* the conflicts. In any case, STATE_TO_RESOLVE_CONFLICTS */ /* frees the space that is used by the action map headed by */ /* ACTION_ROOT. */ /***************************************************************/ state = state_to_resolve_conflicts(sources, symbol, 2); if (state != NULL) { state -> in_state = state_no; free_nodes(action[symbol], tail); action[symbol] = NULL; } } /***************************************************************/ /* If unresolved shift-reduce conflicts are detected on symbol,*/ /* add them to the list of conflicts so they can be reported */ /* (if the CONFLICT option is on) and count them. */ /***************************************************************/ if (action[symbol] != NULL) { act = SHIFT_ACTION(sh, i); for (p = action[symbol]; p != NULL; tail = p, p = p -> next) { if (conflicts_bit) { struct sr_conflict_element *q; q = (struct sr_conflict_element *) allocate_conflict_element(); q -> state_number = act; q -> item = p -> value; q -> symbol = symbol; q -> next = sr_conflict_root; sr_conflict_root = q; } num_sr_conflicts++; } /***********************************************************/ /* Remove reduce actions defined on symbol so as to give */ /* precedence to the shift. */ /***********************************************************/ free_nodes(action[symbol], tail); action[symbol] = NULL; } } /*******************************************************************/ /* We construct a map from each action to a list of states as we */ /* did for the Shift-reduce conflicts. A boolean vector ITEM_SEEN */ /* is used to prevent duplication of actions. This problem does */ /* not occur with Shift-Reduce conflicts. */ /*******************************************************************/ rr_conflict_root = NULL; for (symbol = symbol_root; symbol != NIL; symbol = symbol_list[symbol]) { if (action[symbol] != NULL) { if (single_productions_bit && action[symbol] -> next != NULL) add_conflict_symbol(state_no, symbol); if (lalr_level > 1 && action[symbol] -> next != NULL) { sources = clear_sources(sources); for (p = action[symbol]; p != NULL; tail = p, p = p -> next) { struct stack_element *new_configs; struct node *v, *s; item_no = p -> value; act = item_table[item_no].rule_number; lhs_symbol = rules[act].lhs; clear_visited(); v = lpgaccess(state_no, item_no); for (s = v; s != NULL; tail = s, s = s -> next) { q = allocate_stack_element(); q -> state_number = s -> value; q -> size = 1; q -> previous = NULL; q -> next = NULL; new_configs = follow_sources(q, lhs_symbol, symbol); if (new_configs == NULL) free_stack_elements(q, q); else { add_dangling_stack_element(q); sources = add_configs(sources, act, new_configs); } } free_nodes(v, tail); } /***************************************************************/ /* STATE_TO_RESOLVE_CONFLICTS will return a pointer to a */ /* STATE_ELEMENT if the conflicts were resolvable with more */ /* lookaheads, otherwise, it returns NULL. */ /***************************************************************/ state = state_to_resolve_conflicts(sources, symbol, 2); if (state != NULL) { state -> in_state = state_no; free_nodes(action[symbol], tail); action[symbol] = NULL; } } /***********************************************************/ /* If unresolved reduce-reduce conflicts are detected on */ /* symbol, add them to the list of conflicts so they can be*/ /* reported (if the CONFLICT option is on) and count them. */ /***********************************************************/ if (action[symbol] != NULL) { act = action[symbol] -> value; for (p = action[symbol] -> next; p != NULL; tail = p, p = p -> next) { if (conflicts_bit) { struct rr_conflict_element *q; q = (struct rr_conflict_element *) allocate_conflict_element(); q -> symbol = symbol; q -> item1 = act; q -> item2 = p -> value; q -> next = rr_conflict_root; rr_conflict_root = q; } num_rr_conflicts++; } /***********************************************************/ /* Remove all reduce actions that are defined on symbol */ /* except the first one. That rule is the one with the */ /* longest right-hand side that was associated with symbol.*/ /* See code in MKRED.C. */ /***********************************************************/ if (action[symbol] -> next != NULL) { free_nodes(action[symbol] -> next, tail); action[symbol] -> next = NULL; } } } } /*******************************************************************/ /* If any unresolved conflicts were detected, process them. */ /*******************************************************************/ if (sr_conflict_root != NULL || rr_conflict_root != NULL) process_conflicts(state_no); free_dangling_stack_elements(); return; } /***********************************************************************/ /* CREATE_LASTATS: */ /***********************************************************************/ /* Transfer the look-ahead states to their permanent destination, the */ /* array LASTATS and update the original automaton with the relevant */ /* transitions into the lookahead states. */ /***********************************************************************/ void create_lastats(void) { struct state_element **new_shift_actions, *p; struct shift_header_type sh; short *shift_action, *shift_list, *shift_count, *state_list; int shift_root, state_root, shift_size, i, symbol, state_no, shift_no; /*******************************************************************/ /* Allocate LASTATS structure to permanently construct lookahead */ /* states and reallocate SHIFT map as we may have to construct */ /* new shift maps. */ /*******************************************************************/ lastats = (struct lastats_type *) calloc(max_la_state - num_states, sizeof(struct lastats_type)); if (lastats == NULL) nospace(__FILE__, __LINE__); lastats -= (num_states + 1); shift = (struct shift_header_type *) realloc(shift, (max_la_state + 1) * sizeof(struct shift_header_type)); if (shift == NULL) nospace(__FILE__, __LINE__); /*******************************************************************/ /* Allocate temporary space used to construct final lookahead */ /* states. */ /*******************************************************************/ new_shift_actions = (struct state_element **) calloc(num_states + 1, sizeof(struct state_element *)); if (new_shift_actions == NULL) nospace(__FILE__, __LINE__); shift_action = Allocate_short_array(num_terminals + 1); shift_list = Allocate_short_array(num_terminals + 1); shift_count = Allocate_short_array(max_la_state + 1); state_list = Allocate_short_array(max_la_state + 1); /*******************************************************************/ /* The array shift_action will be used to construct a shift map */ /* for a given state. It is initialized here to the empty map. */ /* The array shift_count is used to count how many references */ /* there are to each shift map. */ /*******************************************************************/ for ALL_TERMINALS(symbol) shift_action[symbol] = OMEGA; for (i = 0; i <= (int) max_la_state; i++) shift_count[i] = 0; for ALL_STATES(state_no) shift_count[statset[state_no].shift_number]++; /*******************************************************************/ /* Traverse the list of lookahead states and initialize the */ /* final lastat element appropriately. Also, construct a mapping */ /* from each relevant initial state into the list of lookahead */ /* states into which it can shift. We also keep track of these */ /* initial states in a list headed by state_root. */ /*******************************************************************/ state_root = NIL; for (p = la_state_root; p != NULL; p = p -> link) { lastats[p -> state_number].in_state = p -> in_state; lastats[p -> state_number].shift_number = p -> shift_number; lastats[p -> state_number].reduce = p -> reduce; if (p -> shift.size != 0) shift[p -> shift_number] = p -> shift; state_no = p -> in_state; if (state_no <= (int) num_states) { if (new_shift_actions[state_no] == NULL) { state_list[state_no] = state_root; state_root = state_no; } p -> next_shift = new_shift_actions[state_no]; new_shift_actions[state_no] = p; } } /*******************************************************************/ /* We now traverse the list of initial states that can shift into */ /* lookahead states and update their shift map appropriately. */ /*******************************************************************/ for (state_no = state_root; state_no != NIL; state_no = state_list[state_no]) { /***************************************************************/ /* Copy the shift map associated with STATE_NO into the direct */ /* access map SHIFT_ACTION. */ /***************************************************************/ shift_no = statset[state_no].shift_number; sh = shift[shift_no]; shift_root = NIL; for (i = 1; i <= sh.size; i++) { symbol = SHIFT_SYMBOL(sh, i); shift_action[symbol] = SHIFT_ACTION(sh, i); shift_list[symbol] = shift_root; shift_root = symbol; } /***************************************************************/ /* Add the lookahead shift transitions to the initial shift */ /* map. */ /***************************************************************/ shift_size = sh.size; for (p = new_shift_actions[state_no]; p != NULL; p = p -> next_shift) { if (shift_action[p -> symbol] == OMEGA) { shift_size++; shift_list[p -> symbol] = shift_root; shift_root = p -> symbol; } else if (shift_action[p -> symbol] < 0) num_shift_reduces--; else num_shifts--; shift_action[p -> symbol] = p -> state_number; } /***************************************************************/ /* There are two conditions under which we have to construct */ /* a brand new shift map: */ /* 1. The initial shift map was shared with other states. */ /* 2. The updated shift map contains more elements than */ /* the initial one. */ /***************************************************************/ if (shift_count[shift_no] > 1) { shift_count[shift_no]--; num_shift_maps++; sh = Allocate_shift_map(shift_size); shift[num_shift_maps] = sh; statset[state_no].shift_number = num_shift_maps; } else if (shift_size > sh.size) { sh = Allocate_shift_map(shift_size); shift[shift_no] = sh; } /***************************************************************/ /* Reconstruct the relevant shift map. */ /***************************************************************/ for (symbol = shift_root, i = 1; symbol != NIL; shift_action[symbol] = OMEGA, symbol = shift_list[symbol], i++) { SHIFT_SYMBOL(sh, i) = symbol; SHIFT_ACTION(sh, i) = shift_action[symbol]; } } /*******************************************************************/ /* Free all local temporary structures and return. */ /*******************************************************************/ ffree(new_shift_actions); ffree(shift_action); ffree(shift_list); ffree(shift_count); ffree(state_list); return; } jikespg-1.3/src/space.h000066400000000000000000000020101167345774400150570ustar00rootroot00000000000000/* $Id: space.h,v 1.2 1999/11/04 14:02:23 shields Exp $ */ /* This software is subject to the terms of the IBM Jikes Compiler License Agreement available at the following URL: http://www.ibm.com/research/jikes. Copyright (C) 1983, 1999, International Business Machines Corporation and others. All Rights Reserved. You must accept the terms of that agreement to use this software. */ #ifndef SPACE_INCLUDED #define SPACE_INCLUDED struct new_state_type { struct reduce_header_type reduce; short shift_number, link, thread, image; }; extern struct new_state_type *new_state_element; extern short *shift_image, *real_shift_number; extern int *term_state_index, *shift_check_index; extern int shift_domain_count, num_terminal_states, check_size, term_check_size, term_action_size, shift_check_size; #endif /* SPACE_INCLUDED */ jikespg-1.3/src/spacetab.c000066400000000000000000002334101167345774400155530ustar00rootroot00000000000000/* $Id: spacetab.c,v 1.2 1999/11/04 14:02:23 shields Exp $ */ /* This software is subject to the terms of the IBM Jikes Compiler License Agreement available at the following URL: http://www.ibm.com/research/jikes. Copyright (C) 1983, 1999, International Business Machines Corporation and others. All Rights Reserved. You must accept the terms of that agreement to use this software. */ static char hostfile[] = __FILE__; #include #include "common.h" #include "space.h" #include "header.h" static struct node **new_state_element_reduce_nodes; static long total_bytes, num_table_entries; static int top, empty_root, single_root, multi_root; static short *row_size, *frequency_symbol, *frequency_count; static BOOLEAN *shift_on_error_symbol; /****************************************************************************/ /* REMAP_NON_TERMINALS: */ /****************************************************************************/ /* REMAP_NON_TERMINALS remaps the non-terminal symbols and states based on */ /* frequency of entries. */ /****************************************************************************/ static void remap_non_terminals(void) { short *frequency_symbol, *frequency_count, *row_size; struct goto_header_type go_to; int i, state_no, symbol; /**********************************************************************/ /* The variable FREQUENCY_SYMBOL is used to hold the non-terminals */ /* in the grammar, and FREQUENCY_COUNT is used correspondingly to */ /* hold the number of actions defined on each non-terminal. */ /* ORDERED_STATE and ROW_SIZE are used in a similar fashion for states*/ /**********************************************************************/ frequency_symbol = Allocate_short_array(num_non_terminals); frequency_symbol -= (num_terminals + 1); frequency_count = Allocate_short_array(num_non_terminals); frequency_count -= (num_terminals + 1); row_size = Allocate_short_array(num_states + 1); for ALL_NON_TERMINALS(i) { frequency_symbol[i] = i; frequency_count[i] = 0; } for ALL_STATES(state_no) { ordered_state[state_no] = state_no; row_size[state_no] = 0; go_to = statset[state_no].go_to; for (i = 1; i <= go_to.size; i++) { row_size[state_no]++; symbol = GOTO_SYMBOL(go_to, i); frequency_count[symbol]++; } } /**********************************************************************/ /* The non-terminals are sorted in descending order based on the */ /* number of actions defined on then, and they are remapped based on */ /* the new arrangement obtained by the sorting. */ /**********************************************************************/ sortdes(frequency_symbol, frequency_count, num_terminals + 1, num_symbols, num_states); for ALL_NON_TERMINALS(i) symbol_map[frequency_symbol[i]] = i; /**********************************************************************/ /* All non-terminal entries in the state automaton are updated */ /* accordingly. We further subtract NUM_TERMINALS from each */ /* non-terminal to make them fall in the range [1..NUM_NON_TERMINLS] */ /* instead of [NUM_TERMINALS+1..NUM_SYMBOLS]. */ /**********************************************************************/ for ALL_STATES(state_no) { go_to = statset[state_no].go_to; for (i = 1; i <= go_to.size; i++) GOTO_SYMBOL(go_to, i) = symbol_map[GOTO_SYMBOL(go_to, i)] - num_terminals; } /**********************************************************************/ /* If Goto-Default was requested, we find out how many non-terminals */ /* were eliminated as a result, and adjust the GOTO-DEFAULT map, */ /* based on the new mapping of the non-terminals. */ /**********************************************************************/ if (goto_default_bit) { short *temp_goto_default; temp_goto_default = Allocate_short_array(num_non_terminals); temp_goto_default -= (num_terminals + 1); for (last_symbol = num_symbols; last_symbol > num_terminals; last_symbol--) if (frequency_count[last_symbol] != 0) break; last_symbol -= num_terminals; sprintf(msg_line, "Number of non-terminals eliminated: %d", num_non_terminals - last_symbol); PRNT(msg_line); /**************************************************************/ /* Remap the GOTO-DEFAULT map. */ /* to hold the original map. */ /**************************************************************/ for ALL_NON_TERMINALS(symbol) temp_goto_default[symbol_map[symbol]] = gotodef[symbol]; gotodef += (num_terminals + 1); ffree(gotodef); gotodef = temp_goto_default; } else last_symbol = num_non_terminals; /**********************************************************************/ /* The states are sorted in descending order based on the number of */ /* actions defined on them, and they are remapped based on the new */ /* arrangement obtained by the sorting. */ /**********************************************************************/ sortdes(ordered_state, row_size, 1, num_states, last_symbol); frequency_symbol += (num_terminals + 1); ffree(frequency_symbol); frequency_count += (num_terminals + 1); ffree(frequency_count); ffree(row_size); return; } /****************************************************************************/ /* OVERLAP_NT_ROWS: */ /****************************************************************************/ /* We now overlap the non-terminal table, or more precisely, we compute the */ /* starting position in a vector where each of its rows may be placed */ /* without clobbering elements in another row. The starting positions are */ /* stored in the vector STATE_INDEX. */ /****************************************************************************/ static void overlap_nt_rows(void) { struct goto_header_type go_to; int max_indx, indx, k, j, i, k_bytes, percentage, state_no, symbol; long num_bytes; num_table_entries = num_gotos + num_goto_reduces + num_states; increment_size = MAX((num_table_entries / 100 * increment), (last_symbol + 1)); table_size = MIN((num_table_entries + increment_size), MAX_TABLE_SIZE); /*************************************************************************/ /* Allocate space for table, and initlaize the AVAIL_POOL list. The */ /* variable FIRST_INDEX keeps track of the first element in the doubly- */ /* linked list, and LAST_ELEMENT keeps track of the last element in the */ /* list. */ /* The variable MAX_INDX is used to keep track of the maximum starting */ /* position for a row that has been used. */ /*************************************************************************/ next = Allocate_int_array(table_size + 1); previous = Allocate_int_array(table_size + 1); first_index = 1; previous[first_index] = NIL; next[first_index] = first_index + 1; for (indx = 2; indx < (int) table_size; indx++) { next[indx] = indx + 1; previous[indx] = indx - 1; } last_index = table_size; previous[last_index] = last_index - 1; next[last_index] = NIL; max_indx = first_index; /*******************************************************************/ /* We now iterate over all the states in their new sorted order as */ /* indicated by the variable STATE_NO, and determine an "overlap" */ /* position for them. */ /*******************************************************************/ for ALL_STATES(k) { state_no = ordered_state[k]; /****************************************************************/ /* INDX is set to the beginning of the list of available slots */ /* and we try to determine if it might be a valid starting */ /* position. If not, INDX is moved to the next element, and we */ /* repeat the process until a valid position is found. */ /****************************************************************/ go_to = statset[state_no].go_to; indx = first_index; look_for_match_in_base_table: if (indx == NIL) indx = table_size + 1; if (indx + last_symbol > table_size) reallocate(); for (i = 1; i <= go_to.size; i++) { if (next[indx + GOTO_SYMBOL(go_to, i)] == OMEGA) { indx = next[indx]; goto look_for_match_in_base_table; } } /*****************************************************************/ /* At this stage, a position(INDX), was found to overlay the row */ /* in question. Remove elements associated with all positions */ /* that will be taken by row from the doubly-linked list. */ /* NOTE tha since SYMBOLs start at 1, the first index can never */ /* be a candidate (==> I = INDX + SYMBOL) in this loop. */ /*****************************************************************/ for (j = 1; j <= go_to.size; j++) { symbol = GOTO_SYMBOL(go_to, j); i = indx + symbol; if (i == last_index) { last_index = previous[last_index]; next[last_index] = NIL; } else { next[previous[i]] = next[i]; previous[next[i]] = previous[i]; } next[i] = OMEGA; } if (first_index == last_index) first_index = NIL; else if (indx == first_index) { first_index = next[first_index]; previous[first_index] = NIL; } else if (indx == last_index) { last_index = previous[last_index]; next[last_index] = NIL; } else { next[previous[indx]] = next[indx]; previous[next[indx]] = previous[indx]; } next[indx] = OMEGA; if (indx > max_indx) max_indx = indx; state_index[state_no] = indx; } if (goto_default_bit || nt_check_bit) check_size = max_indx + num_non_terminals; else check_size = 0; for (action_size = max_indx + last_symbol; action_size >= max_indx; action_size--) if (next[action_size] == OMEGA) break; accept_act = max_indx + num_rules + 1; error_act = accept_act + 1; printf("\n"); if (goto_default_bit || nt_check_bit) { sprintf(msg_line,"Length of base Check Table: %d", check_size); PRNT(msg_line); } sprintf(msg_line,"Length of base Action Table: %ld", action_size); PRNT(msg_line); sprintf(msg_line,"Number of entries in base Action Table: %d", num_table_entries); PRNT(msg_line); percentage = ((action_size - num_table_entries) * 1000) / num_table_entries; sprintf(msg_line, "Percentage of increase: %d.%d%%", percentage / 10, percentage % 10); PRNT(msg_line); if (byte_bit) { num_bytes = 2 * action_size + check_size; if (goto_default_bit || nt_check_bit) { if (last_symbol > 255) num_bytes += check_size; } } else num_bytes = 2 * (action_size + check_size); if (goto_default_bit) num_bytes += ((long) 2 * num_non_terminals); total_bytes = num_bytes; k_bytes = (num_bytes / 1024) + 1; sprintf(msg_line,"Storage required for base Tables: %ld Bytes, %dK", num_bytes, k_bytes); PRNT(msg_line); num_bytes = (long) 4 * num_rules; if (byte_bit) { num_bytes -= num_rules; if (num_non_terminals < 256) num_bytes -= num_rules; } sprintf(msg_line, "Storage required for Rules: %ld Bytes", num_bytes); PRNT(msg_line); return; } /*********************************************************************/ /* MERGE_SIMILAR_T_ROWS: */ /*********************************************************************/ /* We now try to merge states in the terminal table that are similar.*/ /* Two states S1 and S2 are said to be similar if they contain the */ /* same shift actions and they reduce to the same set of rules. In */ /* addition, there must not exist a terminal symbol "t" such that: */ /* REDUCE(S1, t) and REDUCE(S2, t) are defined, and */ /* REDUCE(S1, t) ^= REDUCE(S2, t) */ /*********************************************************************/ static void merge_similar_t_rows(void) { struct shift_header_type sh; struct reduce_header_type red; short *table; int i, j, rule_no, state_no; unsigned long hash_address; struct node *q, *r, *tail, *reduce_root; table = Allocate_short_array(num_shift_maps + 1); empty_root = NIL; single_root = NIL; multi_root = NIL; top = 0; for (i = 1; i <= (int) max_la_state; i++) shift_on_error_symbol[i] = FALSE; for (i = 0; i <= num_shift_maps; i++) table[i] = NIL; /*********************************************************************/ /* We now hash all the states into TABLE, based on their shift map */ /* number. */ /* The rules in the range of the REDUCE MAP are placed in sorted */ /* order in a linear linked list headed by REDUCE_ROOT. */ /*********************************************************************/ for (state_no = 1; state_no <= (int) max_la_state; state_no++) { reduce_root = NULL; if (state_no > (int) num_states) red = lastats[state_no].reduce; else red = reduce[state_no]; for (i = 1; i <= red.size; i++) { rule_no = REDUCE_RULE_NO(red, i); for (q = reduce_root; q != NULL; tail = q, q = q -> next) { /* Is it or not in REDUCE_ROOT list? */ if (q -> value == rule_no) goto continue_traverse_reduce_map; if (q -> value > rule_no) break; } r = Allocate_node(); /* Add element to REDUCE_ROOT list */ r -> value = rule_no; if (q == reduce_root) { r -> next = reduce_root; reduce_root = r; } else { r -> next = q; tail -> next = r; } continue_traverse_reduce_map:; } /*********************************************************************/ /* We compute the HASH_ADDRESS, mark if the state has a shift */ /* action on the ERROR symbol, and search the hash TABLE to see if a */ /* state matching the description is already in there. */ /*********************************************************************/ if (state_no > (int) num_states) hash_address = lastats[state_no].shift_number; else { if (default_opt == 5) { sh = shift[statset[state_no].shift_number]; for (j = 1; (j <= sh.size) && (! shift_on_error_symbol[state_no]); j++) shift_on_error_symbol[state_no] = (SHIFT_SYMBOL(sh, j) == error_image); } hash_address = statset[state_no].shift_number; } for (i = table[hash_address]; i != NIL; i = new_state_element[i].link) { for (r = reduce_root, q = new_state_element_reduce_nodes[i]; (r != NULL) && (q != NULL); r = r -> next, q = q -> next) { if (r -> value != q -> value) break; } if (r == q) break; } /*********************************************************************/ /* If the state is a new state to be inserted in the table, we now */ /* do so, and place it in the proper category based on its reduces, */ /* In any case, the IMAGE field is updated, and so is the relevant */ /* STATE_LIST element. */ /* */ /* If the state contains a shift action on the error symbol and also */ /* contains reduce actions, we allocate a new element for it and */ /* place it in the list headed by MULTI_ROOT. Such states are not */ /* merged, because we do not take default reductions in them. */ /*********************************************************************/ if (shift_on_error_symbol[state_no] && (reduce_root != NULL)) { top++; if (i == NIL) { new_state_element[top].link = table[hash_address]; table[hash_address] = top; } new_state_element[top].thread = multi_root; multi_root = top; new_state_element[top].shift_number = hash_address; new_state_element_reduce_nodes[top] = reduce_root; state_list[state_no] = NIL; new_state_element[top].image = state_no; } else if (i == NIL) { top++; new_state_element[top].link = table[hash_address]; table[hash_address] = top; if (reduce_root == NULL) { new_state_element[top].thread = empty_root; empty_root = top; } else if (reduce_root -> next == NULL) { new_state_element[top].thread = single_root; single_root = top; } else { new_state_element[top].thread = multi_root; multi_root = top; } new_state_element[top].shift_number = hash_address; new_state_element_reduce_nodes[top] = reduce_root; state_list[state_no] = NIL; new_state_element[top].image = state_no; } else { state_list[state_no] = new_state_element[i].image; new_state_element[i].image = state_no; for (r = reduce_root; r != NULL; tail = r, r = r -> next) ; if (reduce_root != NULL) free_nodes(reduce_root, tail); } } ffree(table); return; } /*********************************************************************/ /* MERGE_SHIFT_DOMAINS: */ /*********************************************************************/ /* If shift-default actions are requested, the shift actions */ /* associated with each state are factored out of the Action matrix */ /* and all identical rows are merged. This merged matrix is used to */ /* create a boolean vector that may be used to confirm whether or not*/ /* there is a shift action in a given state S on a given symbol t. */ /* If we can determine that there is a shift action on a pair (S, t) */ /* we can apply shift default to the Shift actions just like we did */ /* for the Goto actions. */ /*********************************************************************/ static void merge_shift_domains(void) { short *shift_domain_link, *ordered_shift, *terminal_list, *temp_shift_default; short shift_domain_table[SHIFT_TABLE_SIZE]; struct shift_header_type sh; struct reduce_header_type red; BOOLEAN *shift_symbols; unsigned long hash_address; int i, j, indx, max_indx, k_bytes, old_table_size, k, percentage, shift_size, shift_no, symbol, state_no; long num_bytes; /*********************************************************************/ /* Some of the rows in the shift action map have already been merged */ /* by the merging of compatible states... We simply need to increase */ /* the size of the granularity by merging these new terminal states */ /* based only on their shift actions. */ /* */ /* The array SHIFT_DOMAIN_TABLE is used as the base for a hash table.*/ /* Each submap represented by a row of the shift action map is hashed*/ /* into this table by summing the terminal symbols in its domain. */ /* The submap is then entered in the hash table and assigned a unique*/ /* number if such a map was not already placed in the hash table. */ /* Otherwise, the number assigned to the previous submap is also */ /* associated with the new submap. */ /* */ /* The vector SHIFT_IMAGE is used to keep track of the unique number */ /* associated with each unique shift submap. */ /* The vector REAL_SHIFT_NUMBER is the inverse of SHIFT_IMAGE. It is */ /* used to associate each unique number to its shift submap. */ /* The integer NUM_TABLE_ENTRIES is used to count the number of */ /* elements in the new merged shift map. */ /* */ /* The arrays ORDERED_SHIFT and ROW_SIZE are also initialized here. */ /* They are used to sort the rows of the shift actions map later... */ /*********************************************************************/ shift_domain_link = Allocate_short_array(num_terminal_states + 1); ordered_shift = Allocate_short_array(num_shift_maps + 1); terminal_list = Allocate_short_array(num_terminals + 1); shift_image = Allocate_short_array(max_la_state + 1); real_shift_number = Allocate_short_array(num_shift_maps + 1); shift_symbols = Allocate_boolean_array(num_terminals + 1); shift_check_index = Allocate_int_array(num_shift_maps + 1); for (i = 0; i <= SHIFT_TABLE_UBOUND; i++) shift_domain_table[i] = NIL; num_table_entries = 0; shift_domain_count = 0; for (state_no = 1; state_no <= num_terminal_states; state_no++) { shift_no = new_state_element[state_no].shift_number; for (i = 1; i <=num_terminals; i++) shift_symbols[i] = FALSE; sh = shift[shift_no]; shift_size = sh.size; hash_address = shift_size; for (i = 1; i <= shift_size; i++) { symbol = SHIFT_SYMBOL(sh, i); hash_address += symbol; shift_symbols[symbol] = TRUE; } hash_address %= SHIFT_TABLE_SIZE; for (i = shift_domain_table[hash_address]; i != NIL; i = shift_domain_link[i]) { sh = shift[new_state_element[i].shift_number]; if (sh.size == shift_size) { for (j = 1; j <= shift_size; j++) if (! shift_symbols[SHIFT_SYMBOL(sh, j)]) break; if (j > shift_size) { shift_image[state_no] = shift_image[i]; goto continu; } } } shift_domain_link[state_no] = shift_domain_table[hash_address]; shift_domain_table[hash_address] = state_no; shift_domain_count++; shift_image[state_no] = shift_domain_count; real_shift_number[shift_domain_count] = shift_no; ordered_shift[shift_domain_count] = shift_domain_count; row_size[shift_domain_count] = shift_size; num_table_entries += shift_size; continu:; } /*********************************************************************/ /* Compute the frequencies, and remap the terminal symbols */ /* accordingly. */ /*********************************************************************/ for ALL_TERMINALS(symbol) { frequency_symbol[symbol] = symbol; frequency_count[symbol] = 0; } for (i = 1; i <= shift_domain_count; i++) { shift_no = real_shift_number[i]; sh = shift[shift_no]; for (j = 1; j <= sh.size; j++) { symbol = SHIFT_SYMBOL(sh, j); frequency_count[symbol]++; } } sortdes(frequency_symbol, frequency_count, 1, num_terminals, shift_domain_count); for ALL_TERMINALS(symbol) symbol_map[frequency_symbol[symbol]] = symbol; symbol_map[DEFAULT_SYMBOL] = DEFAULT_SYMBOL; eoft_image = symbol_map[eoft_image]; if (error_maps_bit) { error_image = symbol_map[error_image]; eolt_image = symbol_map[eolt_image]; } for (i = 1; i <= num_shift_maps; i++) { sh = shift[i]; for (j = 1; j <= sh.size; j++) SHIFT_SYMBOL(sh, j) = symbol_map[SHIFT_SYMBOL(sh, j)]; } for (state_no = 1; state_no <= num_terminal_states; state_no++) { red = new_state_element[state_no].reduce; for (i = 1; i <= red.size; i++) REDUCE_SYMBOL(red, i) = symbol_map[REDUCE_SYMBOL(red, i)]; } /*********************************************************************/ /* If ERROR_MAPS are requested, we also have to remap the original */ /* REDUCE maps. */ /*********************************************************************/ if (error_maps_bit) { for ALL_STATES(state_no) { red = reduce[state_no]; for (i = 1; i <= red.size; i++) REDUCE_SYMBOL(red, i) = symbol_map[REDUCE_SYMBOL(red, i)]; } } /************************************************************/ /* Remap the SHIFT_DEFAULT map. */ /************************************************************/ temp_shift_default = Allocate_short_array(num_terminals + 1); for ALL_TERMINALS(symbol) temp_shift_default[symbol_map[symbol]] = shiftdf[symbol]; ffree(shiftdf); shiftdf = temp_shift_default; /*********************************************************************/ /* We now compute the starting position for each Shift check row */ /* as we did for the terminal states. The starting positions are */ /* stored in the vector SHIFT_CHECK_INDEX. */ /*********************************************************************/ sortdes(ordered_shift, row_size, 1, shift_domain_count, num_terminals); increment_size = MAX((num_table_entries / 100 * increment), (num_terminals + 1)); old_table_size = table_size; table_size = MIN((num_table_entries + increment_size), MAX_TABLE_SIZE); if ((int) table_size > old_table_size) { ffree(previous); ffree(next); previous = Allocate_int_array(table_size + 1); next = Allocate_int_array(table_size + 1); } else table_size = old_table_size; first_index = 1; previous[first_index] = NIL; next[first_index] = first_index + 1; for (indx = 2; indx < (int) table_size; indx++) { next[indx] = indx + 1; previous[indx] = indx - 1; } last_index = table_size; previous[last_index] = last_index - 1; next[last_index] = NIL; max_indx = first_index; /*********************************************************************/ /* Look for a suitable index where to overlay the shift check row. */ /*********************************************************************/ for (k = 1; k <= shift_domain_count; k++) { shift_no = ordered_shift[k]; sh = shift[real_shift_number[shift_no]]; indx = first_index; look_for_match_in_sh_chk_tab: if (indx == NIL) indx = table_size + 1; if (indx + num_terminals > (int) table_size) reallocate(); for (i = 1; i <= sh.size; i++) { symbol = SHIFT_SYMBOL(sh, i); if (next[indx + symbol] == OMEGA) { indx = next[indx]; goto look_for_match_in_sh_chk_tab; } } /*********************************************************************/ /* INDX marks the starting position for the row, remove all the */ /* positions that are claimed by that shift check row. */ /* If a position has the value 0, then it is the starting position */ /* of a Shift row that was previously processed, and that element */ /* has already been removed from the list of available positions. */ /*********************************************************************/ for (j = 1; j <= sh.size; j++) { symbol = SHIFT_SYMBOL(sh, j); i = indx + symbol; if (next[i] != 0) { if (i == last_index) { last_index = previous[last_index]; next[last_index] = NIL; } else { next[previous[i]] = next[i]; previous[next[i]] = previous[i]; } } next[i] = OMEGA; } /*********************************************************************/ /* We now remove the starting position itself from the list without */ /* marking it as taken, since it can still be used for a shift check.*/ /* MAX_INDX is updated if required. */ /* SHIFT_CHECK_INDEX(SHIFT_NO) is properly set to INDX as the */ /* starting position of STATE_NO. */ /*********************************************************************/ if (first_index == last_index) first_index = NIL; else if (indx == first_index) { first_index = next[first_index]; previous[first_index] = NIL; } else if (indx == last_index) { last_index = previous[last_index]; next[last_index] = NIL; } else { next[previous[indx]] = next[indx]; previous[next[indx]] = previous[indx]; } next[indx] = 0; if (indx > max_indx) max_indx = indx; shift_check_index[shift_no] = indx; } /*********************************************************************/ /* Update all counts, and report statistics. */ /*********************************************************************/ shift_check_size = max_indx + num_terminals; printf("\n"); sprintf(msg_line,"Length of Shift Check Table: %d",shift_check_size); PRNT(msg_line); sprintf(msg_line,"Number of entries in Shift Check Table: %d", num_table_entries); PRNT(msg_line); for (k = shift_check_size; k >= max_indx; k--) if (next[k] == OMEGA) break; percentage = (((long) k - num_table_entries) * 1000) / num_table_entries; sprintf(msg_line,"Percentage of increase: %d.%d%%", (percentage/10),(percentage % 10)); PRNT(msg_line); if (byte_bit) { num_bytes = shift_check_size; if (num_terminals > 255) num_bytes +=shift_check_size; } else num_bytes = 2 * shift_check_size; num_bytes += 2 * (num_terminal_states + num_terminals); k_bytes = (num_bytes / 1024) + 1; sprintf(msg_line, "Storage required for Shift Check Table: %ld Bytes, %dK", num_bytes, k_bytes); PRNT(msg_line); total_bytes += num_bytes; ffree(ordered_shift); ffree(terminal_list); ffree(shift_symbols); ffree(shift_domain_link); return; } /*********************************************************************/ /* OVERLAY_SIM_T_ROWS: */ /*********************************************************************/ /* By now, similar states have been grouped together, and placed in */ /* one of three linear linked lists headed by the root pointers: */ /* MULTI_ROOT, SINGLE_ROOT, and EMPTY_ROOT. */ /* We iterate over each of these lists and construct new states out */ /* of these groups of similar states when they are compatible. Then, */ /* we remap the terminal symbols. */ /*********************************************************************/ static void overlay_sim_t_rows(void) { int j, k, i, rule_no, state_no, symbol, default_rule, state_subset_root, state_set_root, state_root, reduce_size, num_shifts_saved = 0, num_reductions_saved = 0, default_saves = 0; short *rule_count, *reduce_action; struct shift_header_type sh; struct reduce_header_type red; struct reduce_header_type new_red; struct node *q, *tail; rule_count = Allocate_short_array(num_rules + 1); reduce_action = Allocate_short_array(num_terminals + 1); /*********************************************************************/ /* We first iterate over the groups of similar states in the */ /* MULTI_ROOT list. These states have been grouped together, */ /* because they have the same Shift map, and reduce to the same */ /* rules, but we must check that they are fully compatible by making */ /* sure that no two states contain reduction to a different rule on */ /* the same symbol. */ /* The idea is to take a state out of the group, and merge with */ /* it as many other compatible states from the group as possible. */ /* remaining states from the group that caused clashes are thrown */ /* back into the MULTI_ROOT list as a new group of states. */ /*********************************************************************/ for (i = multi_root; i != NIL; i = new_state_element[i].thread) { for (q = new_state_element_reduce_nodes[i]; q != NULL; q = q -> next) { rule_count[q -> value] = 0; } /*********************************************************************/ /* REDUCE_ACTION is used to keep track of reductions that are to be */ /* applied on terminal symbols as the states are merged. We pick */ /* out the first state (STATE_NO) from the group of states involved, */ /* initialize REDUCE_ACTION with its reduce map, and count the number*/ /* of reductions associated with each rule in that state. */ /*********************************************************************/ state_no = new_state_element[i].image; if (state_no > (int) num_states) red = lastats[state_no].reduce; else red = reduce[state_no]; for ALL_TERMINALS(j) reduce_action[j] = OMEGA; for (j = 1; j <= red.size; j++) { rule_no = REDUCE_RULE_NO(red, j); reduce_action[REDUCE_SYMBOL(red, j)] = rule_no; rule_count[rule_no]++; } /*********************************************************************/ /* STATE_SET_ROOT is used to traverse the rest of the list that form */ /* the group of states being processed. STATE_SUBSET_ROOT is used */ /* to construct the new list that will consist of all states in the */ /* group that are compatible starting with the initial state. */ /* STATE_ROOT is used to construct a list of all states in the group */ /* that are not compatible with the initial state. */ /*********************************************************************/ state_set_root = state_list[state_no]; state_subset_root = state_no; state_list[state_subset_root] = NIL; state_root = NIL; for (state_no = state_set_root; state_no != NIL; state_no = state_set_root) { state_set_root = state_list[state_set_root]; /*********************************************************************/ /* We traverse the reduce map of the state taken out from the group */ /* and check to see if it is compatible with the subset being */ /* constructed so far. */ /*********************************************************************/ if (state_no > (int) num_states) red = lastats[state_no].reduce; else red = reduce[state_no]; for (j = 1; j <= red.size; j++) { symbol = REDUCE_SYMBOL(red, j); if (reduce_action[symbol] != OMEGA) { if (reduce_action[symbol] != REDUCE_RULE_NO(red, j)) break; } } /*********************************************************************/ /* If J > Q->REDUCE_ELEMENT.N then we traversed the whole reduce map,*/ /* and all the reductions involved are compatible with the new state */ /* being constructed. The state involved is added to the subset, the*/ /* rule counts are updated, and the REDUCE_ACTIONS map is updated. */ /* Otherwise, we add the state involved to the STATE_ROOT list */ /* which will be thrown back in the MULTI_ROOT list. */ /*********************************************************************/ if (j > red.size) { state_list[state_no] = state_subset_root; state_subset_root = state_no; for (j = 1; j <= red.size; j++) { symbol = REDUCE_SYMBOL(red, j); if (reduce_action[symbol] == OMEGA) { rule_no = REDUCE_RULE_NO(red, j); if (rules[rule_no].lhs == accept_image) rule_no = 0; reduce_action[symbol] = rule_no; rule_count[rule_no]++; } else num_reductions_saved++; } } else { state_list[state_no] = state_root; state_root = state_no; } } /*********************************************************************/ /* Figure out the best default rule candidate, and update */ /* DEFAULT_SAVES. */ /* Recall that all accept actions were changed into reduce actions */ /* by rule 0. */ /*********************************************************************/ k = 0; reduce_size = 0; default_rule = error_act; for (q = new_state_element_reduce_nodes[i]; q != NULL; tail = q, q = q -> next) { rule_no = q -> value; reduce_size += rule_count[rule_no]; if ((rule_count[rule_no] > k) && (rule_no != 0) && ! shift_on_error_symbol[state_subset_root]) { k = rule_count[rule_no]; default_rule = rule_no; } } default_saves += k; reduce_size -= k; /*********************************************************************/ /* If STATE_ROOT is not NIL then there are states in the group that */ /* did not meet the compatibility test. Throw those states back in */ /* front of MULTI_ROOT as a group. */ /*********************************************************************/ if (state_root != NIL) { top++; new_state_element[top].thread = new_state_element[i].thread; new_state_element[i].thread = top; if (state_root > (int) num_states) new_state_element[top].shift_number = lastats[state_root].shift_number; else new_state_element[top].shift_number = statset[state_root].shift_number; new_state_element_reduce_nodes[top] = new_state_element_reduce_nodes[i]; new_state_element[top].image = state_root; } else free_nodes(new_state_element_reduce_nodes[i], tail); /*********************************************************************/ /* Create Reduce map for the newly created terminal state. */ /* We may assume that SYMBOL field of defaults is already set to */ /* the DEFAULT_SYMBOL value. */ /*********************************************************************/ new_red = Allocate_reduce_map(reduce_size); REDUCE_SYMBOL(new_red, 0) = DEFAULT_SYMBOL; REDUCE_RULE_NO(new_red, 0) = default_rule; for ALL_TERMINALS(symbol) { if (reduce_action[symbol] != OMEGA) { if (reduce_action[symbol] != default_rule) { REDUCE_SYMBOL(new_red, reduce_size) = symbol; if (reduce_action[symbol] == 0) REDUCE_RULE_NO(new_red, reduce_size) = accept_act; else REDUCE_RULE_NO(new_red, reduce_size) = reduce_action[symbol]; reduce_size--; } } } new_state_element[i].reduce = new_red; new_state_element[i].image = state_subset_root; } /*********************************************************************/ /* We now process groups of states that have reductions to a single */ /* rule. Those states are fully compatible, and the default is the */ /* rule in question. */ /* Any of the REDUCE_ELEMENT maps that belongs to a state in the */ /* group of states being processed may be reused for the new merged */ /* state. */ /*********************************************************************/ for (i = single_root; i != NIL; i = new_state_element[i].thread) { state_no = new_state_element[i].image; q = new_state_element_reduce_nodes[i]; rule_no = q -> value; free_nodes(q, q); if (rules[rule_no].lhs == accept_image) { red = reduce[state_no]; reduce_size = red.size; new_red = Allocate_reduce_map(reduce_size); REDUCE_SYMBOL(new_red, 0) = DEFAULT_SYMBOL; REDUCE_RULE_NO(new_red, 0) = error_act; for (j = 1; j <= reduce_size; j++) { REDUCE_SYMBOL(new_red, j) = REDUCE_SYMBOL(red, j); REDUCE_RULE_NO(new_red, j) = accept_act; } } else { for ALL_TERMINALS(j) reduce_action[j] = OMEGA; for (; state_no != NIL; state_no = state_list[state_no]) { if (state_no > (int) num_states) red = lastats[state_no].reduce; else red = reduce[state_no]; for (j = 1; j <= red.size; j++) { symbol = REDUCE_SYMBOL(red, j); if (reduce_action[symbol] == OMEGA) { reduce_action[symbol] = rule_no; default_saves++; } else num_reductions_saved++; } } new_red = Allocate_reduce_map(0); REDUCE_SYMBOL(new_red, 0) = DEFAULT_SYMBOL; REDUCE_RULE_NO(new_red, 0) = rule_no; } new_state_element[i].reduce = new_red; } /*********************************************************************/ /* Groups of states that have no reductions are also compatible. */ /* Their default is ERROR_ACTION. */ /*********************************************************************/ for (i = empty_root; i != NIL; i = new_state_element[i].thread) { state_no = new_state_element[i].image; if (state_no > (int) num_states) red = lastats[state_no].reduce; else red = reduce[state_no]; REDUCE_SYMBOL(red, 0) = DEFAULT_SYMBOL; REDUCE_RULE_NO(red, 0) = error_act; new_state_element[i].reduce = red; } num_terminal_states = top; frequency_symbol = Allocate_short_array(num_terminals + 1); frequency_count = Allocate_short_array(num_terminals + 1); row_size = Allocate_short_array(max_la_state + 1); if (shift_default_bit) merge_shift_domains(); /*********************************************************************/ /* We now reorder the terminal states based on the number of actions */ /* in them, and remap the terminal symbols if they were not already */ /* remapped in the previous block for the SHIFT_CHECK vector. */ /*********************************************************************/ for ALL_TERMINALS(symbol) { frequency_symbol[symbol] = symbol; frequency_count[symbol] = 0; } for (i = 1; i <= num_terminal_states; i++) { ordered_state[i] = i; row_size[i] = 0; sh = shift[new_state_element[i].shift_number]; for (j = 1; j <= sh.size; j++) { symbol = SHIFT_SYMBOL(sh, j); if ((! shift_default_bit) || (SHIFT_ACTION(sh, j) != shiftdf[symbol])) { row_size[i]++; frequency_count[symbol]++; } } for (state_no = state_list[new_state_element[i].image]; state_no != NIL; state_no = state_list[state_no]) { num_shifts_saved += row_size[i]; } /***********************************************/ /* Note that the Default action is skipped !!! */ /***********************************************/ red = new_state_element[i].reduce; for (j = 1; j <= red.size; j++) { symbol = REDUCE_SYMBOL(red, j); row_size[i]++; frequency_count[symbol]++; } } sprintf(msg_line, "Number of unique terminal states: %d", num_terminal_states); PRNT(msg_line); sprintf(msg_line, "Number of Shift actions saved by merging: %d", num_shifts_saved); PRNT(msg_line); sprintf(msg_line, "Number of Reduce actions saved by merging: %d", num_reductions_saved); PRNT(msg_line); sprintf(msg_line, "Number of Reduce saved by default: %d", default_saves); PRNT(msg_line); sortdes(ordered_state, row_size, 1, num_terminal_states, num_terminals); if (! shift_default_bit) { sortdes(frequency_symbol, frequency_count, 1, num_terminals, num_terminal_states); for ALL_TERMINALS(symbol) symbol_map[frequency_symbol[symbol]] = symbol; symbol_map[DEFAULT_SYMBOL] = DEFAULT_SYMBOL; eoft_image = symbol_map[eoft_image]; if (error_maps_bit) { error_image = symbol_map[error_image]; eolt_image = symbol_map[eolt_image]; } for (i = 1; i <= num_shift_maps; i++) { sh = shift[i]; for (j = 1; j <= sh.size; j++) SHIFT_SYMBOL(sh, j) = symbol_map[SHIFT_SYMBOL(sh, j)]; } for (state_no = 1; state_no <= num_terminal_states; state_no++) { red = new_state_element[state_no].reduce; for (i = 1; i <= red.size; i++) REDUCE_SYMBOL(red, i) = symbol_map[REDUCE_SYMBOL(red, i)]; } /*********************************************************************/ /* If ERROR_MAPS are requested, we also have to remap the original */ /* REDUCE maps. */ /*********************************************************************/ if (error_maps_bit) { for ALL_STATES(state_no) { red = reduce[state_no]; for (i = 1; i <= red.size; i++) REDUCE_SYMBOL(red, i) = symbol_map[REDUCE_SYMBOL(red, i)]; } } } num_table_entries = num_shifts + num_shift_reduces + num_reductions - num_shifts_saved - num_reductions_saved - default_saves + num_terminal_states; ffree(rule_count); ffree(reduce_action); ffree(row_size); ffree(frequency_count); ffree(frequency_symbol); ffree(shift_on_error_symbol); ffree(new_state_element_reduce_nodes); return; } /*********************************************************************/ /* OVERLAP_T_ROWS: */ /*********************************************************************/ /* We now compute the starting position for each terminal state just */ /* as we did for the non-terminal states. */ /* The starting positions are stored in the vector TERM_STATE_INDEX. */ /*********************************************************************/ static void overlap_t_rows(void) { struct shift_header_type sh; struct reduce_header_type red; short *terminal_list; int root_symbol, symbol, i, k, k_bytes, percentage, state_no, old_size, max_indx, indx; long num_bytes; terminal_list = Allocate_short_array(num_terminals + 1); term_state_index = Allocate_int_array(max_la_state + 1); increment_size = MAX((num_table_entries * increment / 100), (num_terminals + 1)); old_size = table_size; table_size = MIN((num_table_entries + increment_size), MAX_TABLE_SIZE); if ((int) table_size > old_size) { ffree(previous); ffree(next); next = Allocate_int_array(table_size + 1); previous = Allocate_int_array(table_size + 1); } else table_size = old_size; first_index = 1; previous[first_index] = NIL; next[first_index] = first_index + 1; for (indx = 2; indx < (int) table_size; indx++) { next[indx] = indx + 1; previous[indx] = indx - 1; } last_index = table_size; previous[last_index] = last_index - 1; next[last_index] = NIL; max_indx = first_index; for (k = 1; k <= num_terminal_states; k++) { state_no = ordered_state[k]; /*********************************************************************/ /* For the terminal table, we are dealing with two lists, the SHIFT */ /* list, and the REDUCE list. Those lists are merged together first */ /* in TERMINAL_LIST. Since we have to iterate over the list twice, */ /* this merging makes things easy. */ /*********************************************************************/ root_symbol = NIL; sh = shift[new_state_element[state_no].shift_number]; for (i = 1; i <= sh.size; i++) { symbol = SHIFT_SYMBOL(sh, i); if (! shift_default_bit || (SHIFT_ACTION(sh, i) != shiftdf[symbol])) { terminal_list[symbol] = root_symbol; root_symbol = symbol; } } red = new_state_element[state_no].reduce; for (i = 1; i <= red.size; i++) { terminal_list[REDUCE_SYMBOL(red, i)] = root_symbol; root_symbol = REDUCE_SYMBOL(red, i); } /*********************************************************************/ /* Look for a suitable index where to overlay the state. */ /*********************************************************************/ indx = first_index; look_for_match_in_term_table: if (indx == NIL) indx = table_size + 1; if (indx + num_terminals > (int) table_size) reallocate(); for (symbol = root_symbol; symbol != NIL; symbol = terminal_list[symbol]) { if (next[indx + symbol] == OMEGA) { indx = next[indx]; goto look_for_match_in_term_table; } } /*********************************************************************/ /* INDX marks the starting position for the state, remove all the */ /* positions that are claimed by terminal actions in the state. */ /*********************************************************************/ for (symbol = root_symbol; symbol != NIL; symbol = terminal_list[symbol]) { i = indx + symbol; if (i == last_index) { last_index = previous[last_index]; next[last_index] = NIL; } else { next[previous[i]] = next[i]; previous[next[i]] = previous[i]; } next[i] = OMEGA; } /*********************************************************************/ /* We now remove the starting position itself from the list, and */ /* mark it as taken(CHECK(INDX) = OMEGA) */ /* MAX_INDX is updated if required. */ /* TERM_STATE_INDEX(STATE_NO) is properly set to INDX as the starting*/ /* position of STATE_NO. */ /*********************************************************************/ if (first_index == last_index) first_index = NIL; else if (indx == first_index) { first_index = next[first_index]; previous[first_index] = NIL; } else if (indx == last_index) { last_index = previous[last_index]; next[last_index] = NIL; } else { next[previous[indx]] = next[indx]; previous[next[indx]] = previous[indx]; } next[indx] = OMEGA; if (indx > max_indx) max_indx = indx; term_state_index[state_no] = indx; } /*********************************************************************/ /* Update all counts, and report statistics. */ /*********************************************************************/ term_check_size = max_indx + num_terminals; for (term_action_size = max_indx + num_terminals; term_action_size >= max_indx; term_action_size--) if (next[term_action_size] == OMEGA) break; printf("\n"); sprintf(msg_line, "Length of Terminal Check Table: %d", term_check_size); PRNT(msg_line); sprintf(msg_line, "Length of Terminal Action Table: %d", term_action_size); PRNT(msg_line); sprintf(msg_line, "Number of entries in Terminal Action Table: %d", num_table_entries); PRNT(msg_line); percentage = (((long)term_action_size - num_table_entries) * 1000) / num_table_entries; sprintf(msg_line, "Percentage of increase: %d.%d%%", (percentage / 10), (percentage % 10)); PRNT(msg_line); if (byte_bit) { num_bytes = 2 * term_action_size + term_check_size; if (num_terminals > 255) num_bytes += term_check_size; } else num_bytes = 2 * (term_action_size + term_check_size); if (shift_default_bit) num_bytes += (2 * num_terminal_states); k_bytes = (num_bytes / 1024) + 1; sprintf(msg_line, "Storage required for Terminal Tables: %ld Bytes, %dK", num_bytes, k_bytes); PRNT(msg_line); total_bytes += num_bytes; /*********************************************************************/ /* Report total number of storage used. */ /*********************************************************************/ k_bytes = (total_bytes / 1024) + 1; sprintf(msg_line, "Total storage required for Tables: %ld Bytes, %dK", total_bytes, k_bytes); PRNT(msg_line); /*********************************************************************/ /* We now write out the tables to the SYSTAB file. */ /*********************************************************************/ table_size = MAX(check_size, term_check_size); table_size = MAX(table_size, shift_check_size); table_size = MAX(table_size, action_size); table_size = MAX(table_size, term_action_size); ffree(terminal_list); ffree(next); ffree(previous); } /*********************************************************************/ /* PRINT_TABLES: */ /*********************************************************************/ /* We now write out the tables to the SYSTAB file. */ /*********************************************************************/ static void print_tables(void) { int *check, *action; int la_state_offset, i, j, k, indx, act, result_act, default_count = 0, goto_count = 0, goto_reduce_count = 0, reduce_count = 0, la_shift_count = 0, shift_count = 0, shift_reduce_count = 0, rule_no, symbol, state_no; char *tok; long offset; check = Allocate_int_array(table_size + 1); action = Allocate_int_array(table_size + 1); /******************************************************************/ /* Prepare header card with proper information, and write it out. */ /******************************************************************/ offset = error_act; if (read_reduce_bit) offset += num_rules; la_state_offset = offset; if (offset > (MAX_TABLE_SIZE + 1)) { sprintf(msg_line, "Table contains entries that are > " "%d; Processing stopped.", MAX_TABLE_SIZE + 1); PRNTERR(msg_line); exit(12); } output_buffer[0] = 'S'; output_buffer[1] = (goto_default_bit ? '1' : '0'); output_buffer[2] = (nt_check_bit ? '1' : '0'); output_buffer[3] = (read_reduce_bit ? '1' : '0'); output_buffer[4] = (single_productions_bit ? '1' : '0'); output_buffer[5] = (shift_default_bit ? '1' : '0'); output_buffer[6] = (rules[1].lhs == accept_image ? '1' : '0'); /* are there more than 1 start symbols? */ output_buffer[7] = (error_maps_bit ? '1' : '0'); output_buffer[8] = (byte_bit && last_symbol <= 255 ? '1' : '0'); output_buffer[9] = escape; output_ptr = output_buffer + 10; field(num_terminals, 5); field(num_non_terminals, 5); field(num_rules, 5); field(num_states, 5); field(check_size, 5); field(action_size, 5); field(term_check_size, 5); field(term_action_size, 5); field(state_index[1] + num_rules, 5); field(eoft_image, 5); field(accept_act, 5); field(error_act, 5); field(la_state_offset, 5); field(lalr_level, 5); *output_ptr++ = '\n'; /*********************************************************/ /* We write the terminal symbols map. */ /*********************************************************/ for ALL_TERMINALS(symbol) { int len; tok = RETRIEVE_STRING(symbol); if (tok[0] == '\n') /* we're dealing with special symbol? */ tok[0] = escape; /* replace initial marker with escape. */ len = strlen(tok); field(symbol_map[symbol], 4); field(len, 4); if (len <= 64) strcpy(output_ptr, tok); else { memcpy(output_ptr, tok, 64); output_ptr += 64; *output_ptr++ = '\n'; BUFFER_CHECK(systab); tok += 64; for (len = strlen(tok); len > 72; len = strlen(tok)) { memcpy(output_ptr, tok, 72); output_ptr += 72; *output_ptr++ = '\n'; BUFFER_CHECK(systab); tok += 72; } memcpy(output_ptr, tok, len); } output_ptr += len; *output_ptr++ = '\n'; BUFFER_CHECK(systab); } /*********************************************************/ /* We write the non-terminal symbols map. */ /*********************************************************/ for ALL_NON_TERMINALS(symbol) { int len; tok = RETRIEVE_STRING(symbol); if (tok[0] == '\n') /* we're dealing with special symbol? */ tok[0] = escape; /* replace initial marker with escape. */ len = strlen(tok); field(symbol_map[symbol]-num_terminals, 4); field(len, 4); if (len <= 64) strcpy(output_ptr, tok); else { memcpy(output_ptr, tok, 64); output_ptr += 64; *output_ptr++ = '\n'; BUFFER_CHECK(systab); tok += 64; for (len = strlen(tok); len > 72; len = strlen(tok)) { memcpy(output_ptr, tok, 72); output_ptr += 72; *output_ptr++ = '\n'; BUFFER_CHECK(systab); tok += 72; } memcpy(output_ptr, tok, len); } output_ptr += len; *output_ptr++ = '\n'; BUFFER_CHECK(systab); } /*********************************************************/ /* Initialize TABLES with default actions. */ /*********************************************************/ for (i = 1; i <= check_size; i++) check[i] = DEFAULT_SYMBOL; for (i = 1; i <= (int) action_size; i++) action[i] = error_act; /********************************************************************/ /* Update the default non-terminal action of each state with the */ /* appropriate corresponding terminal state starting index. */ /********************************************************************/ for (i = 1; i <= num_terminal_states; i++) { indx = term_state_index[i]; state_no = new_state_element[i].image; /*********************************************************************/ /* Update the action link between the non-terminal and terminal */ /* tables. If error-maps are requested, an indirect linking is made */ /* as follows: */ /* Each non-terminal row identifies its original state number, and */ /* a new vector START_TERMINAL_STATE indexable by state numbers */ /* identifies the starting point of each state in the terminal table.*/ /*********************************************************************/ if (state_no <= (int) num_states) { for (; state_no != NIL; state_no = state_list[state_no]) { action[state_index[state_no]] = indx; } } else { for (; state_no != NIL; state_no = state_list[state_no]) { act = la_state_offset + indx; state_index[state_no] = act; } } } /*********************************************************************/ /* Now update the non-terminal tables with the non-terminal actions.*/ /*********************************************************************/ for ALL_STATES(state_no) { struct goto_header_type go_to; indx = state_index[state_no]; go_to = statset[state_no].go_to; for (j = 1; j <= go_to.size; j++) { symbol = GOTO_SYMBOL(go_to, j); i = indx + symbol; if (goto_default_bit || nt_check_bit) check[i] = symbol; act = GOTO_ACTION(go_to, j); if (act > 0) { action[i] = state_index[act] + num_rules; goto_count++; } else { action[i] = -act; goto_reduce_count++; } } } /*********************************************************************/ /* Write size of right hand side of rules followed by CHECK table. */ /*********************************************************************/ k = 0; for (i = 1; i <= num_rules; i++) { field(RHS_SIZE(i), 4); k++; if (k == 18) { *output_ptr++ = '\n'; BUFFER_CHECK(systab); k = 0; } } for (i = 1; i <= check_size; i++) { field(check[i], 4); k++; if (k == 18) { *output_ptr++ = '\n'; BUFFER_CHECK(systab); k = 0; } } if (k != 0) { *output_ptr++ = '\n'; BUFFER_CHECK(systab); } /*********************************************************************/ /* Write left hand side symbol of rules followed by ACTION table. */ /*********************************************************************/ k = 0; for (i = 1; i <= num_rules; i++) { field(symbol_map[rules[i].lhs] - num_terminals, 6); k++; if (k == 12) { *output_ptr++ = '\n'; BUFFER_CHECK(systab); k = 0; } } for (i = 1; i <= (int) action_size; i++) { field(action[i], 6); k++; if (k == 12) { *output_ptr++ = '\n'; BUFFER_CHECK(systab); k = 0; } } if (k != 0) { *output_ptr++ = '\n'; BUFFER_CHECK(systab); } /********************************************************************/ /* Initialize the terminal tables,and update with terminal actions. */ /********************************************************************/ for (i = 1; i <= term_check_size; i++) check[i] = DEFAULT_SYMBOL; for (i = 1; i <= term_action_size; i++) action[i] = error_act; for (state_no = 1; state_no <= num_terminal_states; state_no++) { struct shift_header_type sh; struct reduce_header_type red; indx = term_state_index[state_no]; sh = shift[new_state_element[state_no].shift_number]; for (j = 1; j <= sh.size; j++) { symbol = SHIFT_SYMBOL(sh, j); act = SHIFT_ACTION(sh, j); if ((! shift_default_bit) || (act != shiftdf[symbol])) { i = indx + symbol; check[i] = symbol; if (act > (int) num_states) { result_act = state_index[act]; la_shift_count++; } else if (act > 0) { result_act = state_index[act] + num_rules; shift_count++; } else { result_act = -act + error_act; shift_reduce_count++; } if (result_act > (MAX_TABLE_SIZE + 1)) { sprintf(msg_line, "Table contains look-ahead shift entry that is >" " %d; Processing stopped.", MAX_TABLE_SIZE + 1); PRNTERR(msg_line); return; } action[i] = result_act; } } red = new_state_element[state_no].reduce; for (j = 1; j <= red.size; j++) { symbol = REDUCE_SYMBOL(red, j); rule_no = REDUCE_RULE_NO(red, j); i = indx + symbol; check[i] = symbol; action[i] = rule_no; reduce_count++; } rule_no = REDUCE_RULE_NO(red, 0); if (rule_no != error_act) default_count++; check[indx] = DEFAULT_SYMBOL; if (shift_default_bit) action[indx] = state_no; else action[indx] = rule_no; } PRNT("\n\nActions in Compressed Tables:"); sprintf(msg_line," Number of Shifts: %d",shift_count); PRNT(msg_line); sprintf(msg_line," Number of Shift/Reduces: %d",shift_reduce_count); PRNT(msg_line); if (max_la_state > num_states) { sprintf(msg_line, " Number of Look-Ahead Shifts: %d", la_shift_count); PRNT(msg_line); } sprintf(msg_line," Number of Gotos: %d",goto_count); PRNT(msg_line); sprintf(msg_line," Number of Goto/Reduces: %d",goto_reduce_count); PRNT(msg_line); sprintf(msg_line," Number of Reduces: %d",reduce_count); PRNT(msg_line); sprintf(msg_line," Number of Defaults: %d",default_count); PRNT(msg_line); /********************************************************************/ /* Write Terminal Check Table. */ /********************************************************************/ k = 0; for (i = 1; i <= term_check_size; i++) { field(check[i], 4); k++; if (k == 18) { *output_ptr++ = '\n'; BUFFER_CHECK(systab); k = 0; } } if (k != 0) { *output_ptr++ = '\n'; BUFFER_CHECK(systab); } /********************************************************************/ /* Write Terminal Action Table. */ /********************************************************************/ k = 0; for (i = 1; i <= term_action_size; i++) { field(action[i], 6); k++; if (k == 12) { *output_ptr++ = '\n'; BUFFER_CHECK(systab); k = 0; } } if (k != 0) { *output_ptr++ = '\n'; BUFFER_CHECK(systab); } /********************************************************************/ /* If GOTO_DEFAULT is requested, we print out the GOTODEF vector. */ /********************************************************************/ if (goto_default_bit) { k = 0; for ALL_NON_TERMINALS(symbol) { act = gotodef[symbol]; if (act < 0) result_act = -act; else if (act == 0) result_act = error_act; else result_act = state_index[act] + num_rules; field(result_act, 6); k++; if (k == 12) { *output_ptr++ = '\n'; BUFFER_CHECK(systab); k = 0; } } if (k != 0) { *output_ptr++ = '\n'; BUFFER_CHECK(systab); } } /*********************************************************************/ /* If SHIFT_DEFAULT is requested, we print out the Default Reduce */ /* map, the Shift State map, the Shift Check vector, and the SHIFTDF */ /* vector. */ /*********************************************************************/ if (shift_default_bit) { /* Print out header */ field(num_terminal_states, 5); field(shift_check_size, 5); *output_ptr++ = '\n'; k = 0; for (state_no = 1; state_no <= num_terminal_states; state_no++) { struct reduce_header_type red; red = new_state_element[state_no].reduce; field(REDUCE_RULE_NO(red, 0), 4); k++; if (k == 18) { *output_ptr++ = '\n'; BUFFER_CHECK(systab); k = 0; } } if (k != 0) { *output_ptr++ = '\n'; BUFFER_CHECK(systab); } /*************************************************************/ /* First, check whether or not maximum value in SHIFT_STATE */ /* table exceeds 9999. If so, stop. Otherwise, write out */ /* SHIFT_STATE table. */ /*************************************************************/ if ((shift_check_size - num_terminals) > 9999) { PRNTERR("SHIFT_STATE map contains > 9999 elements"); return; } k = 0; for (state_no = 1; state_no <= num_terminal_states; state_no++) { field(shift_check_index[shift_image[state_no]], 4); k++; if (k == 18) { *output_ptr++ = '\n'; BUFFER_CHECK(systab); k = 0; } } if (k != 0) { *output_ptr++ = '\n'; BUFFER_CHECK(systab); } /*********************************************************************/ /* Set the Check vector with the symbols in the domain of the shift */ /* maps. */ /*********************************************************************/ for (i = 1; i <= shift_check_size; i++) check[i] = DEFAULT_SYMBOL; for (i = 1; i <= shift_domain_count; i++) { struct shift_header_type sh; indx = shift_check_index[i]; sh = shift[real_shift_number[i]]; for (j = 1; j <= sh.size; j++) { symbol = SHIFT_SYMBOL(sh, j); check[indx + symbol] = symbol; } } k = 0; for (i = 1; i <= shift_check_size; i++) { field(check[i], 4); k++; if (k == 18) { *output_ptr++ = '\n'; BUFFER_CHECK(systab); k = 0; } } if (k != 0) { *output_ptr++ = '\n'; BUFFER_CHECK(systab); } k = 0; for ALL_TERMINALS(symbol) { act = shiftdf[symbol]; if (act < 0) result_act = -act + error_act; else if (act == 0) result_act = error_act; else if (act > (int) num_states) result_act = state_index[act]; else result_act = state_index[act] + num_rules; if (result_act > (MAX_TABLE_SIZE + 1)) { sprintf(msg_line, "Table contains look-ahead shift entry that is >" " %d; Processing stopped.", MAX_TABLE_SIZE + 1); PRNTERR(msg_line); return; } field(result_act, 6); k++; if (k == 12) { *output_ptr++ = '\n'; BUFFER_CHECK(systab); k = 0; } } if (k != 0) { *output_ptr++ = '\n'; BUFFER_CHECK(systab); } } /*********************************************************************/ /* We first sort the new state numbers. A bucket sort technique */ /* is used using the ACTION vector as a base to simulate the */ /* buckets. NOTE: the iteration over the buckets is done backward */ /* because we also construct a list of the original state numbers */ /* that reflects the permutation of the new state numbers. */ /* During the backward iteration, we construct the list as a stack. */ /*********************************************************************/ if (error_maps_bit || states_bit) { int max_indx; max_indx = accept_act - num_rules - 1; for (i = 1; i <= max_indx; i++) action[i] = OMEGA; for ALL_STATES(state_no) action[state_index[state_no]] = state_no; j = num_states + 1; for (i = max_indx; i >= 1; i--) { state_no = action[i]; if (state_no != OMEGA) { j--; ordered_state[j] = i + num_rules; state_list[j] = state_no; } } } ffree(check); ffree(action); if (error_maps_bit) process_error_maps(); fwrite(output_buffer, sizeof(char), output_ptr - &output_buffer[0], systab); return; } /*********************************************************************/ /* CMPRSPA: */ /*********************************************************************/ void cmprspa(void) { state_index = Allocate_int_array(max_la_state + 1); ordered_state = Allocate_short_array(max_la_state + 1); symbol_map = Allocate_short_array(num_symbols + 1); state_list = Allocate_short_array(max_la_state + 1); shift_on_error_symbol = Allocate_boolean_array(max_la_state + 1); new_state_element = (struct new_state_type *) calloc(max_la_state + 1, sizeof(struct new_state_type)); if (new_state_element == NULL) nospace(__FILE__, __LINE__); new_state_element_reduce_nodes = (struct node **) calloc(max_la_state + 1, sizeof(struct node *)); if (new_state_element_reduce_nodes == NULL) nospace(__FILE__, __LINE__); remap_non_terminals(); overlap_nt_rows(); merge_similar_t_rows(); overlay_sim_t_rows(); overlap_t_rows(); if (c_bit || cpp_bit || java_bit) print_space_parser(); else print_tables(); return; } jikespg-1.3/src/tabutil.c000066400000000000000000001415621167345774400154430ustar00rootroot00000000000000/* $Id: tabutil.c,v 1.2 1999/11/04 14:02:23 shields Exp $ */ /* This software is subject to the terms of the IBM Jikes Compiler License Agreement available at the following URL: http://www.ibm.com/research/jikes. Copyright (C) 1983, 1999, International Business Machines Corporation and others. All Rights Reserved. You must accept the terms of that agreement to use this software. */ static char hostfile[] = __FILE__; #include #include "common.h" #include "header.h" static const char digits[] = "0123456789"; /**************************************************************************/ /* PRNT_SHORTS: */ /**************************************************************************/ void prnt_shorts(char *title, int init, int bound, int perline, short *array) { int i, k; mystrcpy(title); padline(); k = 0; for (i = init; i <= bound; i++) { itoc(array[i]); *output_ptr++ = COMMA; k++; if (k == perline && i != bound) { *output_ptr++ = '\n'; BUFFER_CHECK(sysdcl); padline(); k = 0; } } if (k != 0) { *(output_ptr - 1) = '\n'; BUFFER_CHECK(sysdcl); } if (java_bit) mystrcpy(" };\n"); else mystrcpy(" };\n"); return; } /**************************************************************************/ /* PRNT_INTS: */ /**************************************************************************/ void prnt_ints(char *title, int init, int bound, int perline, int *array) { int i, k; mystrcpy(title); padline(); k = 0; for (i = init; i <= bound; i++) { itoc(array[i]); *output_ptr++ = COMMA; k++; if (k == perline && i != bound) { *output_ptr++ = '\n'; BUFFER_CHECK(sysdcl); padline(); k = 0; } } if (k != 0) { *(output_ptr - 1) = '\n'; BUFFER_CHECK(sysdcl); } if (java_bit) mystrcpy(" };\n"); else mystrcpy(" };\n"); return; } /***************************************************************************/ /* MYSTRCPY: */ /***************************************************************************/ void mystrcpy(char *str) { while (*str != '\0') *output_ptr++ = *str++; BUFFER_CHECK(sysdcl); return; } /***************************************************************************/ /* PADLINE: */ /***************************************************************************/ void padline(void) { register int i; for (i = 0; i < 12; i++) *output_ptr++ = ' '; return; } /***************************************************************************/ /* ITOC: */ /***************************************************************************/ /* ITOC takes as arguments an integer NUM. NUM is an integer containing at */ /* most 11 digits which is converted into a character string and placed in */ /* the iobuffer. Leading zeros are eliminated and if the number is */ /* negative, a leading "-" is added. */ /***************************************************************************/ void itoc(int num) { register int val; register char *p; char tmp[12]; val = ABS(num); tmp[11] = '\0'; p = &tmp[11]; do { p--; *p = digits[val % 10]; val /= 10; } while(val > 0); if (num < 0) { p--; *p = '-'; } while(*p != '\0') *(output_ptr++) = *(p++); return; } /***************************************************************************/ /* FIELD: */ /***************************************************************************/ /* FIELD takes as arguments two integers: NUM and LEN. NUM is an integer */ /* containing at most LEN digits which is converted into a character */ /* string and placed in the iobuffer. */ /* Leading zeros are replaced by blanks and if the number is negative, a */ /* leading "-" is added. */ /***************************************************************************/ void field(int num, int len) { register int val; register char *p; val = ABS(num); p = output_ptr + len; do { p--; *p = digits[val % 10]; val /= 10; } while(val > 0 && p > output_ptr); if (num < 0 && p > output_ptr) { p--; *p = '-'; } while(p > output_ptr) { p--; *p = ' '; } output_ptr += len; return; } /***************************************************************************/ /* SORTDES: */ /***************************************************************************/ /* SORTDES sorts the elements of ARRAY and COUNT in the range LOW..HIGH */ /* based on the values of the elements of COUNT. Knowing that the maximum */ /* value of the elements of count cannot exceed MAX and cannot be lower */ /* than zero, we can use a bucket sort technique. */ /***************************************************************************/ void sortdes(short array[], short count[], int low, int high, int max) { short *bucket, *list; register int element, i, k; /*****************************************************************/ /* BUCKET is used to hold the roots of lists that contain the */ /* elements of each bucket. LIST is used to hold these lists. */ /*****************************************************************/ bucket = Allocate_short_array(max + 1); list = Allocate_short_array(high - low + 1); for (i = 0; i <= max; i++) bucket[i] = NIL; /*********************************************************************/ /* We now partition the elements to be sorted and place them in their*/ /* respective buckets. We iterate backward over ARRAY and COUNT to */ /* keep the sorting stable since elements are inserted in the buckets*/ /* in stack-fashion. */ /* */ /* NOTE that it is known that the values of the elements of ARRAY */ /* also lie in the range LOW..HIGH. */ /*********************************************************************/ for (i = high; i >= low; i--) { k = count[i]; element = array[i]; list[element - low] = bucket[k]; bucket[k] = element; } /*********************************************************************/ /* Iterate over each bucket, and place elements in ARRAY and COUNT */ /* in sorted order. The iteration is done backward because we want */ /* the arrays sorted in descending order. */ /*********************************************************************/ k = low; for (i = max; i >= 0; i--) { for (element = bucket[i]; element != NIL; element = list[element - low], k++) { array[k] = element; count[k] = i; } } ffree(bucket); ffree(list); return; } /***************************************************************************/ /* REALLOCATE: */ /***************************************************************************/ /* This procedure is invoked when the TABLE being used is not large */ /* enough. A new table is allocated, the information from the old table */ /* is copied, and the old space is released. */ /***************************************************************************/ void reallocate(void) { int *n, *p; register int old_size, i; if (table_size == MAX_TABLE_SIZE) { sprintf(msg_line, "Table has exceeded maximum limit of %d", MAX_TABLE_SIZE); PRNTERR(msg_line); exit(12); } old_size = table_size; table_size = MIN(table_size + increment_size, MAX_TABLE_SIZE); if (verbose_bit) { if (table_opt == OPTIMIZE_TIME) { sprintf(msg_line, "Reallocating storage for TIME table, " "adding %d entries", table_size - old_size); } else { sprintf(msg_line, "Reallocating storage for SPACE table, " "adding %d entries", table_size - old_size); } PRNT(msg_line); } n = Allocate_int_array(table_size + 1); p = Allocate_int_array(table_size + 1); for (i = 1; i <= old_size; i++) /* Copy old information */ { n[i] = next[i]; p[i] = previous[i]; } ffree(next); ffree(previous); next = n; previous = p; if (first_index == NIL) { first_index = old_size + 1; previous[first_index] = NIL; } else { next[last_index] = old_size + 1; previous[old_size + 1] = last_index; } next[old_size + 1] = old_size + 2; for (i = old_size + 2; i < (int) table_size; i++) { next[i] = i + 1; previous[i] = i - 1; } last_index = table_size; next[last_index] = NIL; previous[last_index] = last_index - 1; return; } /*****************************************************************************/ /* PROCESS_ERROR_MAPS: */ /*****************************************************************************/ /* if ERROR_MAPS are requested, we print them out in the following order: */ /* */ /* 1) The FOLLOW map (NEWFOLL) */ /* 2) The SORTED_STATE vector */ /* 3) The ORIGINAL_STATE vector */ /* 4) The map from states into valid symbols on which actions are */ /* defined within the state in question: ACTION_SYMBOLS */ /* 5) The map from each symbol into the set of staes that can */ /* possibly be reached after a transition on the symbol in */ /* question: TRANSITION_STATES */ /* */ /*****************************************************************************/ void process_error_maps(void) { short *state_start, *state_stack, *temp, *original = NULL, *symbol_root, *symbol_count, *term_list, *as_size, *action_symbols_range, *naction_symbols_range; int offset, item_no, lhs_symbol, state_no, symbol, max_len, i, k, terminal_ubound, non_terminal_ubound; long num_bytes; char tok[SYMBOL_SIZE + 1]; terminal_ubound = (table_opt == OPTIMIZE_TIME ? num_symbols : num_terminals); non_terminal_ubound = (table_opt == OPTIMIZE_TIME ? num_symbols : num_non_terminals); symbol_root = Allocate_short_array(num_symbols + 1); symbol_count = Allocate_short_array(num_symbols + 1); state_start = Allocate_short_array(num_states + 2); state_stack = Allocate_short_array(num_states + 1); term_list = Allocate_short_array(num_symbols + 1); PRNT("\nError maps storage:"); /*********************************************************************/ /* The FOLLOW map is written out as two vectors where the first */ /* vector indexed by a Symbol gives the starting location in the */ /* second vector where the elements of the follow set of that symbol */ /* starts. Note that since the terminal and non-terminal symbols */ /* have been intermixed, the FOLLOW map is written out with the */ /* complete set of symbols as its domain even though it is only */ /* defined on non-terminals. */ /* */ /* We now compute and write the starting location for each symbol. */ /* The offset for the first symbol is 1, and hence does not */ /* have to be computed. However, we compute an extra offset to */ /* indicate the extent of the last symbol. */ /*********************************************************************/ for (symbol = 1; symbol <= non_terminal_ubound; symbol++) { symbol_count[symbol] = 0; symbol_root[symbol] = OMEGA; } for ALL_NON_TERMINALS(lhs_symbol) { if (table_opt == OPTIMIZE_TIME) symbol = symbol_map[lhs_symbol]; else symbol = symbol_map[lhs_symbol] - num_terminals; symbol_root[symbol] = lhs_symbol; for ALL_TERMINALS(i) { if IS_IN_SET(follow, (lhs_symbol + 1), (i + 1)) symbol_count[symbol]++; } } offset = 1; k = 1; field(offset, 6); /* Offset of the first state */ for (symbol = 1; symbol <= non_terminal_ubound; symbol++) { offset += symbol_count[symbol]; field(offset, 6); k++; if (k == 12) { *output_ptr++ = '\n'; BUFFER_CHECK(systab); k = 0; } } if (k != 0) { *output_ptr++ = '\n'; BUFFER_CHECK(systab); } /***************************************************************/ /* We now write the elements in the range of the FOLLOW map. */ /***************************************************************/ k = 0; for (symbol = 1; symbol <= non_terminal_ubound; symbol++) { lhs_symbol = symbol_root[symbol]; if (lhs_symbol != OMEGA) { for ALL_TERMINALS(i) { if IS_IN_SET(follow, (lhs_symbol + 1), (i + 1)) { field(symbol_map[i], 4); k++; if (k == 18) { *output_ptr++ = '\n'; BUFFER_CHECK(systab); k = 0; } } } } } if (k != 0) { *output_ptr++ = '\n'; BUFFER_CHECK(systab); } /*****************************************************************/ /* Compute and list amount of space required for the Follow map. */ /*****************************************************************/ if (table_opt == OPTIMIZE_TIME) { num_bytes = 2 * (num_symbols + offset); if (byte_bit) { if (last_non_terminal <= 255) num_bytes = num_bytes - offset + 1; } } else { num_bytes = 2 * (num_non_terminals + offset); if (byte_bit) { if (num_terminals <= 255) num_bytes = num_bytes - offset + 1; } } sprintf(msg_line, " Storage required for FOLLOW map: %d Bytes", num_bytes); PRNT(msg_line); /**************************************************************/ /* We now write out the states in sorted order: SORTED_STATE. */ /**************************************************************/ k = 0; for ALL_STATES(i) { field(ordered_state[i], 6); k++; if (k == 12) { *output_ptr++ = '\n'; BUFFER_CHECK(systab); k = 0; } } if (k != 0) { *output_ptr++ = '\n'; BUFFER_CHECK(systab); } /*****************************************************************/ /* Compute and list space required for SORTED_STATE map. */ /*****************************************************************/ num_bytes = 2 * num_states; sprintf(msg_line, " Storage required for SORTED_STATE map: %d Bytes", num_bytes); PRNT(msg_line); /********************************************************************/ /* We now write a vector parallel to SORTED_STATE that gives us the */ /* original number associated with the state: ORIGINAL_STATE. */ /********************************************************************/ k = 0; for (i = 1; i <= (int) num_states; i++) { field(state_list[i], 6); k++; if (k == 12) { *output_ptr++ = '\n'; BUFFER_CHECK(systab); k = 0; } } if (k != 0) { *output_ptr++ = '\n'; BUFFER_CHECK(systab); } /*****************************************************************/ /* Compute and list space required for ORIGINAL_STATE map. */ /*****************************************************************/ num_bytes = 2 * num_states; sprintf(msg_line, " Storage required for ORIGINAL_STATE map: %d Bytes", num_bytes); PRNT(msg_line); /********************************************************************/ /* We now construct a bit map for the set of terminal symbols that */ /* may appear in each state. Then, we invoke PARTSET to apply the */ /* Partition Heuristic and print it. */ /********************************************************************/ as_size = Allocate_short_array(num_states + 1); if (table_opt == OPTIMIZE_TIME) { original = Allocate_short_array(num_symbols + 1); /*************************************************************/ /* In a compressed TIME table, the terminal and non-terminal */ /* symbols are mixed together when they are remapped. */ /* We shall now recover the original number associated with */ /* each terminal symbol since it lies very nicely in the */ /* range 1..NUM_TERMINALS. This will save a considerable */ /* amount of space in the bit_string representation of sets */ /* as well as time when operations are performed on those */ /* bit-strings. */ /*************************************************************/ for ALL_TERMINALS(symbol) original[symbol_map[symbol]] = symbol; } /***********************************************************************/ /* NOTE that the arrays ACTION_SYMBOLS and NACTION_SYMBOLS are global */ /* variables that are allocated in the procedure PROCESS_TABLES by */ /* calloc which automatically initializes them to 0. */ /***********************************************************************/ for ALL_STATES(state_no) { struct shift_header_type sh; struct reduce_header_type red; sh = shift[statset[state_no].shift_number]; as_size[state_no] = sh.size; for (i = 1; i <= sh.size; i++) { if (table_opt == OPTIMIZE_TIME) symbol = original[SHIFT_SYMBOL(sh, i)]; else symbol = SHIFT_SYMBOL(sh, i); SET_BIT_IN(action_symbols, state_no, symbol); } red = reduce[state_no]; as_size[state_no] += red.size; for (i = 1; i <= red.size; i++) { if (table_opt == OPTIMIZE_TIME) symbol = original[REDUCE_SYMBOL(red, i)]; else symbol = REDUCE_SYMBOL(red, i); SET_BIT_IN(action_symbols, state_no, symbol); } } partset(action_symbols, as_size, state_list, state_start, state_stack, num_terminals); ffree(action_symbols); /*********************************************************************/ /* We now write the starting location for each state in the domain */ /* of the ACTION_SYMBOL map. */ /* The starting locations are contained in the STATE_START vector. */ /*********************************************************************/ offset = state_start[num_states + 1]; k = 0; for ALL_STATES(i) { field(ABS(state_start[state_list[i]]), 6); k++; if (k == 12) { *output_ptr++ = '\n'; BUFFER_CHECK(systab); k = 0; } } field(offset, 6); k++; *output_ptr++ = '\n'; BUFFER_CHECK(systab); /**************************************************************/ /* Compute and write out the range of the ACTION_SYMBOLS map. */ /**************************************************************/ action_symbols_range = Allocate_short_array(offset); compute_action_symbols_range(state_start, state_stack, state_list, action_symbols_range); k = 0; for (i = 0; i < (offset - 1); i++) { field(action_symbols_range[i], 4); k++; if (k == 18) { *output_ptr++ = '\n'; BUFFER_CHECK(systab); k = 0; } } if (k != 0) { *output_ptr++ = '\n'; BUFFER_CHECK(systab); } /*************************************************************/ /* Compute and list space required for ACTION_SYMBOLS map. */ /*************************************************************/ num_bytes = 2 * (num_states + offset); if (byte_bit) { if (offset <= 255) num_bytes -= (num_states + 1); if (((table_opt == OPTIMIZE_TIME) && (last_terminal <= 255)) || ((table_opt != OPTIMIZE_TIME) && (num_terminals <= 255))) num_bytes -= (offset - 1); } sprintf(msg_line, " Storage required for ACTION_SYMBOLS map: " "%ld Bytes", num_bytes); PRNT(msg_line); ffree(action_symbols_range); /***********************************************************************/ /* We now repeat the same process for the domain of the GOTO table. */ /***********************************************************************/ for ALL_STATES(state_no) { as_size[state_no] = gd_index[state_no + 1] - gd_index[state_no]; for (i = gd_index[state_no]; i < gd_index[state_no + 1]; i++) { symbol = gd_range[i] - num_terminals; NTSET_BIT_IN(naction_symbols, state_no, symbol); } } partset(naction_symbols, as_size, state_list, state_start, state_stack, num_non_terminals); ffree(as_size); ffree(naction_symbols); for (i = 1; i <= gotodom_size; i++) /* Remap non-terminals */ { if (table_opt == OPTIMIZE_TIME) gd_range[i] = symbol_map[gd_range[i]]; else gd_range[i] = symbol_map[gd_range[i]] - num_terminals; } /*****************************************************************/ /* We now write the starting location for each state in the */ /* domain of the NACTION_SYMBOLS map. The starting locations are */ /* contained in the STATE_START vector. */ /*****************************************************************/ offset = state_start[num_states + 1]; k = 0; for ALL_STATES(i) { field(ABS(state_start[state_list[i]]), 6); k++; if (k == 12) { *output_ptr++ = '\n'; BUFFER_CHECK(systab); k = 0; } } field(offset, 6); k++; *output_ptr++ = '\n'; BUFFER_CHECK(systab); /**************************************************************/ /* Compute and write out the range of the NACTION_SYMBOLS map.*/ /**************************************************************/ naction_symbols_range = Allocate_short_array(offset); compute_naction_symbols_range(state_start, state_stack, state_list, naction_symbols_range); k = 0; for (i = 0; i < (offset - 1); i++) { field(naction_symbols_range[i], 4); k++; if (k == 18) { *output_ptr++ = '\n'; BUFFER_CHECK(systab); k = 0; } } if (k != 0) { *output_ptr++ = '\n'; BUFFER_CHECK(systab); } /*************************************************************/ /* Compute and list space required for NACTION_SYMBOLS map. */ /*************************************************************/ num_bytes = 2 * (num_states + offset); if (byte_bit) { if (offset <= 255) num_bytes -= (num_states + 1); if (((table_opt == OPTIMIZE_TIME) && (last_non_terminal <= 255)) || ((table_opt != OPTIMIZE_TIME) && (num_non_terminals <= 255))) num_bytes -= (offset - 1); } sprintf(msg_line, " Storage required for NACTION_SYMBOLS map: " "%ld Bytes", num_bytes); PRNT(msg_line); ffree(naction_symbols_range); /***********************************************************************/ /* Compute map from each symbol to state into which that symbol can */ /* cause a transition: TRANSITION_STATES */ /* TRANSITION_STATES is also written as two vectors like the FOLLOW */ /* map and the ACTION_DOMAIN map. */ /* The first vector contains the starting location in the second */ /* vector for each symbol. */ /* Construct the TRANSITION_STATES map using an array SYMBOL_ROOT */ /* (indexable by each symbol) whose elements are the root of a linked */ /* stack built in STATE_STACK. Another array SYMBOL_COUNT is used to */ /* keep count of the number of states associated with each symbol. */ /* For space tables, the TRANSITION_STATES map is written as two */ /* separate tables: SHIFT_STATES and GOTO_STATES. */ /***********************************************************************/ for ALL_SYMBOLS(symbol) { symbol_root[symbol] = NIL; symbol_count[symbol] = 0; } for (state_no = 2; state_no <= (int) num_states; state_no++) { struct node *q; q = statset[state_no].kernel_items; if (q == NULL) /* is the state a single production state? */ { q = statset[state_no].complete_items; /* pick arbitrary item */ } item_no = q -> value - 1; i = item_table[item_no].symbol; symbol = symbol_map[i]; state_stack[state_no] = symbol_root[symbol]; symbol_root[symbol] = state_no; symbol_count[symbol]++; } /***************************************************************************/ /* We now compute and write the starting location for each terminal symbol */ /***************************************************************************/ offset = 1; /* Offset of the first state */ field(offset, 6); k = 1; for (symbol = 1; symbol <= terminal_ubound; symbol++) { offset += symbol_count[symbol]; field(offset, 6); k++; if (k == 12) { *output_ptr++ = '\n'; BUFFER_CHECK(systab); k = 0; } } if (k != 0) { *output_ptr++ = '\n'; BUFFER_CHECK(systab); } /*********************************************************************/ /* We now write out the range elements of SHIFT_STATES for space */ /* tables or TRANSITION_STATES for time tables. */ /*********************************************************************/ k = 0; for (symbol = 1; symbol <= terminal_ubound; symbol++) { for (state_no = symbol_root[symbol]; state_no != NIL; state_no = state_stack[state_no]) { field(state_index[state_no] + num_rules, 6); k++; if (k == 12) { *output_ptr++ = '\n'; BUFFER_CHECK(systab); k = 0; } } } if (k != 0) { *output_ptr++ = '\n'; BUFFER_CHECK(systab); } /*********************************************************************/ /* If space tables are requested we compute and list space required */ /* for SHIFT_STATES map. The base vector contains NUM_TERMINALS+ 1 */ /* elements, and the vector containing the range elements has size */ /* OFFSET - 1. If time tables are requested we compute and list space*/ /* requirements for TRANSITION_STATES map. The base vector has */ /* NUM_SYMBOLS + 1 elements, and the range elements vector contains */ /* OFFSET - 1 elements. */ /*********************************************************************/ if (table_opt == OPTIMIZE_TIME) { num_bytes = 2 * (num_symbols + offset); sprintf(msg_line, " Storage required for TRANSITION_STATES map: %d Bytes", num_bytes); PRNT(msg_line); } else { num_bytes = 2 * (num_terminals + offset); sprintf(msg_line, " Storage required for SHIFT_STATES map: %d Bytes", num_bytes); PRNT(msg_line); /************************************************************/ /* We now compute and write the starting location for each */ /* non-terminal symbol... */ /************************************************************/ offset = 1; field(offset, 6); /* Offset of the first state */ k = 1; for ALL_NON_TERMINALS(symbol) { offset += symbol_count[symbol]; field(offset, 6); k++; if (k == 12) { *output_ptr++ = '\n'; BUFFER_CHECK(systab); k = 0; } } if (k != 0) { *output_ptr++ = '\n'; BUFFER_CHECK(systab); } /*********************************************************************/ /* We now write out the range elements of GOTO_STATES whose domain */ /* is a non-terminal symbol. */ /*********************************************************************/ k = 0; for ALL_NON_TERMINALS(symbol) { for (state_no = symbol_root[symbol]; state_no != NIL; state_no = state_stack[state_no]) { field(state_index[state_no] + num_rules, 6); k++; if (k == 12) { *output_ptr++ = '\n'; BUFFER_CHECK(systab); k = 0; } } } if (k != 0) { *output_ptr++ = '\n'; BUFFER_CHECK(systab); } /*********************************************************************/ /* We compute and list space required for GOTO_STATES map. The */ /* base vector contains NUM_NON_TERMINALS+ 1 elements, and the vector*/ /* containing the range elements has size OFFSET - 1 */ /*********************************************************************/ num_bytes = 2 * (num_non_terminals + offset); sprintf(msg_line," Storage required for GOTO_STATES map: %d Bytes", num_bytes); PRNT(msg_line); } /*********************************************************************/ /* Write the number associated with the ERROR symbol. */ /*********************************************************************/ field(error_image, 4); field(eolt_image, 4); field(num_names, 4); field(num_scopes, 4); field(scope_rhs_size, 4); field(scope_state_size, 4); if (table_opt == OPTIMIZE_SPACE) field(num_error_rules, 4); *output_ptr++ = '\n'; BUFFER_CHECK(systab); /*********************************************************************/ /* We write out the names map. */ /*********************************************************************/ num_bytes = 0; max_len = 0; for (i = 1; i <= num_names; i++) { int name_len; strcpy(tok, RETRIEVE_NAME(i)); if (tok[0] == '\n') /* we're dealing with special symbol? */ tok[0] = escape; /* replace initial marker with escape. */ name_len = strlen(tok); num_bytes += name_len; if (max_len < name_len) max_len = name_len; field(name_len, 4); if (name_len <= 68) strcpy(output_ptr, tok); else { memcpy(output_ptr, tok, 68); output_ptr+= 68; *output_ptr++ = '\n'; BUFFER_CHECK(systab);; strcpy(tok, tok+68); for (name_len = strlen(tok); name_len > 72; name_len = strlen(tok)) { memcpy(output_ptr, tok, 72); output_ptr+= 72; *output_ptr++ = '\n'; BUFFER_CHECK(systab); strcpy(tok, tok+72); } memcpy(output_ptr, tok, name_len); } output_ptr += name_len; *output_ptr++ = '\n'; BUFFER_CHECK(systab); } /*********************************************************************/ /* We write the name_index of each terminal symbol. The array TEMP */ /* is used to remap the NAME_INDEX values based on the new symbol */ /* numberings. If time tables are requested, the terminals and non- */ /* terminals are mixed together. */ /*********************************************************************/ temp = Allocate_short_array(num_symbols + 1); if (table_opt == OPTIMIZE_TIME) { for ALL_SYMBOLS(symbol) temp[symbol_map[symbol]] = symno[symbol].name_index; k = 0; for ALL_SYMBOLS(symbol) { field(temp[symbol], 4); k++; if (k == 18) { *output_ptr++ = '\n'; BUFFER_CHECK(systab); k = 0; } } if (k != 0) { *output_ptr++ = '\n'; BUFFER_CHECK(systab); } } else { for ALL_TERMINALS(symbol) temp[symbol_map[symbol]] = symno[symbol].name_index; k = 0; for ALL_TERMINALS(symbol) { field(temp[symbol], 4); k++; if (k == 18) { *output_ptr++ = '\n'; BUFFER_CHECK(systab); k = 0; } } if (k != 0) { *output_ptr++ = '\n'; BUFFER_CHECK(systab); } /****************************************************************/ /* We write the name_index of each non_terminal symbol. The */ /* array TEMP is used to remap the NAME_INDEX values based on */ /* the new symbol numberings. */ /****************************************************************/ for ALL_NON_TERMINALS(symbol) temp[symbol_map[symbol]] = symno[symbol].name_index; k = 0; for ALL_NON_TERMINALS(symbol) { field(temp[symbol], 4); k++; if (k == 18) { *output_ptr++ = '\n'; BUFFER_CHECK(systab); k = 0; } } if (k != 0) { *output_ptr++ = '\n'; BUFFER_CHECK(systab); } } /*****************************************************/ /* Compute and list space requirements for NAME map. */ /*****************************************************/ if (max_len > 255) offset = 2 * num_symbols; else offset = num_symbols; if (num_bytes > 255) offset += (2 * num_symbols); else offset += num_symbols; sprintf(msg_line, " Storage required for direct NAME map: %d Bytes", num_bytes + offset); PRNT(msg_line); if (max_len > 255) offset = 2 * num_names; else offset = num_names; if (num_bytes > 255) offset += (2 * num_names); else offset += num_names; if (num_names > 255) offset += (2 * num_symbols); else offset += num_symbols; sprintf(msg_line, " Storage required for indirect NAME map: %d Bytes", num_bytes + offset); PRNT(msg_line); if (scopes_bit) { for (i = 1; i <= scope_rhs_size; i++) { if (scope_right_side[i] != 0) scope_right_side[i] = symbol_map[scope_right_side[i]]; } for (i = 1; i <= num_scopes; i++) { scope[i].look_ahead = symbol_map[scope[i].look_ahead]; if (table_opt == OPTIMIZE_TIME) scope[i].lhs_symbol = symbol_map[scope[i].lhs_symbol]; else scope[i].lhs_symbol = symbol_map[scope[i].lhs_symbol] - num_terminals; } k = 0; for (i = 1; i <= num_scopes; i++) { field(scope[i].prefix, 4); k++; if (k == 18) { *output_ptr++ = '\n'; BUFFER_CHECK(systab); k = 0; } } if (k != 0) { *output_ptr++ = '\n'; BUFFER_CHECK(systab); } k = 0; for (i = 1; i <= num_scopes; i++) { field(scope[i].suffix, 4); k++; if (k == 18) { *output_ptr++ = '\n'; BUFFER_CHECK(systab); k = 0; } } if (k != 0) { *output_ptr++ = '\n'; BUFFER_CHECK(systab); } k = 0; for (i = 1; i <= num_scopes; i++) { field(scope[i].lhs_symbol, 4); k++; if (k == 18) { *output_ptr++ = '\n'; BUFFER_CHECK(systab); k = 0; } } if (k != 0) { *output_ptr++ = '\n'; BUFFER_CHECK(systab); } k = 0; for (i = 1; i <= num_scopes; i++) { field(scope[i].look_ahead, 4); k++; if (k == 18) { *output_ptr++ = '\n'; BUFFER_CHECK(systab); k = 0; } } if (k != 0) { *output_ptr++ = '\n'; BUFFER_CHECK(systab); } k = 0; for (i = 1; i <= num_scopes; i++) { field(scope[i].state_set, 4); k++; if (k == 18) { *output_ptr++ = '\n'; BUFFER_CHECK(systab); k = 0; } } if (k != 0) { *output_ptr++ = '\n'; BUFFER_CHECK(systab); } k = 0; for (i = 1; i <= scope_rhs_size; i++) { field(scope_right_side[i], 4); k++; if (k == 18) { *output_ptr++ = '\n'; BUFFER_CHECK(systab); k = 0; } } if (k != 0) { *output_ptr++ = '\n'; BUFFER_CHECK(systab); } k = 0; for (i = 1; i <= scope_state_size; i++) { if (scope_state[i] == 0) field(0, 6); else field(state_index[scope_state[i]] + num_rules, 6); k++; if (k == 12) { *output_ptr++ = '\n'; BUFFER_CHECK(systab); k = 0; } } if (k != 0) { *output_ptr++ = '\n'; BUFFER_CHECK(systab); } if (table_opt == OPTIMIZE_TIME) { num_bytes = 5 * num_scopes + scope_rhs_size+ scope_state_size; if (num_symbols > 255) num_bytes += (2 * num_scopes + scope_rhs_size); } else { num_bytes = 5 * num_scopes + scope_rhs_size+ 2 * scope_state_size; if (num_non_terminals > 255) num_bytes += num_scopes; if (num_terminals > 255) num_bytes += num_scopes; if (num_symbols > 255) num_bytes += scope_rhs_size; } if (scope_rhs_size > 255) num_bytes += (2 * num_scopes); if (scope_state_size > 255) num_bytes += num_scopes; sprintf(msg_line, " Storage required for SCOPE map: %d Bytes", num_bytes); PRNT(msg_line); } if (original != NULL) { ffree(original); } ffree(symbol_root); ffree(symbol_count); ffree(temp); ffree(state_start); ffree(state_stack); ffree(term_list); return; } /*********************************************************************/ /* COMPUTE_ACTION_SYMBOLS_RANGE: */ /*********************************************************************/ /* */ /* This procedure computes the range of the ACTION_SYMBOLS map after */ /* Optimal Partitioning has been used to compress that map. Its */ /* first argument is an array, STATE_START, that indicates the */ /* starting location in the compressed vector for each state. When */ /* a value of STATE_START is negative it indicates that the state in */ /* question shares its elements with another state. Its second */ /* argument, STATE_STACK, is an array that contains the elements of */ /* the partition created by PARTSET. Each element of the partition */ /* is organized as a circular list where the smallest sets appear */ /* first in the list. */ /* */ /*********************************************************************/ void compute_action_symbols_range(short *state_start, short *state_stack, short *state_list, short *action_symbols_range) { int i, j, k, state_no, state, symbol, symbol_root; BOOLEAN end_node; short *symbol_list; symbol_list = Allocate_short_array(num_symbols + 1); /*********************************************************************/ /* We now write out the range elements of the ACTION_SYMBOLS map. */ /* Recall that if STATE_START has a negative value, then the set in */ /* question is sharing elements and does not need to be processed. */ /*********************************************************************/ k = 0; for ALL_SYMBOLS(j) symbol_list[j] = OMEGA; /* Initialize all links to OMEGA */ for ALL_STATES(i) { state_no = state_list[i]; if (state_start[state_no] > 0) { symbol_root = 0; /* Add "fence" element: 0 to list */ symbol_list[symbol_root] = NIL; /*************************************************************/ /* Pop a state from the stack, and add each of its elements */ /* that has not yet been processed into the list. */ /* Continue until stack is empty... */ /* Recall that the stack is represented by a circular queue. */ /*************************************************************/ for (end_node = ((state = state_no) == NIL); ! end_node; end_node = (state == state_no)) { struct shift_header_type sh; struct reduce_header_type red; state = state_stack[state]; sh = shift[statset[state].shift_number]; for (j = 1; j <= sh.size; j++) { symbol = SHIFT_SYMBOL(sh, j); if (symbol_list[symbol] == OMEGA) { symbol_list[symbol] = symbol_root; symbol_root = symbol; } } red = reduce[state]; for (j = 1; j <= red.size; j++) { symbol = REDUCE_SYMBOL(red, j); if (symbol_list[symbol] == OMEGA) { symbol_list[symbol] = symbol_root; symbol_root = symbol; } } } /*************************************************************/ /* Write the list out. */ /*************************************************************/ for (symbol = symbol_root; symbol != NIL; symbol = symbol_root) { symbol_root = symbol_list[symbol]; symbol_list[symbol] = OMEGA; action_symbols_range[k++] = symbol; } } } ffree(symbol_list); return; } /*********************************************************************/ /* COMPUTE_NACTION_SYMBOLS_RANGE: */ /*********************************************************************/ /* This procedure computes the range of the NACTION_SYMBOLS map. It */ /* organization is analoguous to COMPUTE_ACTION_SYMBOLS_RANGE. */ /*********************************************************************/ void compute_naction_symbols_range(short *state_start, short *state_stack, short *state_list, short *naction_symbols_range) { int i, j, k, state_no, state, symbol, symbol_root; BOOLEAN end_node; short *symbol_list; symbol_list = Allocate_short_array(num_symbols + 1); /*********************************************************************/ /* We now write out the range elements of the NACTION_SYMBOLS map. */ /* Recall that if STATE_START has a negative value, then the set in */ /* question is sharing elements and does not need to be processed. */ /*********************************************************************/ k = 0; for ALL_SYMBOLS(j) symbol_list[j] = OMEGA; /* Initialize all links to OMEGA */ for ALL_STATES(i) { state_no = state_list[i]; if (state_start[state_no] > 0) { symbol_root = 0; /* Add "fence" element: 0 to list */ symbol_list[symbol_root] = NIL; /*************************************************************/ /* Pop a state from the stack, and add each of its elements */ /* that has not yet been processed into the list. */ /* Continue until stack is empty... */ /* Recall that the stack is represented by a circular queue. */ /*************************************************************/ for (end_node = ((state = state_no) == NIL); ! end_node; end_node = (state == state_no)) { state = state_stack[state]; for (j = gd_index[state]; j <= gd_index[state + 1] - 1; j++) { symbol = gd_range[j]; if (symbol_list[symbol] == OMEGA) { symbol_list[symbol] = symbol_root; symbol_root = symbol; } } } /**********************************************************/ /* Write the list out. */ /**********************************************************/ for (symbol = symbol_root; symbol != NIL; symbol = symbol_root) { symbol_root = symbol_list[symbol]; symbol_list[symbol] = OMEGA; naction_symbols_range[k++] = symbol; } } } ffree(symbol_list); return; } jikespg-1.3/src/timetab.c000066400000000000000000001017021167345774400154140ustar00rootroot00000000000000/* $Id: timetab.c,v 1.2 1999/11/04 14:02:23 shields Exp $ */ /* This software is subject to the terms of the IBM Jikes Compiler License Agreement available at the following URL: http://www.ibm.com/research/jikes. Copyright (C) 1983, 1999, International Business Machines Corporation and others. All Rights Reserved. You must accept the terms of that agreement to use this software. */ static char hostfile[] = __FILE__; #include #include "common.h" #include "header.h" static int default_saves = 0; static short default_rule; static BOOLEAN *is_terminal; /*********************************************************************/ /* REMAP_SYMBOLS: */ /*********************************************************************/ /* We now remap the symbols in the unified Table based on frequency. */ /* We also remap the states based on frequency. */ /*********************************************************************/ static void remap_symbols(void) { struct goto_header_type go_to; struct shift_header_type sh; struct reduce_header_type red; short *frequency_symbol, *frequency_count, *row_size; int symbol, state_no, i, j, k; ordered_state = Allocate_short_array(max_la_state + 1); symbol_map = Allocate_short_array(num_symbols + 1); is_terminal = Allocate_boolean_array(num_symbols + 1); frequency_symbol = Allocate_short_array(num_symbols + 1); frequency_count = Allocate_short_array(num_symbols + 1); row_size = Allocate_short_array(max_la_state + 1); fprintf(syslis, "\n"); /*********************************************************************/ /* The variable FREQUENCY_SYMBOL is used to hold the symbols */ /* in the grammar, and the variable FREQUENCY_COUNT is used */ /* correspondingly to hold the number of actions defined on each */ /* symbol. */ /* ORDERED_STATE and ROW_SIZE are used in a similar fashion for */ /* states. */ /*********************************************************************/ for (i = 1; i <= num_symbols; i++) { frequency_symbol[i] = i; frequency_count[i] = 0; } for ALL_STATES(state_no) { ordered_state[state_no] = state_no; row_size[state_no] = 0; sh = shift[statset[state_no].shift_number]; for (i = 1; i <= sh.size; i++) { row_size[state_no]++; symbol = SHIFT_SYMBOL(sh, i); frequency_count[symbol]++; } go_to = statset[state_no].go_to; for (i = 1; i <= go_to.size; i++) { row_size[state_no]++; symbol = GOTO_SYMBOL(go_to, i); frequency_count[symbol]++; } red = reduce[state_no]; default_rule = REDUCE_RULE_NO(red, 0); for (i = 1; i <= red.size; i++) { if (REDUCE_RULE_NO(red, i) != default_rule) { row_size[state_no]++; symbol = REDUCE_SYMBOL(red, i); frequency_count[symbol]++; } else default_saves++; } } sprintf(msg_line, "Number of Reductions saved by default: %d", default_saves); PRNT(msg_line); for ALL_LA_STATES(state_no) { ordered_state[state_no] = state_no; row_size[state_no] = 0; sh = shift[lastats[state_no].shift_number]; for (i = 1; i <= sh.size; i++) { row_size[state_no]++; symbol = SHIFT_SYMBOL(sh, i); frequency_count[symbol]++; } red = lastats[state_no].reduce; default_rule = REDUCE_RULE_NO(red, 0); for (i = 1; i <= red.size; i++) { if (REDUCE_RULE_NO(red, i) != default_rule) { row_size[state_no]++; symbol = REDUCE_SYMBOL(red, i); frequency_count[symbol]++; } else default_saves++; } } /*********************************************************************/ /* The non-terminals are sorted in descending order based on the */ /* number of actions defined on them. */ /* The terminals are sorted in descending order based on the */ /* number of actions defined on them. */ /*********************************************************************/ sortdes(frequency_symbol, frequency_count, 1, num_terminals, max_la_state); sortdes(frequency_symbol, frequency_count, num_terminals + 1, num_symbols, max_la_state); for (last_symbol = num_symbols; last_symbol > num_terminals; last_symbol--) if (frequency_count[last_symbol] != 0) break; /*********************************************************************/ /* We now merge the two sorted arrays of symbols giving precedence to*/ /* the terminals. Note that we can guarantee that the terminal array*/ /* will be depleted first since it has precedence, and we know that */ /* there exists at least one non-terminal: the accept non-terminal, */ /* on which no action is defined. */ /* As we merge the symbols, we keep track of which ones are terminals*/ /* and which ones are non-terminals. We also keep track of the new */ /* mapping for the symbols in SYMBOL_MAP. */ /*********************************************************************/ i = 1; j = num_terminals + 1; k = 0; while (i <= num_terminals) { k++; if (frequency_count[i] >= frequency_count[j]) { symbol = frequency_symbol[i]; is_terminal[k] = TRUE; i++; } else { symbol = frequency_symbol[j]; is_terminal[k] = FALSE; j++; } symbol_map[symbol] = k; } symbol_map[DEFAULT_SYMBOL] = DEFAULT_SYMBOL; /*********************************************************************/ /* Process the remaining non-terminal and useless terminal symbols. */ /*********************************************************************/ for (; j <= num_symbols; j++) { k++; symbol = frequency_symbol[j]; is_terminal[k] = FALSE; symbol_map[symbol] = k; } eoft_image = symbol_map[eoft_image]; if (error_maps_bit) { error_image = symbol_map[error_image]; eolt_image = symbol_map[eolt_image]; } /*********************************************************************/ /* All symbol entries in the state automaton are updated based on */ /* the new mapping of the symbols. */ /* The states are sorted in descending order based on the number of */ /* actions defined on them. */ /*********************************************************************/ for ALL_STATES(state_no) { go_to = statset[state_no].go_to; for (i = 1; i <= go_to.size; i++) /* Remap Goto map */ GOTO_SYMBOL(go_to, i) = symbol_map[GOTO_SYMBOL(go_to, i)]; red = reduce[state_no]; for (i = 1; i <= red.size; i++) REDUCE_SYMBOL(red, i) = symbol_map[REDUCE_SYMBOL(red, i)]; } for ALL_LA_STATES(state_no) { red = lastats[state_no].reduce; for (i = 1; i <= red.size; i++) REDUCE_SYMBOL(red, i) = symbol_map[REDUCE_SYMBOL(red, i)]; } for (i = 1; i <= num_shift_maps; i++) { sh = shift[i]; for (j = 1; j <= sh.size; j++) SHIFT_SYMBOL(sh, j) = symbol_map[SHIFT_SYMBOL(sh, j)]; } sortdes(ordered_state, row_size, 1, max_la_state, num_symbols); ffree(frequency_symbol); ffree(frequency_count); ffree(row_size); return; } /*********************************************************************/ /* OVERLAP_TABLES: */ /*********************************************************************/ /* We now overlap the State automaton table, or more precisely, we */ /* compute the starting position in a vector where each of its rows */ /* may be placed without clobbering elements in another row. */ /* The starting positions are stored in the vector STATE_INDEX. */ /*********************************************************************/ static void overlap_tables(void) { struct goto_header_type go_to; struct shift_header_type sh; struct reduce_header_type red; short *symbol_list; int symbol, state_no, root_symbol, max_indx, indx, percentage, k_bytes, k, i; long num_bytes; state_index = Allocate_int_array(max_la_state + 1); symbol_list = Allocate_short_array(num_symbols + 1); num_entries -= default_saves; increment_size = MAX((num_entries*increment/100), (num_symbols + 1)); table_size = MIN((num_entries + increment_size), MAX_TABLE_SIZE); /*********************************************************************/ /* Allocate space for table, and initialize the AVAIL_POOL list. */ /* The variable FIRST_INDEX keeps track of the first element in the */ /* doubly-linked list, and LAST_ELEMENT keeps track of the last */ /* element in the list. */ /* The variable MAX_INDX is used to keep track of the maximum */ /* starting position for a row that has been used. */ /*********************************************************************/ next = Allocate_int_array(table_size + 1); previous = Allocate_int_array(table_size + 1); first_index = 1; next[first_index] = first_index + 1; /* Should be constant-folded */ previous[first_index] = NIL; for (indx = 2; indx < (int) table_size; indx++) { next[indx] = indx + 1; previous[indx] = indx - 1; } last_index = table_size; previous[last_index] = last_index - 1; next[last_index] = NIL; max_indx = first_index; /*********************************************************************/ /* We now iterate over all the states in their new sorted order as */ /* indicated by the variable STATE_NO, and deternime an "overlap" */ /* position for them. */ /*********************************************************************/ for (k = 1; k <= (int) max_la_state; k++) { state_no = ordered_state[k]; /*********************************************************************/ /* First, we iterate over all actions defined in STATE_NO, and */ /* create a set with all the symbols involved. */ /*********************************************************************/ root_symbol = NIL; if (state_no > (int) num_states) { sh = shift[lastats[state_no].shift_number]; red = lastats[state_no].reduce; } else { go_to = statset[state_no].go_to; for (i = 1; i <= go_to.size; i++) { symbol = GOTO_SYMBOL(go_to, i); symbol_list[symbol] = root_symbol; root_symbol = symbol; } sh = shift[statset[state_no].shift_number]; red = reduce[state_no]; } for (i = 1; i <= sh.size; i++) { symbol = SHIFT_SYMBOL(sh, i); symbol_list[symbol] = root_symbol; root_symbol = symbol; } symbol_list[0] = root_symbol; root_symbol = 0; default_rule = REDUCE_RULE_NO(red, 0); for (i = 1; i <= red.size; i++) { if (REDUCE_RULE_NO(red, i) != default_rule) { symbol = REDUCE_SYMBOL(red, i); symbol_list[symbol] = root_symbol; root_symbol = symbol; } } /*********************************************************************/ /* INDX is set to the beginning of the list of available slots and */ /* we try to determine if it might be a valid starting position. If */ /* not, INDX is moved to the next element, and we repeat the process */ /* until a valid position is found. */ /*********************************************************************/ indx = first_index; look_for_match_in_table: if (indx == NIL) indx = table_size + 1; if (indx + num_symbols > (int) table_size) reallocate(); for (symbol = root_symbol; symbol != NIL; symbol = symbol_list[symbol]) { if (next[indx + symbol] == OMEGA) { indx = next[indx]; goto look_for_match_in_table; } } /*********************************************************************/ /* At this stage, a position(INDX), was found to overlay the row in */ /* question. Remove elements associated with all positions that */ /* will be taken by row from the doubly-linked list. */ /* NOTE that since SYMBOLs start at 1, the first index can never be */ /* a candidate (==> I = INDX + SYMBOL) in this loop. */ /*********************************************************************/ if (indx > max_indx) max_indx = indx; state_index[state_no] = indx; for (symbol = root_symbol; symbol != NIL; symbol = symbol_list[symbol]) { i = indx + symbol; if (first_index == last_index) first_index = NIL; else if (i == first_index) { first_index = next[first_index]; previous[first_index] = NIL; } else if (i == last_index) { last_index = previous[last_index]; next[last_index] = NIL; } else { next[previous[i]] = next[i]; previous[next[i]] = previous[i]; } next[i] = OMEGA; } } /*********************************************************************/ /* Update all global counters, and compute ACCEPT_ACTION and */ /* ERROR_ACTION. */ /*********************************************************************/ table_size = max_indx + num_symbols; accept_act = max_indx + num_rules + 1; error_act = accept_act + 1; for (action_size = table_size; action_size >= max_indx; action_size--) if (next[action_size] == OMEGA) break; printf("\n"); sprintf(msg_line,"Length of Check table: %ld", table_size); PRNT(msg_line); sprintf(msg_line,"Length of Action table: %ld", action_size); PRNT(msg_line); sprintf(msg_line, "Number of entries in Action Table: %d", num_entries); PRNT(msg_line); percentage = ((action_size - num_entries) * 1000) / num_entries; sprintf(msg_line, "Percentage of increase: %d.%d%%", percentage / 10, percentage % 10); PRNT(msg_line); if (byte_bit) { num_bytes = 2 * action_size + table_size; if ((! goto_default_bit) && (! nt_check_bit)) { for (; (last_symbol >= 1) && (! is_terminal[last_symbol]); last_symbol--); } sprintf(msg_line, "Highest symbol in Check Table: %d", last_symbol); PRNT(msg_line); if (last_symbol > 255) num_bytes += table_size; } else num_bytes = 2 * (action_size + table_size); if (goto_default_bit) num_bytes += ((long) 2 * num_symbols); k_bytes = (num_bytes / 1024) + 1; sprintf(msg_line, "Storage Required for Tables: %ld Bytes, %dK", num_bytes, k_bytes); PRNT(msg_line); num_bytes = (long) 4 * num_rules; if (byte_bit) { num_bytes -= num_rules; if (num_symbols < 256) num_bytes -= num_rules; } sprintf(msg_line, "Storage Required for Rules: %ld Bytes", num_bytes); PRNT(msg_line); return; } /*********************************************************************/ /* PRINT_TABLES: */ /*********************************************************************/ /* We now write out the tables to the SYSTAB file. */ /*********************************************************************/ static void print_tables(void) { int *action, *check; struct goto_header_type go_to; struct shift_header_type sh; struct reduce_header_type red; int la_shift_count = 0, shift_count = 0, goto_count = 0, default_count = 0, reduce_count = 0, shift_reduce_count = 0, goto_reduce_count = 0; int indx, la_state_offset, act, result_act, i, j, k, symbol, state_no; char *tok; long offset; state_list = Allocate_short_array(max_la_state + 1); check = next; action = previous; offset = error_act; if (read_reduce_bit) offset += num_rules; la_state_offset = offset; if (offset > (MAX_TABLE_SIZE + 1)) { sprintf(msg_line, "Table contains entries that are > " "%d; Processing stopped.", MAX_TABLE_SIZE + 1); PRNTERR(msg_line); exit(12); } /*********************************************************************/ /* Initialize all unfilled slots with default values. */ /*********************************************************************/ indx = first_index; for (i = indx; (i != NIL) && (i <= (int) action_size); i = indx) { indx = next[i]; check[i] = DEFAULT_SYMBOL; action[i] = error_act; } for (i = (int) action_size + 1; i <= (int) table_size; i++) check[i] = DEFAULT_SYMBOL; /*********************************************************************/ /* We set the rest of the table with the proper table entries. */ /*********************************************************************/ for (state_no = 1; state_no <= (int) max_la_state; state_no++) { indx = state_index[state_no]; if (state_no > (int) num_states) { sh = shift[lastats[state_no].shift_number]; red = lastats[state_no].reduce; } else { go_to = statset[state_no].go_to; for (j = 1; j <= go_to.size; j++) { symbol = GOTO_SYMBOL(go_to, j); i = indx + symbol; if (goto_default_bit || nt_check_bit) check[i] = symbol; else check[i] = DEFAULT_SYMBOL; act = GOTO_ACTION(go_to, j); if (act > 0) { action[i] = state_index[act] + num_rules; goto_count++; } else { action[i] = -act; goto_reduce_count++; } } sh = shift[statset[state_no].shift_number]; red = reduce[state_no]; } for (j = 1; j <= sh.size; j++) { symbol = SHIFT_SYMBOL(sh, j); i = indx + symbol; check[i] = symbol; act = SHIFT_ACTION(sh, j); if (act > (int) num_states) { result_act = la_state_offset + state_index[act]; la_shift_count++; } else if (act > 0) { result_act = state_index[act] + num_rules; shift_count++; } else { result_act = -act + error_act; shift_reduce_count++; } if (result_act > (MAX_TABLE_SIZE + 1)) { sprintf(msg_line, "Table contains look-ahead shift entry that is >" " %d; Processing stopped.", MAX_TABLE_SIZE + 1); PRNTERR(msg_line); return; } action[i] = result_act; } /*********************************************************************/ /* We now initialize the elements reserved for reduce actions in */ /* the current state. */ /*********************************************************************/ default_rule = REDUCE_RULE_NO(red, 0); for (j = 1; j <= red.size; j++) { if (REDUCE_RULE_NO(red, j) != default_rule) { symbol = REDUCE_SYMBOL(red, j); i = indx + symbol; check[i] = symbol; act = REDUCE_RULE_NO(red, j); if (rules[act].lhs == accept_image) action[i] = accept_act; else action[i] = act; reduce_count++; } } /*********************************************************************/ /* We now initialize the element reserved for the DEFAULT reduce */ /* action of the current state. If error maps are requested, the */ /* default slot is initialized to the original state number, and the */ /* corresponding element of the DEFAULT_REDUCE array is initialized. */ /* Otherwise it is initialized to the rule number in question. */ /*********************************************************************/ i = indx + DEFAULT_SYMBOL; check[i] = DEFAULT_SYMBOL; act = REDUCE_RULE_NO(red, 0); if (act == OMEGA) action[i] = error_act; else { action[i] = act; default_count++; } } PRNT("\n\nActions in Compressed Tables:"); sprintf(msg_line," Number of Shifts: %d",shift_count); PRNT(msg_line); sprintf(msg_line," Number of Shift/Reduces: %d",shift_reduce_count); PRNT(msg_line); if (max_la_state > num_states) { sprintf(msg_line, " Number of Look-Ahead Shifts: %d", la_shift_count); PRNT(msg_line); } sprintf(msg_line," Number of Gotos: %d",goto_count); PRNT(msg_line); sprintf(msg_line, " Number of Goto/Reduces: %d",goto_reduce_count); PRNT(msg_line); sprintf(msg_line," Number of Reduces: %d",reduce_count); PRNT(msg_line); sprintf(msg_line," Number of Defaults: %d",default_count); PRNT(msg_line); /*********************************************************************/ /* Prepare Header with proper information, and write it out. */ /*********************************************************************/ output_buffer[0] = 'T'; output_buffer[1] = (goto_default_bit ? '1' : '0'); output_buffer[2] = (nt_check_bit ? '1' : '0'); output_buffer[3] = (read_reduce_bit ? '1' : '0'); output_buffer[4] = (single_productions_bit ? '1' : '0'); if (default_opt == 0) output_buffer[5] = '0'; else if (default_opt == 1) output_buffer[5] = '1'; else if (default_opt == 2) output_buffer[5] = '2'; else if (default_opt == 3) output_buffer[5] = '3'; else if (default_opt == 4) output_buffer[5] = '4'; else output_buffer[5] = '5'; output_buffer[6] = (rules[1].lhs == accept_image ? '1' : '0'); output_buffer[7] = (error_maps_bit ? '1' : '0'); output_buffer[8] = (byte_bit && last_symbol <= 255 ? '1' : '0'); output_buffer[9] = escape; output_ptr = &output_buffer[0] + 10; field(num_terminals, 5); field(num_symbols, 5); field(num_rules, 5); field(num_states, 5); field(table_size, 5); field(action_size, 5); field(state_index[1] + num_rules, 5); field(eoft_image, 5); field(accept_act, 5); field(error_act, 5); field(la_state_offset, 5); field(lalr_level, 5); *output_ptr++ = '\n'; /*********************************************************/ /* We write the terminal symbols map. */ /*********************************************************/ for (symbol = 1; symbol <= num_symbols; symbol++) { if (is_terminal[symbol_map[symbol]]) { int len; if (last_terminal < symbol_map[symbol]) last_terminal = symbol_map[symbol]; tok = RETRIEVE_STRING(symbol); if (tok[0] == '\n') /* We're dealing with special symbol? */ tok[0] = escape; /* replace initial marker with escape. */ len = strlen(tok); field(symbol_map[symbol], 4); field(len, 4); if (len <= 64) strcpy(output_ptr, tok); else { memcpy(output_ptr, tok, 64); output_ptr += 64; *output_ptr++ = '\n'; *output_ptr = '\0'; BUFFER_CHECK(systab); tok += 64; for (len = strlen(tok); len > 72; len = strlen(tok)) { memcpy(output_ptr, tok, 72); output_ptr += 72; *output_ptr++ = '\n'; BUFFER_CHECK(systab); tok += 72; } memcpy(output_ptr, tok, len); } output_ptr += len; *output_ptr++ = '\n'; BUFFER_CHECK(systab); } } /*********************************************************/ /* We write the non-terminal symbols map. */ /*********************************************************/ for (symbol = 1; symbol <= num_symbols; symbol++) { if (! is_terminal[symbol_map[symbol]]) { int len; if (last_non_terminal < symbol_map[symbol]) last_non_terminal = symbol_map[symbol]; tok = RETRIEVE_STRING(symbol); if (tok[0] == '\n') /* we're dealing with special symbol? */ tok[0] = escape; /* replace initial marker with escape. */ len = strlen(tok); field(symbol_map[symbol], 4); field(len, 4); if (len <= 64) strcpy(output_ptr, tok); else { memcpy(output_ptr, tok, 64); output_ptr += 64; *output_ptr++ = '\n'; BUFFER_CHECK(systab); tok += 64; for (len = strlen(tok); len > 72; len = strlen(tok)) { memcpy(output_ptr, tok, 72); output_ptr += 72; *output_ptr++ = '\n'; BUFFER_CHECK(systab); tok += 72; } memcpy(output_ptr, tok, len); } output_ptr += len; *output_ptr++ = '\n'; BUFFER_CHECK(systab); } } /*********************************************************************/ /* Write size of right hand side of rules followed by CHECK table. */ /*********************************************************************/ k = 0; for (i = 1; i <= num_rules; i++) { field(RHS_SIZE(i), 4); k++; if (k == 18) { *output_ptr++ = '\n'; BUFFER_CHECK(systab); k = 0; } } for (i = 1; i <= (int) table_size; i++) { field(check[i], 4); k++; if (k == 18) { *output_ptr++ = '\n'; BUFFER_CHECK(systab); k = 0; } } if (k != 0) { *output_ptr++ = '\n'; BUFFER_CHECK(systab); } /*********************************************************************/ /* Write left hand side symbol of rules followed by ACTION table. */ /*********************************************************************/ k = 0; for (i = 1; i <= num_rules; i++) { field(symbol_map[rules[i].lhs], 6); k++; if (k == 12) { *output_ptr++ = '\n'; BUFFER_CHECK(systab); k = 0; } } for (i = 1; i <= (int) action_size; i++) { field(action[i], 6); k++; if (k == 12) { *output_ptr++ = '\n'; BUFFER_CHECK(systab); k = 0; } } if (k != 0) { *output_ptr++ = '\n'; BUFFER_CHECK(systab); } /******************************************************************/ /* If GOTO_DEFAULT is requested, we print out the GOTODEF vector */ /* after rearranging its elements based on the new ordering of the*/ /* symbols. The array TEMP is used to hold the GOTODEF values. */ /******************************************************************/ if (goto_default_bit) { short *default_map; default_map = Allocate_short_array(num_symbols + 1); for (i = 0; i <= num_symbols; i++) default_map[i] = error_act; for ALL_NON_TERMINALS(symbol) { act = gotodef[symbol]; if (act < 0) result_act = -act; else if (act > 0) result_act = state_index[act] + num_rules; else result_act = error_act; default_map[symbol_map[symbol]] = result_act; } k = 0; for (symbol = 1; symbol <= num_symbols; symbol++) { k++; field(default_map[symbol], 6); if (k == 12) { *output_ptr++ = '\n'; BUFFER_CHECK(systab); k = 0; } } if (k != 0) { *output_ptr++ = '\n'; BUFFER_CHECK(systab); } } /*********************************************************************/ /* We first sort the new state numbers. A bucket sort technique */ /* is used using the ACTION vector as a base to simulate the */ /* buckets. NOTE: the iteration over the buckets is done backward */ /* because we also construct a list of the original state numbers */ /* that reflects the permutation of the new state numbers. */ /* During the backward iteration, we construct the list as a stack. */ /*********************************************************************/ if (error_maps_bit || states_bit) { int max_indx; max_indx = accept_act - num_rules - 1; for (i = 1; i <= max_indx; i++) action[i] = OMEGA; for ALL_STATES(state_no) action[state_index[state_no]] = state_no; j = num_states + 1; for (i = max_indx; i >= 1; i--) { state_no = action[i]; if (state_no != OMEGA) { j--; ordered_state[j] = i + num_rules; state_list[j] = state_no; } } } ffree(next); ffree(previous); /*********************************************************************/ /* If ERROR_MAPS are requested, we print them out in the following */ /* order: */ /* */ /* 1) The FOLLOW map (NEWFOLL) */ /* 2) The SORTED_STATE vector */ /* 3) The ORIGINAL_STATE vector */ /* 4) The map from states into valid symbols on which actions are */ /* defined within the state in question: ACTION_SYMBOLS */ /* 5) The map from each symbol into the set of states that can */ /* possibly be reached after a transition on the symbol in */ /* question: TRANSITION_STATES */ /* */ /*********************************************************************/ if (error_maps_bit) process_error_maps(); fwrite(output_buffer, sizeof(char), output_ptr - &output_buffer[0], systab); return; } /*********************************************************************/ /* CMPRTIM: */ /*********************************************************************/ /* In this routine we compress the State tables and write them out */ /* to a file. The emphasis here is in generating tables that allow */ /* fast access. The terminal and non-terminal tables are compressed */ /* together, so as to achieve maximum speed efficiency. */ /* Otherwise, the compression technique used in this table is */ /* analoguous to the technique used in the routine CMPRSPA. */ /*********************************************************************/ void cmprtim(void) { remap_symbols(); overlap_tables(); if (c_bit || cpp_bit || java_bit) print_time_parser(); else print_tables(); return; }