24 std::cout <<
"Phasor C++ Code Generator\n";
25 std::cout <<
"Copyright (c) 2026 Daniel McGuire\n";
36 std::cerr <<
"Error: No input file provided\n";
37 std::cerr <<
"Use --help for usage information\n";
43 m_args.mainFile =
"C:\\Program Files\\Phasor VM\\Development\\nativestub.cpp";
45 m_args.mainFile =
"/usr/local/share/phasor/dev/nativestub.cpp";
48 if (
m_args.moduleName.empty())
50 std::filesystem::path inputPath(
m_args.inputFile);
51 m_args.moduleName = inputPath.stem().string();
55 if (
m_args.outputFile.empty())
66 std::cout <<
"Input file: " <<
m_args.inputFile <<
"\n";
67 std::cout <<
"Output file: " <<
m_args.outputFile <<
"\n";
68 if (!
m_args.moduleName.empty())
69 std::cout <<
"Module name: " <<
m_args.moduleName <<
"\n";
94 std::cout <<
"Generating wrapper...\n";
97 std::cout <<
m_args.inputFile <<
" -> " <<
m_args.moduleName +
".h\n";
100 std::cerr <<
"Error: Could not generate header file\n";
105 std::cout <<
m_args.mainFile.filename() <<
" -> " <<
m_args.moduleName +
".cpp\n\n";
108 std::cerr <<
"Could not generate source file\n";
112 std::cout <<
"Compiling...\n";
113 std::cout <<
"[COMPILER] ";
115 std::cout <<
m_args.moduleName +
".cpp -> " <<
m_args.moduleName +
".obj\n\n";
118 std::cerr <<
"Could not compile program\n";
122 std::cout <<
"Linking...\n";
123 std::cout <<
"[LINKER] ";
125 std::cout <<
m_args.moduleName +
".obj -> " <<
m_args.outputFile <<
"\n";
128 std::cerr <<
"Could not link program\n";
137 for (
int i = 1; i < argc; i++)
139 std::string arg = argv[i];
141 if (arg ==
"-h" || arg ==
"--help")
146 else if (arg ==
"-v" || arg ==
"--verbose")
150 else if (arg ==
"-o" || arg ==
"--output")
154 m_args.outputFile = argv[++i];
158 std::cerr <<
"Error: " << arg <<
" requires an argument\n";
163 else if (arg ==
"-n" || arg ==
"--nologo")
167 else if (arg ==
"-H" || arg ==
"--header-only")
171 else if (arg ==
"-g" || arg ==
"--generate-only")
173 m_args.generateOnly =
true;
175 else if (arg ==
"-O" || arg ==
"--object-only")
179 else if (arg ==
"-m" || arg ==
"--module")
183 m_args.moduleName = argv[++i];
187 std::cerr <<
"Error: " << arg <<
" requires an argument\n";
192 else if (arg ==
"-c" || arg ==
"--compiler")
196 m_args.compiler = argv[++i];
201 else if ((
m_args.compiler ==
"clang" ||
m_args.compiler ==
"clang++") &&
m_args.linker.empty())
205 else if ((
m_args.compiler ==
"gcc" ||
m_args.compiler ==
"g++") &&
m_args.linker.empty())
212 std::cerr <<
"Error: " << arg <<
" requires an argument\n";
217 else if (arg ==
"-l" || arg ==
"--linker")
221 m_args.linker = argv[++i];
225 std::cerr <<
"Error: " << arg <<
" requires an argument\n";
230 else if (arg ==
"-s" || arg ==
"--source")
232 m_args.mainFile = argv[++i];
234 else if (arg[0] ==
'-')
236 std::cerr <<
"Error: Unknown option: " << arg <<
"\n";
243 if (
m_args.inputFile.empty())
247 std::cerr <<
"Error: Multiple input files specified\n";
258 std::cout <<
"Usage:\n";
259 std::cout <<
" " << programName <<
" [options] <input.phs>\n\n";
260 std::cout <<
"Options:\n";
261 std::cout <<
" -c, --compiler <name> Compiler to use (default: g++)\n";
262 std::cout <<
" -l, --linker <name> Linker to use (default: g++)\n";
263 std::cout <<
" -s, --source <name> The source file to compile with\n";
264 std::cout <<
" -o, --output <file> Output file\n";
265 std::cout <<
" -m, --module <name> Module name for generated code (default: input filename)\n";
266 std::cout <<
" -H, --header-only Generate header file only\n";
267 std::cout <<
" -g, --generate-only Generate source file only\n";
268 std::cout <<
" -O, --object-only Generate and compile to object only\n";
269 std::cout <<
" -v, --verbose Enable verbose output\n";
270 std::cout <<
" -h, --help Show this help message\n";
271 std::cout <<
" -n, --nologo Do not show banner\n\n";
272 std::cout <<
"Example:\n";
273 std::cout <<
" " << programName <<
" program.phs -o program.exe -c clang++ -l lld\n";
274 std::cout <<
" " << programName <<
" -O program.phs -o program.obj -c clang++\n";
275 std::cout <<
" " << programName <<
" -H program.phs -o program.hpp\n";
276 std::cout <<
" " << programName <<
" -g program.phs -o program.cpp\n";
285 if (sourcePath.extension() ==
".phir")
292 std::cout <<
"Reading source file...\n";
294 std::ifstream file(sourcePath);
297 std::cerr <<
"Error: Could not open input file: " << sourcePath <<
"\n";
301 std::stringstream buffer;
302 buffer << file.rdbuf();
303 std::string source = buffer.str();
308 std::cout <<
"Lexing...\n";
315 std::cout <<
"Parsing...\n";
318 auto program = parser.
parse();
322 std::cout <<
"Generating bytecode...\n";
325 bytecode = codegen.
generate(*program);
330 std::cerr <<
"Error: No instructions generated\n";
336 std::cout <<
"Bytecode statistics:\n";
337 std::cout <<
" Instructions: " << bytecode.
instructions.size() <<
"\n";
338 std::cout <<
" Constants: " << bytecode.
constants.size() <<
"\n";
339 std::cout <<
" Variables: " << bytecode.
variables.size() <<
"\n";
340 std::cout <<
" Functions: " << bytecode.
functionEntries.size() <<
"\n";
345 std::cout <<
"Generating C++ code...\n";
348 bool success = cppGen.
generate(bytecode, outputPath,
m_args.moduleName);
352 std::cerr <<
"Error: Failed to generate C++ code\n";
357 std::cout <<
"Successfully generated: " << outputPath <<
"\n";
359 catch (
const std::exception &e)
361 std::cerr <<
"Compilation Error: " << e.what() <<
"\n";
369 std::ifstream file(sourcePath);
372 std::cerr <<
"Error: Could not open input file: " << sourcePath <<
"\n";
376 std::stringstream buffer;
377 buffer << file.rdbuf();
378 std::string source = buffer.str();
381 std::ofstream outputFile(outputPath);
382 if (!outputFile.is_open())
384 std::cerr <<
"Error: Could not open output file: " << outputPath <<
"\n";
389 std::filesystem::path headerPath = outputPath;
390 headerPath.replace_extension(
".h");
392 outputFile <<
"#include \"" << headerPath.filename().string() <<
"\"\n";
393 outputFile << source;
401 std::vector<std::string> flags;
402 if (
m_args.compiler ==
"cl")
403 flags = {
"/std:c++20",
"/Ox",
"/D",
"NDEBUG",
"/MD",
"/GL",
"/Gy-",
404 "/GS-",
"/Gw",
"/EHsc",
"/WX-",
"/nologo",
"/c", (
"/Fo" + outputPath.string())};
405 else if (
m_args.compiler ==
"g++" ||
m_args.compiler ==
"clang++")
406 flags = {
"-std=c++20",
411 "-fno-function-sections",
412 "-fno-stack-protector",
417 (
"-o" + outputPath.string())};
421 std::cerr <<
"Error: Unknown compiler: " <<
m_args.compiler <<
"\n";
425 std::string command =
m_args.compiler;
426 for (
const auto &flag : flags)
428 command +=
" " + flag;
431 command +=
" " + sourcePath.string();
432 if (std::system(command.c_str()) != 0)
434 std::cerr <<
"Error: Compilation failed\n";
443 std::string command =
m_args.linker;
444 command +=
" " + objectPath.string();
445 if (
m_args.linker ==
"link")
446 command +=
" /NOLOGO /LTCG /OPT:REF /OPT:ICF /INCREMENTAL:NO /out:" + outputPath.string();
447 else if (
m_args.linker ==
"ld" ||
m_args.linker ==
"clang++" ||
m_args.linker ==
"clang")
448 command +=
"-flto -pthread -Wl,--gc-sections -o " + outputPath.string();
451 std::cerr <<
"Error: Unknown linker: " <<
m_args.linker <<
"\n";
454 return (std::system(command.c_str()) == 0);
Code generator for Phasor VM.
Bytecode generate(const AST::Program &program, const std::map< std::string, int > &existingVars={}, int nextVarIdx=0, bool replMode=false)
Generate bytecode from program.
Generates C++ header files with embedded Phasor bytecode.
bool generate(const Bytecode &bytecode, const std::filesystem::path &outputPath, const std::string &moduleName="")
Generate C++ header file from bytecode.
bool generateSource(const std::filesystem::path &sourcePath, const std::filesystem::path &outputPath)
struct Phasor::CppCompiler::Args m_args
bool parseArguments(int argc, char *argv[])
bool showHelp(const std::string &programName)
bool generateHeader(const std::filesystem::path &sourcePath, const std::filesystem::path &outputPath)
bool linkObject(const std::filesystem::path &objectPath, const std::filesystem::path &outputPath)
bool compileSource(const std::filesystem::path &sourcePath, const std::filesystem::path &outputPath)
CppCompiler(int argc, char *argv[])
std::vector< Token > tokenize()
std::unique_ptr< AST::Program > parse()
Phasor IR Serializer/Deserializer.
static Bytecode loadFromFile(const std::filesystem::path &filename)
Load bytecode from .phir file.
The Phasor Programming Language and Runtime.
Complete bytecode structure.
std::vector< Value > constants
Constant pool.
std::map< std::string, int > functionEntries
Function name -> instruction index mapping.
std::map< std::string, int > variables
Variable name -> index mapping.
std::vector< Instruction > instructions
List of instructions.