public static PcodeProgram compileUserop(SleighLanguage language, String opName,
			List<String> params, String source, PcodeUseropLibrary<?> library,
			List<Varnode> args) {
		PcodeParser parser = createParser(language);
		Map<Integer, UserOpSymbol> symbols = library.getSymbols(language);
		addParserSymbols(parser, symbols);
		SleighBase sleigh = parser.getSleigh();

		int count = params.size();
		if (args.size() != count) {
			throw new IllegalArgumentException("Mismatch of params and args sizes");
		}
		VarnodeSymbol nil = addNilSymbol(parser);
		VarnodeData nilVnData = nil.getFixedVarnode();
		for (int i = 0; i < count; i++) {
			String p = params.get(i);
			Varnode a = args.get(i);
			if (a == null && i == 0) { // Only allow output to be omitted
				parser.addSymbol(new VarnodeSymbol(nil.getLocation(), p, nilVnData.space,
					nilVnData.offset, nilVnData.size));
			}
			else {
				parser.addSymbol(paramSym(language, sleigh, opName, p, a));
			}
		}

		try {
			ConstructTpl template = compileTemplate(language, parser, opName, source);
			return constructProgram(PcodeProgram::new, language, template, symbols);
		}
		catch (Throwable t) {
			Msg.error(SleighProgramCompiler.class, "Error trying to compile userop:\n" + source);
			throw t;
		}
	}
Compile the definition of a p-code userop from Sleigh source into a p-code program

<p>
TODO: Defining a userop from Sleigh source is currently a bit of a hack. It would be nice if
there were a formalization of Sleigh/p-code subroutines. At the moment, the control flow for
subroutines is handled out of band, which actually works fairly well. However, parameter
passing and returning results is not well defined. The current solution is to alias the
parameters to their arguments, implementing a pass-by-reference scheme. Similarly, the output
variable is aliased to the symbol named {@link SleighPcodeUseropDefinition#OUT_SYMBOL_NAME},
which could be problematic if no output variable is given. In this setup, the use of
temporary variables is tenuous, since no provision is made to ensure a subroutine's
allocation of temporary variables do not collide with those of callers lower in the stack.
This could be partly resolved by creating a fresh unique space for each invocation, but then
it becomes necessary to copy values from the caller's to the callee's. If we're strict about
parameters being inputs, this is straightforward. If parameters can be used to communicate
results, then we may need parameter attributes to indicate in, out, or inout. Of course,
having a separate unique space per invocation implies the executor state can't simply have
one unique space. Likely, the {@link PcodeFrame} would come to own its own unique space, but
the {@link PcodeExecutorState} should probably still manufacture it.

@param language the language of the target p-code machine
@param opName the name of the userop (used only for diagnostics here)
@param params the names of parameters in order. Index 0 names the output symbol, probably
           {@link SleighPcodeUseropDefinition#OUT_SYMBOL_NAME}
@param source the Sleigh source
@param library the userop library or stub library for binding userop symbols
@param args the varnode arguments in order. Index 0 is the output varnode.
@return a p-code program that implements the userop for the given arguments
Ghidra/Framework/Emulation/src/main/java/ghidra/pcode/exec/SleighProgramCompiler.java