9. pyxc: File Input Mode
Next: run a complete .pyxc file.
Chapter 8 always reads from stdin. Keep that interactive mode, but add a positional filename:
./build/pyxc program.pyxc
Do not build a second compiler path. The clean boundary is:
stdin or file -> one FILE* -> the same frontend and JIT
Work in:
cd code/chapter-09
9.2 Route Every Character Read through Input
In advance(), replace:
getchar()
with:
fgetc(Input)
Replace newline lookahead reads the same way, and change:
ungetc(NextChar, stdin)
to:
ungetc(NextChar, Input)
This is the only lexer change required. Tokens, locations, diagnostics, parsing, codegen, optimization, and JIT execution remain shared.
9.3 Add the Positional Input Option
Near the existing LLVM command-line options, add:
static cl::opt<string> InputFile(
cl::Positional, cl::desc("[script.pyxc]"),
cl::init(""), cl::cat(PyxcCategory));
This accepts zero or one positional filename:
no filename -> REPL
filename -> file mode
9.4 Add Optional IR Output
Chapter 8 always prints generated IR. Add:
static cl::opt<bool> VerboseIR(
"v", cl::desc("Print generated LLVM IR to stderr"),
cl::init(false), cl::cat(PyxcCategory));
Wrap every successful IR dump:
if (VerboseIR)
FunctionIR->print(errs());
This makes normal program output usable while retaining an inspection mode:
./build/pyxc -v program.pyxc
Keep IR on stderr; runtime output remains on stdout.
9.5 Open the Selected Input
Extend ProcessCommandLine() after parsing and optimization-level validation:
if (!InputFile.empty()) {
Input = fopen(InputFile.c_str(), "r");
if (!Input) {
perror(InputFile.c_str());
return -1;
}
IsRepl = false;
} else {
IsRepl = true;
}
return 0;
Use perror() so a missing file includes the operating system's explanation.
Do this before priming the lexer. getNextToken() must read its first character from the selected stream.
9.6 Centralize REPL-Only Output
Add:
void PrintReplPrompt() {
if (IsRepl) {
fflush(stdout);
fprintf(stderr, "ready> ");
}
}
Replace direct prompt printing with PrintReplPrompt().
Add a REPL-only logging helper:
void Log(const string &Message) {
if (IsRepl)
fprintf(stderr, "%s", Message.c_str());
}
Replace confirmation messages such as:
fprintf(stderr, "Parsed a function definition.\n");
with:
Log("Parsed a function definition.\n");
Do the same for externs and top-level expressions.
Do not suppress diagnostics. Syntax, codegen, and file-opening errors must still be printed in both modes.
9.7 Keep Evaluation Output Explicit
Use one result function:
void PrintEvaluationResult(double Result) {
fprintf(stdout, "Evaluated to %f\n", Result);
}
Call it after executing a top-level anonymous expression.
This is program behavior, not parser chatter. Runtime functions such as printd and putchard also continue writing normally.
9.8 Close the File
After MainLoop() returns, add:
if (Input && Input != stdin) {
fclose(Input);
Input = stdin;
}
Do not close stdin.
9.9 Build and Run the REPL
cmake -S . -B build \
-DLLVM_DIR="$(llvm-config --cmakedir)"
cmake --build build
./build/pyxc
Try:
ready> 1 + 2
Expected:
Parsed a top-level expression.
Evaluated to 3.000000
The REPL behavior should be unchanged except that IR is hidden unless -v is present.
9.10 Run a Source File
Create or use a test file such as:
extern def printd(x)
def square(x): x * x
printd(square(5))
Run:
./build/pyxc program.pyxc
Expected runtime output:
25.000000
Evaluated to 0.000000
There should be no ready> prompt and no “Parsed...” messages.
Inspect the same run with IR:
./build/pyxc -v program.pyxc
Redirect the streams independently when useful:
./build/pyxc -v program.pyxc >program.out 2>program.ll
9.11 Test the Error Boundary
Run a missing file:
./build/pyxc does-not-exist.pyxc
Expected behavior:
does-not-exist.pyxc: <operating-system error>
and a nonzero exit code.
Run the full suite:
llvm-lit -v test/
What you built is one compiler with two input presentations:
REPL mode -> stdin + prompts + confirmations
file mode -> file + quiet compiler presentation
both -> same lexer/parser/codegen/optimizer/JIT
Next: Chapter 10 adds comparisons, if expressions, and for loops.
9.12 Need Help?
Build issues? Questions?
Include:
- Your operating system and version
- The chapter number
- The exact command you ran
- The complete error message
- The output of
c++ --versionandcmake --version - The output of
llvm-config --versionfor Chapter 6 and later