/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * JFlex 1.8.2                                                             *
 * Copyright (C) 1998-2018  Gerwin Klein <lsf@jflex.de>                    *
 * All rights reserved.                                                    *
 *                                                                         *
 * License: BSD                                                            *
 *                                                                         *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

package jflex.generator;

import java.io.File;
import java.io.PrintWriter;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import jflex.base.Build;
import jflex.base.Pair;
import jflex.core.AbstractLexScan;
import jflex.core.Action;
import jflex.core.EOFActions;
import jflex.core.LexParse;
import jflex.core.LexScan;
import jflex.core.unicode.CMapBlock;
import jflex.core.unicode.CharClasses;
import jflex.dfa.DFA;
import jflex.exceptions.GeneratorException;
import jflex.io.FileUtils;
import jflex.l10n.ErrorMessages;
import jflex.logging.Out;
import jflex.option.Options;
import jflex.skeleton.Skeleton;

This class manages the actual code generation, putting the scanner together, filling in skeleton sections etc.

Table compression, String packing etc. is also done here.

Author:Gerwin Klein
Version:JFlex 1.8.2
/** * This class manages the actual code generation, putting the scanner together, filling in skeleton * sections etc. * * <p>Table compression, String packing etc. is also done here. * * @author Gerwin Klein * @version JFlex 1.8.2 */
public final class Emitter { private static final Pattern JAVADOC_COMMENT_AND_MAYBE_ANNOTATIONS_PATTERN = Pattern.compile( ".*/\\*\\*(.*)\\*/" // javadoc comment, embedded '*/' disallowed + "(?:\\s*@[a-z][a-z0-9_]*(?:\\.[a-z][a-z0-9_]*)*" // @[p.ack.age.]AnnotationClass + " (?:\\s*\\(\\s*(?:\"(?:\\\"|[^\"])*\"" // ignore close parens in double quotes + " |'(?:[^']|\\\\(?:'|u[0-9a-f]{4}))'" // ignore close parens in // single quotes + " |[^)])+\\))?" // optional annotation params + ")*\\s*", // zero or more annotations, followed by optional whitespace Pattern.DOTALL | Pattern.CASE_INSENSITIVE | Pattern.COMMENTS); // bit masks for state attributes private static final int FINAL = 1; private static final int NOLOOK = 8; private final File inputFile; final String outputFileName; private final PrintWriter out; private final Skeleton skel; private final AbstractLexScan scanner; private final LexParse parser; private final DFA dfa; private boolean[] isTransition; // for row killing: private int[] rowMap; private boolean[] rowKilled; // for col killing: private int numCols; private int[] colMap; private boolean[] colKilled;
maps actions to their switch label
/** maps actions to their switch label */
private final Map<Action, Integer> actionTable = new LinkedHashMap<>(); private final String visibility; private String eofCode; private String eofThrow;
Emits the java code.
Params:
  • inputFile – input grammar.
  • parser – a LexParse.
  • dfa – a DFA.
  • writer – output file.
/** * Emits the java code. * * @param inputFile input grammar. * @param parser a {@link LexParse}. * @param dfa a {@link DFA}. * @param writer output file. */
Emitter(String outputFileName, File inputFile, LexParse parser, DFA dfa, PrintWriter writer) { this.outputFileName = outputFileName; this.out = writer; this.parser = parser; this.scanner = parser.scanner; this.visibility = scanner.visibility(); this.inputFile = inputFile; this.dfa = dfa; this.skel = new Skeleton(out); }
Computes base name of the class name. Needs to take into account generics.
Params:
  • className – Class name for which to construct the base name
/** * Computes base name of the class name. Needs to take into account generics. * * @param className Class name for which to construct the base name */
static String getBaseName(String className) { int gen = className.indexOf('<'); if (gen < 0) { return className; } else { return className.substring(0, gen); } }
Constructs a file in Options.getDir() or in the same directory as another file. Makes a backup if the file already exists.
Params:
  • name – the name (without path) of the file
  • input – fall back location if path = null (expected to be a file in the directory to write to)
Returns:The constructed File
/** * Constructs a file in Options.getDir() or in the same directory as another file. Makes a backup * if the file already exists. * * @param name the name (without path) of the file * @param input fall back location if {@code path = null} (expected to be a file in the directory * to write to) * @return The constructed File */
public static File normalize(String name, File input) { File outputFile; if (Options.getDir() == null) if (input == null || input.getParent() == null) outputFile = new File(name); else outputFile = new File(input.getParent(), name); else outputFile = new File(Options.getDir(), name); if (outputFile.exists() && !Options.no_backup) { File backup = new File(outputFile.toString() + "~"); if (backup.exists()) { //noinspection ResultOfMethodCallIgnored backup.delete(); } if (outputFile.renameTo(backup)) Out.println("Old file \"" + outputFile + "\" saved as \"" + backup + "\""); else Out.println("Couldn't save old file \"" + outputFile + "\", overwriting!"); } return outputFile; } private void println() { out.println(); } private void println(String line) { out.println(line); } private void println(int i) { out.println(i); } private void print(String line) { out.print(line); } private void print(int i) { out.print(i); } private void print(int i, @SuppressWarnings("SameParameterValue") int tab) { int exp; if (i < 0) exp = 1; else exp = 10; while (tab-- > 1) { if (Math.abs(i) < exp) print(" "); exp *= 10; } print(i); } private boolean hasGenLookAhead() { return dfa.lookaheadUsed(); } private void emitLookBuffer() { if (!hasGenLookAhead()) return; println(" /** For the backwards DFA of general lookahead statements */"); println(" private boolean [] zzFin = new boolean [ZZ_BUFFERSIZE+1];"); println(); } private void emitScanError() { print(" private static void zzScanError(int errorCode)"); if (scanner.scanErrorException() != null) print(" throws " + scanner.scanErrorException()); println(" {"); skel.emitNext(); if (scanner.scanErrorException() == null) println(" throw new Error(message);"); else println(" throw new " + scanner.scanErrorException() + "(message);"); skel.emitNext(); print(" " + visibility + " void yypushback(int number) "); if (scanner.scanErrorException() == null) println(" {"); else println(" throws " + scanner.scanErrorException + " {"); } private void emitMain(String functionName) { if (!(scanner.standalone() || scanner.debugOption() || scanner.cupDebug())) return; if (scanner.cupDebug()) { println(" /**"); println(" * Converts an int token code into the name of the"); println(" * token by reflection on the cup symbol class/interface " + scanner.cupSymbol()); println(" */"); println(" private static String getTokenName(int token) {"); println(" try {"); println( " java.lang.reflect.Field [] classFields = " + scanner.cupSymbol() + ".class.getFields();"); println(" for (int i = 0; i < classFields.length; i++) {"); println(" if (classFields[i].getInt(null) == token) {"); println(" return classFields[i].getName();"); println(" }"); println(" }"); println(" } catch (Exception e) {"); println(" e.printStackTrace(System.err);"); println(" }"); println(""); println(" return \"UNKNOWN TOKEN\";"); println(" }"); println(""); println(" /**"); println(" * Same as " + functionName + " but also prints the token to standard out"); println(" * for debugging."); println(" */"); if (scanner.cupCompatible() || scanner.cup2Compatible()) { // cup interface forces public method print(" public "); } else { print(" " + visibility + " "); } if (scanner.tokenType() == null) { if (scanner.isInteger()) print("int"); else if (scanner.isIntWrap()) print("Integer"); else print("Yytoken"); } else print(scanner.tokenType()); print(" debug_"); print(functionName); print("() throws java.io.IOException"); if (scanner.lexThrow() != null) { print(", "); print(scanner.lexThrow()); } if (scanner.scanErrorException() != null) { print(", "); print(scanner.scanErrorException()); } println(" {"); println(" " + scanner.tokenType() + " s = " + functionName + "();"); print(" System.out.println( "); if (scanner.lineCount()) print("\"line:\" + (yyline+1) + "); if (scanner.columnCount()) print("\" col:\" + (yycolumn+1) + "); if (scanner.charCount()) print("\" char:\" + yychar + "); println("\" --\"+ yytext() + \"--\" + getTokenName(s.sym) + \"--\");"); println(" return s;"); println(" }"); println(""); } if (scanner.standalone()) { println(" /**"); println(" * Runs the scanner on input files."); println(" *"); println(" * This is a standalone scanner, it will print any unmatched"); println(" * text to System.out unchanged."); println(" *"); println(" * @param argv the command line, contains the filenames to run"); println(" * the scanner on."); println(" */"); } else { println(" /**"); println(" * Runs the scanner on input files."); println(" *"); println(" * This main method is the debugging routine for the scanner."); println(" * It prints debugging information about each returned token to"); println(" * System.out until the end of file is reached, or an error occured."); println(" *"); println(" * @param argv the command line, contains the filenames to run"); println(" * the scanner on."); println(" */"); } String className = getBaseName(scanner.className()); println(" public static void main(String[] argv) {"); println(" if (argv.length == 0) {"); println( " System.out.println(\"Usage : java " + className + " [ --encoding <name> ] <inputfile(s)>\");"); println(" }"); println(" else {"); println(" int firstFilePos = 0;"); println(" String encodingName = \"UTF-8\";"); println(" if (argv[0].equals(\"--encoding\")) {"); println(" firstFilePos = 2;"); println(" encodingName = argv[1];"); println(" try {"); println(" // Side-effect: is encodingName valid?"); println(" java.nio.charset.Charset.forName(encodingName);"); println(" } catch (Exception e) {"); println(" System.out.println(\"Invalid encoding '\" + encodingName + \"'\");"); println(" return;"); println(" }"); println(" }"); println(" for (int i = firstFilePos; i < argv.length; i++) {"); println(" " + className + " scanner = null;"); println(" try {"); println(" java.io.FileInputStream stream = new java.io.FileInputStream(argv[i]);"); println( " java.io.Reader reader = new java.io.InputStreamReader(stream, encodingName);"); println(" scanner = new " + className + "(reader);"); if (scanner.standalone()) { println(" while ( !scanner.zzAtEOF ) scanner." + functionName + "();"); } else if (scanner.cupDebug()) { println(" while ( !scanner.zzAtEOF ) scanner.debug_" + functionName + "();"); } else { println(" do {"); println(" System.out.println(scanner." + functionName + "());"); println(" } while (!scanner.zzAtEOF);"); println(""); } println(" }"); println(" catch (java.io.FileNotFoundException e) {"); println(" System.out.println(\"File not found : \\\"\"+argv[i]+\"\\\"\");"); println(" }"); println(" catch (java.io.IOException e) {"); println(" System.out.println(\"IO error scanning file \\\"\"+argv[i]+\"\\\"\");"); println(" System.out.println(e);"); println(" }"); println(" catch (Exception e) {"); println(" System.out.println(\"Unexpected exception:\");"); println(" e.printStackTrace();"); println(" }"); println(" }"); println(" }"); println(" }"); println(""); } private void emitNoMatch() { println(" zzScanError(ZZ_NO_MATCH);"); } private void emitNextInput() { println(" if (zzCurrentPosL < zzEndReadL) {"); println(" zzInput = Character.codePointAt(zzBufferL, zzCurrentPosL, zzEndReadL);"); println(" zzCurrentPosL += Character.charCount(zzInput);"); println(" }"); println(" else if (zzAtEOF) {"); println(" zzInput = YYEOF;"); println(" break zzForAction;"); println(" }"); println(" else {"); println(" // store back cached positions"); println(" zzCurrentPos = zzCurrentPosL;"); println(" zzMarkedPos = zzMarkedPosL;"); println(" boolean eof = zzRefill();"); println(" // get translated positions and possibly new buffer"); println(" zzCurrentPosL = zzCurrentPos;"); println(" zzMarkedPosL = zzMarkedPos;"); println(" zzBufferL = zzBuffer;"); println(" zzEndReadL = zzEndRead;"); println(" if (eof) {"); println(" zzInput = YYEOF;"); println(" break zzForAction;"); println(" }"); println(" else {"); println(" zzInput = Character.codePointAt(zzBufferL, zzCurrentPosL, zzEndReadL);"); println(" zzCurrentPosL += Character.charCount(zzInput);"); println(" }"); println(" }"); } public static String sourceFileString(File file) { String path = FileUtils.getRelativePath(Options.getRootDirectory(), file); if (File.separatorChar == '\\') { path = FileUtils.slashify(path); } // Character '\' can be use for Unicode representation, e.g. \\u000A is new line return path.replace("\\", "\\\\"); } private void emitHeader() { println("// DO NOT EDIT"); println("// Generated by JFlex " + Build.VERSION + " http://jflex.de/"); println("// source: " + sourceFileString(inputFile)); println(""); } private void emitUserCode() { println(scanner.userCode()); if (scanner.cup2Compatible()) { println(); println("/* CUP2 imports */"); println("import edu.tum.cup2.scanner.*;"); println("import edu.tum.cup2.grammar.*;"); println(); } } private void emitClassName() { // TODO(#222) Actually fix the fall-through violations println("// See https://github.com/jflex-de/jflex/issues/222"); println("@SuppressWarnings(\"FallThrough\")"); if (scanner.isPublic()) print("public "); if (scanner.isAbstract()) print("abstract "); if (scanner.isFinal()) print("final "); print("class "); print(scanner.className()); if (scanner.isExtending() != null) { print(" extends "); print(scanner.isExtending()); } if (scanner.isImplementing() != null) { print(" implements "); print(scanner.isImplementing()); } println(" {"); }
Try to find out if user code ends with a javadoc comment, maybe followed by one or more annotations
Params:
  • usercode – the user code
Returns:true if it ends with a javadoc comment and zero or more annotations
/** * Try to find out if user code ends with a javadoc comment, maybe followed by one or more * annotations * * @param usercode the user code * @return true if it ends with a javadoc comment and zero or more annotations */
static boolean endsWithJavadoc(CharSequence usercode) { Matcher matcher = JAVADOC_COMMENT_AND_MAYBE_ANNOTATIONS_PATTERN.matcher(usercode); return matcher.matches() && !matcher.group(1).contains("*/"); } private void emitLexicalStates() { for (String name : scanner.stateNames()) { int num = scanner.getStateNumber(name); println(" " + visibility + " static final int " + name + " = " + 2 * num + ";"); } // can't quite get rid of the indirection, even for non-bol lex states: // their DFA states might be the same, but their EOF actions might be different // (see bug #1540228) println(""); println(" /**"); println(" * ZZ_LEXSTATE[l] is the state in the DFA for the lexical state l"); println(" * ZZ_LEXSTATE[l+1] is the state in the DFA for the lexical state l"); println(" * at the beginning of a line"); println(" * l is of the form l = 2*k, k a non negative integer"); println(" */"); println(" private static final int ZZ_LEXSTATE[] = {"); int i, j = 0; print(" "); for (i = 0; i < 2 * dfa.numLexStates() - 1; i++) { print(dfa.entryState(i), 2); print(", "); if (++j >= 16) { println(); print(" "); j = 0; } } println(dfa.entryState(i)); println(" };"); } private void emitDynamicInit() { int count = 0; int value = dfa.table(0, 0); println(" /**"); println(" * The transition table of the DFA"); println(" */"); CountEmitter e = new CountEmitter("Trans"); e.setValTranslation(+1); // allow vals in [-1, 0xFFFE] e.emitInit(); for (int i = 0; i < dfa.numStates(); i++) { if (!rowKilled[i]) { for (int c = 0; c < dfa.numInput(); c++) { if (!colKilled[c]) { if (dfa.table(i, c) == value) { count++; } else { e.emit(count, value); count = 1; value = dfa.table(i, c); } } } } } e.emit(count, value); e.emitUnpack(); println(e.toString()); } private void emitCharMapArrayUnPacked() { CharClasses cl = parser.getCharClasses(); println(""); println(" /**"); println(" * Translates characters to character classes"); println(" */"); println(" private static final char [] ZZ_CMAP = {"); int n = 0; // numbers of entries in current line print(" "); int max = cl.getMaxCharCode(); // not very efficient, but good enough for <= 255 characters for (char c = 0; c <= max; c++) { print(colMap[cl.getClassCode(c)], 2); if (c < max) { print(", "); if (++n >= 16) { println(); print(" "); n = 0; } } } println(); println(" };"); println(); }
Performs an in-place update to map the colMap translation over the char classes in the second-level cmap table.
/** * Performs an in-place update to map the colMap translation over the char classes in the * second-level cmap table. */
private void mapColMap(int[] blocks) { for (int i = 0; i < blocks.length; i++) { blocks[i] = colMap[blocks[i]]; } }
Emits two-level character translation tables. The translation is from raw input codepoint to the column in the generated DFA table.

For maxCharCode < 256, a single-level unpacked array is used instead.

/** * Emits two-level character translation tables. The translation is from raw input codepoint to * the column in the generated DFA table. * * <p>For maxCharCode < 256, a single-level unpacked array is used instead. */
private void emitCharMapTables() { CharClasses cl = parser.getCharClasses(); if (cl.getMaxCharCode() < 256) { emitCharMapArrayUnPacked(); } else { Pair<int[], int[]> tables = cl.getTables(); mapColMap(tables.snd); println(""); println(" /**"); println(" * Top-level table for translating characters to character classes"); println(" */"); CountEmitter e = new CountEmitter("cmap_top"); e.emitInit(); e.emitCountValueString(tables.fst); e.emitUnpack(); println(e.toString()); println(""); println(" /**"); println(" * Second-level tables for translating characters to character classes"); println(" */"); e = new CountEmitter("cmap_blocks"); e.emitInit(); e.emitCountValueString(tables.snd); e.emitUnpack(); println(e.toString()); } } private void emitRowMapArray() { println(""); println(" /**"); println(" * Translates a state to a row index in the transition table"); println(" */"); HiLowEmitter e = new HiLowEmitter("RowMap"); e.emitInit(); for (int i = 0; i < dfa.numStates(); i++) { e.emit(rowMap[i] * numCols); } e.emitUnpack(); println(e.toString()); } private void emitAttributes() { // TODO(lsf): refactor to use CountEmitter.emitCountValueString println(" /**"); println(" * ZZ_ATTRIBUTE[aState] contains the attributes of state {@code aState}"); println(" */"); CountEmitter e = new CountEmitter("Attribute"); e.emitInit(); int count = 1; int value = 0; if (dfa.isFinal(0)) value = FINAL; if (!isTransition[0]) value |= NOLOOK; for (int i = 1; i < dfa.numStates(); i++) { int attribute = 0; if (dfa.isFinal(i)) attribute = FINAL; if (!isTransition[i]) attribute |= NOLOOK; if (value == attribute) { count++; } else { e.emit(count, value); count = 1; value = attribute; } } e.emit(count, value); e.emitUnpack(); println(e.toString()); } private void emitClassCode() { if (scanner.classCode() != null) { println(" /* user code: */"); println(scanner.classCode()); } if (scanner.cup2Compatible()) { // convenience methods for CUP2 println(); println(" /* CUP2 code: */"); println(" private <T> ScannerToken<T> token(Terminal terminal, T value) {"); println(" return new ScannerToken<T>(terminal, value, yyline, yycolumn);"); println(" }"); println(); println(" private ScannerToken<Object> token(Terminal terminal) {"); println(" return new ScannerToken<Object>(terminal, yyline, yycolumn);"); println(" }"); println(); } } private void emitConstructorDecl() { emitConstructorDecl(true); if ((scanner.standalone() || scanner.debugOption()) && scanner.ctorArgsCount() > 0) { Out.warning(ErrorMessages.get(ErrorMessages.CTOR_DEBUG)); println(); emitConstructorDecl(false); } } private void emitConstructorDecl(boolean printCtorArgs) { println(" /**"); println(" * Creates a new scanner"); println(" *"); println(" * @param in the java.io.Reader to read input from."); println(" */"); String warn = "// WARNING: this is a default constructor for " + "debug/standalone only. Has no custom parameters or init code."; if (!printCtorArgs) println(warn); print(" "); if (scanner.isPublic()) print("public "); print(getBaseName(scanner.className())); print("(java.io.Reader in"); if (printCtorArgs) emitCtorArgs(); print(")"); if (scanner.initThrow() != null && printCtorArgs) { print(" throws "); print(scanner.initThrow()); } println(" {"); if (scanner.initCode() != null && printCtorArgs) { print(" "); print(scanner.initCode()); } println(" this.zzReader = in;"); println(" }"); println(); } private void emitCtorArgs() { for (int i = 0; i < scanner.ctorArgsCount(); i++) { print(", " + scanner.ctorType(i)); print(" " + scanner.ctorArg(i)); } } private void emitDoEOF() { if (eofCode == null) return; println(" /**"); println(" * Contains user EOF-code, which will be executed exactly once,"); println(" * when the end of file is reached"); println(" */"); print(" private void zzDoEOF()"); if (eofThrow != null) { print(" throws "); print(eofThrow); } println(" {"); println(" if (!zzEOFDone) {"); println(" zzEOFDone = true;"); println(" "); print(/* */ eofCode); println(" }"); println(" }"); println(""); println(""); } private void emitLexFunctHeader(String functionName) { if (scanner.cupCompatible() || scanner.cup2Compatible()) { print(" @Override"); // force public, because we have to implement cup/cup2 interface print(" public "); } else { print(" " + visibility + " "); } if (scanner.tokenType() == null) { if (scanner.isInteger()) print("int"); else if (scanner.isIntWrap()) print("Integer"); else print("Yytoken"); } else print(scanner.tokenType()); print(" "); print(functionName); print("() throws java.io.IOException"); if (scanner.lexThrow() != null) { print(", "); print(scanner.lexThrow()); } if (scanner.scanErrorException() != null) { print(", "); print(scanner.scanErrorException()); } println(" {"); skel.emitNext(); println(" int [] zzTransL = ZZ_TRANS;"); println(" int [] zzRowMapL = ZZ_ROWMAP;"); println(" int [] zzAttrL = ZZ_ATTRIBUTE;"); skel.emitNext(); if (scanner.charCount()) { println(" yychar+= zzMarkedPosL-zzStartRead;"); println(""); } if (scanner.lineCount() || scanner.columnCount()) { println(" boolean zzR = false;"); println(" int zzCh;"); println(" int zzCharCount;"); println(" for (zzCurrentPosL = zzStartRead ;"); println(" zzCurrentPosL < zzMarkedPosL ;"); println(" zzCurrentPosL += zzCharCount ) {"); println(" zzCh = Character.codePointAt(zzBufferL, zzCurrentPosL, zzMarkedPosL);"); println(" zzCharCount = Character.charCount(zzCh);"); println(" switch (zzCh) {"); println(" case '\\u000B': // fall through"); println(" case '\\u000C': // fall through"); println(" case '\\u0085': // fall through"); println(" case '\\u2028': // fall through"); println(" case '\\u2029':"); if (scanner.lineCount()) println(" yyline++;"); if (scanner.columnCount()) println(" yycolumn = 0;"); println(" zzR = false;"); println(" break;"); println(" case '\\r':"); if (scanner.lineCount()) println(" yyline++;"); if (scanner.columnCount()) println(" yycolumn = 0;"); println(" zzR = true;"); println(" break;"); println(" case '\\n':"); println(" if (zzR)"); println(" zzR = false;"); println(" else {"); if (scanner.lineCount()) println(" yyline++;"); if (scanner.columnCount()) println(" yycolumn = 0;"); println(" }"); println(" break;"); println(" default:"); println(" zzR = false;"); if (scanner.columnCount()) println(" yycolumn += zzCharCount;"); println(" }"); println(" }"); println(); if (scanner.lineCount()) { println(" if (zzR) {"); println(" // peek one character ahead if it is"); println(" // (if we have counted one line too much)"); println(" boolean zzPeek;"); println(" if (zzMarkedPosL < zzEndReadL)"); println(" zzPeek = zzBufferL[zzMarkedPosL] == '\\n';"); println(" else if (zzAtEOF)"); println(" zzPeek = false;"); println(" else {"); println(" boolean eof = zzRefill();"); println(" zzEndReadL = zzEndRead;"); println(" zzMarkedPosL = zzMarkedPos;"); println(" zzBufferL = zzBuffer;"); println(" if (eof)"); println(" zzPeek = false;"); println(" else"); println(" zzPeek = zzBufferL[zzMarkedPosL] == '\\n';"); println(" }"); println(" if (zzPeek) yyline--;"); println(" }"); } } if (scanner.bolUsed()) { // zzMarkedPos > zzStartRead <=> last match was not empty // if match was empty, last value of zzAtBOL can be used // zzStartRead is always >= 0 println(" if (zzMarkedPosL > zzStartRead) {"); println(" switch (zzBufferL[zzMarkedPosL-1]) {"); println(" case '\\n':"); println(" case '\\u000B': // fall through"); println(" case '\\u000C': // fall through"); println(" case '\\u0085': // fall through"); println(" case '\\u2028': // fall through"); println(" case '\\u2029': // fall through"); println(" zzAtBOL = true;"); println(" break;"); println(" case '\\r': "); println(" if (zzMarkedPosL < zzEndReadL)"); println(" zzAtBOL = zzBufferL[zzMarkedPosL] != '\\n';"); println(" else if (zzAtEOF)"); println(" zzAtBOL = false;"); println(" else {"); println(" boolean eof = zzRefill();"); println(" zzMarkedPosL = zzMarkedPos;"); println(" zzEndReadL = zzEndRead;"); println(" zzBufferL = zzBuffer;"); println(" if (eof) "); println(" zzAtBOL = false;"); println(" else "); println(" zzAtBOL = zzBufferL[zzMarkedPosL] != '\\n';"); println(" }"); println(" break;"); println(" default:"); println(" zzAtBOL = false;"); println(" }"); println(" }"); } skel.emitNext(); if (scanner.bolUsed()) { println(" if (zzAtBOL)"); println(" zzState = ZZ_LEXSTATE[zzLexicalState+1];"); println(" else"); println(" zzState = ZZ_LEXSTATE[zzLexicalState];"); println(); } else { println(" zzState = ZZ_LEXSTATE[zzLexicalState];"); println(); } println(" // set up zzAction for empty match case:"); println(" int zzAttributes = zzAttrL[zzState];"); println(" if ( (zzAttributes & 1) == 1 ) {"); println(" zzAction = zzState;"); println(" }"); println(); skel.emitNext(); } private void emitCMapAccess() { println(" /**"); println(" * Translates raw input code points to DFA table row"); println(" */"); println(" private static int zzCMap(int input) {"); if (parser.getCharClasses().getMaxCharCode() <= 0xFF) { println(" return ZZ_CMAP[input];"); } else { println(" int offset = input & " + (CMapBlock.BLOCK_SIZE - 1) + ";"); println( " return offset == input ? ZZ_CMAP_BLOCKS[offset] : ZZ_CMAP_BLOCKS[ZZ_CMAP_TOP[input >> " + CMapBlock.BLOCK_BITS + "] | offset];"); } println(" }"); } private void emitGetRowMapNext() { println(" int zzNext = zzTransL[ zzRowMapL[zzState] + zzCMap(zzInput) ];"); println(" if (zzNext == " + DFA.NO_TARGET + ") break zzForAction;"); println(" zzState = zzNext;"); println(); println(" zzAttributes = zzAttrL[zzState];"); println(" if ( (zzAttributes & " + FINAL + ") == " + FINAL + " ) {"); skel.emitNext(); println( " if ( (zzAttributes & " + NOLOOK + ") == " + NOLOOK + " ) break zzForAction;"); skel.emitNext(); }
Escapes all " ' \ tabs and newlines
Params:
  • s – The string to escape
Returns:The escaped string
/** * Escapes all " ' \ tabs and newlines * * @param s The string to escape * @return The escaped string */
private static String escapify(String s) { StringBuilder result = new StringBuilder(s.length() * 2); for (int i = 0; i < s.length(); i++) { char c = s.charAt(i); switch (c) { case '\'': result.append("\\\'"); break; case '\"': result.append("\\\""); break; case '\\': result.append("\\\\"); break; case '\t': result.append("\\t"); break; case '\r': if (i + 1 == s.length() || s.charAt(i + 1) != '\n') result.append("\"+ZZ_NL+\""); break; case '\n': result.append("\"+ZZ_NL+\""); break; default: result.append(c); } } return result.toString(); }
emitActionTable.
/** emitActionTable. */
private void emitActionTable() { int lastAction = 1; int count = 0; int value = 0; println(" /**"); println(" * Translates DFA states to action switch labels."); println(" */"); CountEmitter e = new CountEmitter("Action"); e.emitInit(); for (int i = 0; i < dfa.numStates(); i++) { int newVal = 0; if (dfa.isFinal(i)) { Action action = dfa.action(i); if (action.isEmittable()) { Integer stored = actionTable.get(action); if (stored == null) { stored = lastAction++; actionTable.put(action, stored); } newVal = stored; } } if (value == newVal) { count++; } else { if (count > 0) e.emit(count, value); count = 1; value = newVal; } } if (count > 0) e.emit(count, value); e.emitUnpack(); println(e.toString()); } private void emitActions() { println(" switch (zzAction < 0 ? zzAction : ZZ_ACTION[zzAction]) {"); int i = actionTable.size() + 1; for (Map.Entry<Action, Integer> entry : actionTable.entrySet()) { Action action = entry.getKey(); int label = entry.getValue(); println(" case " + label + ":"); if (action.lookAhead() == Action.FIXED_BASE) { println(" // lookahead expression with fixed base length"); println(" zzMarkedPos = Character.offsetByCodePoints"); println( " (zzBufferL, zzStartRead, zzEndRead - zzStartRead, zzStartRead, " + action.getLookLength() + ");"); } if (action.lookAhead() == Action.FIXED_LOOK || action.lookAhead() == Action.FINITE_CHOICE) { println(" // lookahead expression with fixed lookahead length"); println(" zzMarkedPos = Character.offsetByCodePoints"); println( " (zzBufferL, zzStartRead, zzEndRead - zzStartRead, zzMarkedPos, -" + action.getLookLength() + ");"); } if (action.lookAhead() == Action.GENERAL_LOOK) { println(" // general lookahead, find correct zzMarkedPos"); println(" { int zzFState = " + dfa.entryState(action.getEntryState()) + ";"); println(" int zzFPos = zzStartRead;"); println(" if (zzFin.length <= zzBufferL.length) {"); println(" zzFin = new boolean[zzBufferL.length+1];"); println(" }"); println(" boolean zzFinL[] = zzFin;"); println(" while (zzFState != -1 && zzFPos < zzMarkedPos) {"); println(" zzFinL[zzFPos] = ((zzAttrL[zzFState] & 1) == 1);"); println(" zzInput = Character.codePointAt(zzBufferL, zzFPos, zzMarkedPos);"); println(" zzFPos += Character.charCount(zzInput);"); println(" zzFState = zzTransL[ zzRowMapL[zzFState] + zzCMap(zzInput) ];"); println(" }"); println(" if (zzFState != -1) {"); println(" zzFinL[zzFPos++] = ((zzAttrL[zzFState] & 1) == 1);"); println(" }"); println(" while (zzFPos <= zzMarkedPos) {"); println(" zzFinL[zzFPos++] = false;"); println(" }"); println(); println(" zzFState = " + dfa.entryState(action.getEntryState() + 1) + ";"); println(" zzFPos = zzMarkedPos;"); println(" while (!zzFinL[zzFPos] || (zzAttrL[zzFState] & 1) != 1) {"); println( " zzInput = Character.codePointBefore(zzBufferL, zzFPos, zzStartRead);"); println(" zzFPos -= Character.charCount(zzInput);"); println(" zzFState = zzTransL[ zzRowMapL[zzFState] + zzCMap(zzInput) ];"); println(" };"); println(" zzMarkedPos = zzFPos;"); println(" }"); } if (scanner.debugOption()) { print(" System.out.println("); if (scanner.lineCount()) print("\"line: \"+(yyline+1)+\" \"+"); if (scanner.columnCount()) print("\"col: \"+(yycolumn+1)+\" \"+"); if (scanner.charCount()) print("\"char: \"+yychar+\" \"+"); println("\"match: --\"+zzToPrintable(yytext())+\"--\");"); print(" System.out.println(\"action [" + action.priority + "] { "); print(escapify(action.content)); println(" }\");"); } println(" { " + action.content); println(" }"); println(" // fall through"); println(" case " + (i++) + ": break;"); } } private void emitEOFVal() { EOFActions eofActions = parser.getEOFActions(); if (eofCode != null) println(" zzDoEOF();"); if (eofActions.numActions() > 0) { println(" switch (zzLexicalState) {"); // pick a start value for break case labels. // must be larger than any value of a lex state: int last = dfa.numStates(); for (String name : scanner.stateNames()) { int num = scanner.getStateNumber(name); Action action = eofActions.getAction(num); if (action != null) { println(" case " + name + ": {"); if (scanner.debugOption()) { print(" System.out.println("); if (scanner.lineCount()) print("\"line: \"+(yyline+1)+\" \"+"); if (scanner.columnCount()) print("\"col: \"+(yycolumn+1)+\" \"+"); if (scanner.charCount()) print("\"char: \"+yychar+\" \"+"); println("\"match: <<EOF>>\");"); print(" System.out.println(\"action [" + action.priority + "] { "); print(escapify(action.content)); println(" }\");"); } println(" " + action.content); println(" } // fall though"); println(" case " + (++last) + ": break;"); } } println(" default:"); } Action defaultAction = eofActions.getDefault(); if (defaultAction != null) { println(" {"); if (scanner.debugOption()) { print(" System.out.println("); if (scanner.lineCount()) print("\"line: \"+(yyline+1)+\" \"+"); if (scanner.columnCount()) print("\"col: \"+(yycolumn+1)+\" \"+"); if (scanner.charCount()) print("\"char: \"+yychar+\" \"+"); println("\"match: <<EOF>>\");"); print(" System.out.println(\"action [" + defaultAction.priority + "] { "); print(escapify(defaultAction.content)); println(" }\");"); } println(" " + defaultAction.content); println(" }"); } else if (scanner.eofVal() != null) println(" { " + scanner.eofVal() + " }"); else if (scanner.isInteger()) { if (scanner.tokenType() != null) { Out.error(ErrorMessages.INT_AND_TYPE); throw new GeneratorException(); } println(" return YYEOF;"); } else println(" return null;"); if (eofActions.numActions() > 0) println(" }"); } private void findActionStates() { isTransition = new boolean[dfa.numStates()]; for (int i = 0; i < dfa.numStates(); i++) { char j = 0; while (!isTransition[i] && j < dfa.numInput()) isTransition[i] = dfa.table(i, j++) != DFA.NO_TARGET; } } private void reduceColumns() { colMap = new int[dfa.numInput()]; colKilled = new boolean[dfa.numInput()]; int i, j, k; int translate = 0; boolean equal; numCols = dfa.numInput(); for (i = 0; i < dfa.numInput(); i++) { colMap[i] = i - translate; for (j = 0; j < i; j++) { // test for equality: k = -1; equal = true; while (equal && ++k < dfa.numStates()) equal = dfa.table(k, i) == dfa.table(k, j); if (equal) { translate++; colMap[i] = colMap[j]; colKilled[i] = true; numCols--; break; } // if } // for j } // for i } private void reduceRows() { rowMap = new int[dfa.numStates()]; rowKilled = new boolean[dfa.numStates()]; int i, j, k; int translate = 0; boolean equal; // i is the state to add to the new table for (i = 0; i < dfa.numStates(); i++) { rowMap[i] = i - translate; // check if state i can be removed (i.e. already // exists in entries 0..i-1) for (j = 0; j < i; j++) { // test for equality: k = -1; equal = true; while (equal && ++k < dfa.numInput()) equal = dfa.table(i, k) == dfa.table(j, k); if (equal) { translate++; rowMap[i] = rowMap[j]; rowKilled[i] = true; break; } // if } // for j } // for i }
Set up EOF code section according to scanner.eofcode
/** Set up EOF code section according to scanner.eofcode */
private void setupEOFCode() { if (scanner.eofclose()) { eofCode = LexScan.conc(scanner.eofCode(), " yyclose();"); eofThrow = LexScan.concExc(scanner.eofThrow(), "java.io.IOException"); } else { eofCode = scanner.eofCode(); eofThrow = scanner.eofThrow(); } }
Emit yychar, yycolumn, zzAtBOL, zzEOFDone with warning suppression when needed.
/** * Emit {@code yychar}, {@code yycolumn}, {@code zzAtBOL}, {@code zzEOFDone} with warning * suppression when needed. */
private void emitVarDefs() { // We can't leave out these declarations completely, even if unused, because // the reset functions in the skeleton refer to them. They are written to, // but not read. Only other option would be to pull these out of the skeleton // as well. println(" /** Number of newlines encountered up to the start of the matched text. */"); if (!scanner.lineCount()) { println(" @SuppressWarnings(\"unused\")"); } println(" private int yyline;"); println(); println( " /** Number of characters from the last newline up to the start of the matched text. */"); if (!scanner.columnCount()) { println(" @SuppressWarnings(\"unused\")"); } println(" private int yycolumn;"); println(); println(" /** Number of characters up to the start of the matched text. */"); if (!scanner.charCount()) { println(" @SuppressWarnings(\"unused\")"); } println(" private long yychar;"); println(); println(" /** Whether the scanner is currently at the beginning of a line. */"); if (!scanner.bolUsed()) { println(" @SuppressWarnings(\"unused\")"); } println(" private boolean zzAtBOL = true;"); println(); println(" /** Whether the user-EOF-code has already been executed. */"); if (eofCode == null) { println(" @SuppressWarnings(\"unused\")"); } println(" private boolean zzEOFDone;"); println(); }
Main Emitter method.
/** Main Emitter method. */
public void emit() { String functionName = (scanner.functionName() != null) ? scanner.functionName() : "yylex"; setupEOFCode(); reduceColumns(); findActionStates(); emitHeader(); emitUserCode(); emitClassName(); skel.emitNext(); println(" private static final int ZZ_BUFFERSIZE = " + scanner.bufferSize() + ";"); if (scanner.debugOption()) { println(" private static final String ZZ_NL = System.getProperty(\"line.separator\");"); } skel.emitNext(); emitLexicalStates(); emitCharMapTables(); emitActionTable(); reduceRows(); emitRowMapArray(); emitDynamicInit(); skel.emitNext(); emitAttributes(); skel.emitNext(); emitLookBuffer(); emitVarDefs(); emitClassCode(); skel.emitNext(); emitConstructorDecl(); if (scanner.debugOption()) { println(""); println(" private static String zzToPrintable(String str) {"); println(" StringBuilder builder = new StringBuilder();"); println(" for (int n = 0 ; n < str.length() ; ) {"); println(" int ch = str.codePointAt(n);"); println(" int charCount = Character.charCount(ch);"); println(" n += charCount;"); println(" if (ch > 31 && ch < 127) {"); println(" builder.append((char)ch);"); println(" } else if (charCount == 1) {"); println(" builder.append(String.format(\"\\\\u%04X\", ch));"); println(" } else {"); println(" builder.append(String.format(\"\\\\U%06X\", ch));"); println(" }"); println(" }"); println(" return builder.toString();"); println(" }"); } emitCMapAccess(); skel.emitNext(); emitScanError(); skel.emitNext(); emitDoEOF(); skel.emitNext(); emitLexFunctHeader(functionName); emitNextInput(); emitGetRowMapNext(); skel.emitNext(); emitEOFVal(); skel.emitNext(); emitActions(); skel.emitNext(); emitNoMatch(); skel.emitNext(); emitMain(functionName); skel.emitNext(); out.close(); } }