public static <T extends RuleReturnScope> T parseSleigh(ParseFunction<T> nt,
			String text, String follow) {
		LineArrayListWriter writer = new LineArrayListWriter();
		ParsingEnvironment env = new ParsingEnvironment(writer);

		// inject pcode statement lines into writer (needed for error reporting)
		BufferedReader r = new BufferedReader(new StringReader(text));
		String line;
		try {
			while ((line = r.readLine()) != null) {
				writer.write(line);
				writer.newLine();
			}
		}
		catch (IOException e) {
			throw new AssertionError(e);
		}

		String inputText = writer.toString().stripTrailing();
		CharStream input = new ANTLRStringStream(inputText + follow);

		env.getLocator().registerLocation(0, new Location("sleigh", 0));

		SleighLexer lex = new SleighLexer(input);
		lex.setEnv(env);
		UnbufferedTokenStream tokens = new UnbufferedTokenStream(lex);
		List<SleighParseErrorEntry> errors = new ArrayList<>();
		SleighParser parser = new SleighParser(tokens) {
			private void collectError(String[] tokenNames, RecognitionException e) {
				String hdr = getErrorHeader(e);
				String msg = getErrorMessage(e, tokenNames);
				CommonToken ct = (CommonToken) e.token;
				errors.add(new SleighParseErrorEntry(hdr, msg, ct.getStartIndex(),
					ct.getStopIndex()));
			}

			{
				this.gSemanticParser = new SleighParser_SemanticParser(input, state, this) {
					@Override
					public void displayRecognitionError(String[] tokenNames,
							RecognitionException e) {
						collectError(tokenNames, e);
					}

					@Override
					public void emitErrorMessage(String msg) {
						throw new AssertionError();
					}
				};
			}

			@Override
			public void displayRecognitionError(String[] tokenNames, RecognitionException e) {
				collectError(tokenNames, e);
			}

			@Override
			public void emitErrorMessage(String msg) {
				throw new AssertionError();
			}
		};
		parser.setEnv(env);
		parser.setLexer(lex);
		lex.pushMode(SleighRecognizerConstants.SEMANTIC);
		T t;
		try {
			t = nt.apply(parser);
		}
		catch (RecognitionException e) {
			parser.reportError(e);
			return null;
		}
		lex.popMode();

		CommonToken lastTok = (CommonToken) tokens.elementAt(0);
		if (follow.isEmpty()) {
			if (!tokens.isEOF(lastTok)) {
				parser.reportError(new UnwantedTokenException(Token.EOF, tokens));
			}
		}
		else {
			if (inputText.length() != lastTok.getStartIndex()) {
				parser.reportError(new UnwantedTokenException(Token.EOF, tokens));
			}
		}

		if (!errors.isEmpty()) {
			throw new SleighParseError(errors);
		}

		return t;
	}
Parse a non-terminal symbol from the Sleigh semantic grammar

<p>
Because the ANTLR parsing function for the non-terminal symbol depends on the "follows" set
to determine when it has finished, we can't just invoke the function in isolation without
some hacking. If EOF is not in the non-terminal's follows set, then it won't recognize EOF as
completing the non-terminal. Instead, we have to present some token that it will recognize.
Furthermore, regardless of the follow token, we have to check that all of the given input was
consumed by the parser.

@param <T> the type of result from parsing
@param nt the function from the parser implementing the non-terminal symbol
@param text the text to parse
@param follow a token that would ordinarily follow the non-terminal symbol, or empty for EOF
@return the parsed result
Ghidra/Framework/Emulation/src/main/java/ghidra/pcode/exec/SleighUtils.java