mirror of
https://gitlab.com/camelot/kickc.git
synced 2025-02-18 01:30:56 +00:00
Added support for compiling multiple C-files using a single command line. Closes #382
This commit is contained in:
parent
f42a921d2b
commit
1c59ad61fd
@ -8,6 +8,7 @@ import dk.camelot64.kickc.model.statements.StatementSource;
|
|||||||
import dk.camelot64.kickc.model.symbols.Procedure;
|
import dk.camelot64.kickc.model.symbols.Procedure;
|
||||||
import dk.camelot64.kickc.model.values.SymbolRef;
|
import dk.camelot64.kickc.model.values.SymbolRef;
|
||||||
import dk.camelot64.kickc.parser.CParser;
|
import dk.camelot64.kickc.parser.CParser;
|
||||||
|
import dk.camelot64.kickc.parser.KickCLexer;
|
||||||
import dk.camelot64.kickc.parser.KickCParser;
|
import dk.camelot64.kickc.parser.KickCParser;
|
||||||
import dk.camelot64.kickc.passes.*;
|
import dk.camelot64.kickc.passes.*;
|
||||||
import org.antlr.v4.runtime.RuleContext;
|
import org.antlr.v4.runtime.RuleContext;
|
||||||
@ -137,11 +138,16 @@ public class Compiler {
|
|||||||
program.getImportPaths().add(path);
|
program.getImportPaths().add(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Program compile(String fileName) {
|
public Program compile(List<Path> files) {
|
||||||
if(fileName.endsWith(".kc")) {
|
if(files.size()==0)
|
||||||
fileName = fileName.substring(0, fileName.length() - 3);
|
throw new CompileError("Error! You must supply at least one file to compile!");
|
||||||
|
|
||||||
|
final Path primaryFile = files.get(0);
|
||||||
|
String primaryFileName = primaryFile.toString();
|
||||||
|
if(primaryFileName.endsWith(".kc")) {
|
||||||
|
primaryFileName = primaryFileName.substring(0, primaryFileName.length() - 3);
|
||||||
}
|
}
|
||||||
program.setFileName(fileName);
|
program.setPrimaryFileName(primaryFileName);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Path currentPath = new File(".").toPath();
|
Path currentPath = new File(".").toPath();
|
||||||
@ -150,7 +156,13 @@ public class Compiler {
|
|||||||
}
|
}
|
||||||
program.setStatementSequence(new StatementSequence());
|
program.setStatementSequence(new StatementSequence());
|
||||||
CParser cParser = new CParser(program);
|
CParser cParser = new CParser(program);
|
||||||
KickCParser.FileContext cFileContext = cParser.loadAndParseCFile(fileName, currentPath);
|
for(Path file : files) {
|
||||||
|
final KickCLexer fileLexer = cParser.loadCFile(file.toString(), currentPath);
|
||||||
|
cParser.addSourceLast(fileLexer);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse the files
|
||||||
|
KickCParser.FileContext cFileContext = cParser.getParser().file();
|
||||||
|
|
||||||
if(variableBuilderConfig == null) {
|
if(variableBuilderConfig == null) {
|
||||||
VariableBuilderConfig config = new VariableBuilderConfig();
|
VariableBuilderConfig config = new VariableBuilderConfig();
|
||||||
@ -159,7 +171,7 @@ public class Compiler {
|
|||||||
this.variableBuilderConfig = config;
|
this.variableBuilderConfig = config;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(callingConvention==null) {
|
if(callingConvention == null) {
|
||||||
callingConvention = Procedure.CallingConvention.PHI_CALL;
|
callingConvention = Procedure.CallingConvention.PHI_CALL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -321,14 +333,26 @@ public class Compiler {
|
|||||||
optimizations.add(new PassNTypeIdSimplification(program));
|
optimizations.add(new PassNTypeIdSimplification(program));
|
||||||
optimizations.add(new PassNSizeOfSimplification(program));
|
optimizations.add(new PassNSizeOfSimplification(program));
|
||||||
optimizations.add(new PassNStatementIndices(program));
|
optimizations.add(new PassNStatementIndices(program));
|
||||||
optimizations.add(() -> { program.clearVariableReferenceInfos(); return false; });
|
optimizations.add(() -> {
|
||||||
|
program.clearVariableReferenceInfos();
|
||||||
|
return false;
|
||||||
|
});
|
||||||
optimizations.add(new Pass2UnaryNotSimplification(program));
|
optimizations.add(new Pass2UnaryNotSimplification(program));
|
||||||
optimizations.add(new Pass2AliasElimination(program));
|
optimizations.add(new Pass2AliasElimination(program));
|
||||||
optimizations.add(new Pass2IdenticalPhiElimination(program));
|
optimizations.add(new Pass2IdenticalPhiElimination(program));
|
||||||
optimizations.add(new Pass2DuplicateRValueIdentification(program));
|
optimizations.add(new Pass2DuplicateRValueIdentification(program));
|
||||||
optimizations.add(() -> { program.clearStatementIndices(); return false; });
|
optimizations.add(() -> {
|
||||||
optimizations.add(() -> { program.clearVariableReferenceInfos();return false; });
|
program.clearStatementIndices();
|
||||||
optimizations.add(() -> { program.clearStatementInfos(); return false; });
|
return false;
|
||||||
|
});
|
||||||
|
optimizations.add(() -> {
|
||||||
|
program.clearVariableReferenceInfos();
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
optimizations.add(() -> {
|
||||||
|
program.clearStatementInfos();
|
||||||
|
return false;
|
||||||
|
});
|
||||||
optimizations.add(new PassNStatementIndices(program));
|
optimizations.add(new PassNStatementIndices(program));
|
||||||
optimizations.add(new Pass2ConditionalJumpSimplification(program));
|
optimizations.add(new Pass2ConditionalJumpSimplification(program));
|
||||||
optimizations.add(new Pass2ConditionalAndOrRewriting(program));
|
optimizations.add(new Pass2ConditionalAndOrRewriting(program));
|
||||||
@ -352,10 +376,19 @@ public class Compiler {
|
|||||||
optimizations.add(new Pass2EliminateUnusedBlocks(program));
|
optimizations.add(new Pass2EliminateUnusedBlocks(program));
|
||||||
if(enableLoopHeadConstant) {
|
if(enableLoopHeadConstant) {
|
||||||
optimizations.add(new PassNStatementIndices(program));
|
optimizations.add(new PassNStatementIndices(program));
|
||||||
optimizations.add(() -> { program.clearDominators(); return false; });
|
optimizations.add(() -> {
|
||||||
optimizations.add(() -> { program.clearLoopSet(); return false; });
|
program.clearDominators();
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
optimizations.add(() -> {
|
||||||
|
program.clearLoopSet();
|
||||||
|
return false;
|
||||||
|
});
|
||||||
optimizations.add(new Pass2LoopHeadConstantIdentification(program));
|
optimizations.add(new Pass2LoopHeadConstantIdentification(program));
|
||||||
optimizations.add(() -> { program.clearStatementIndices(); return false; });
|
optimizations.add(() -> {
|
||||||
|
program.clearStatementIndices();
|
||||||
|
return false;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
return optimizations;
|
return optimizations;
|
||||||
}
|
}
|
||||||
|
@ -37,8 +37,8 @@ import java.util.stream.Collectors;
|
|||||||
)
|
)
|
||||||
public class KickC implements Callable<Void> {
|
public class KickC implements Callable<Void> {
|
||||||
|
|
||||||
@CommandLine.Parameters(index = "0", arity = "0..1", description = "The KickC source file to compile.")
|
@CommandLine.Parameters(index = "0", arity = "0..n", description = "The KickC source files to compile.")
|
||||||
private Path kcFile = null;
|
private List<Path> kcFiles = null;
|
||||||
|
|
||||||
@CommandLine.Option(names = {"-I", "-libdir"}, description = "Path to a library folder, where the compiler looks for included files. This option can be repeated to add multiple library folders.")
|
@CommandLine.Option(names = {"-I", "-libdir"}, description = "Path to a library folder, where the compiler looks for included files. This option can be repeated to add multiple library folders.")
|
||||||
private List<Path> libDir = null;
|
private List<Path> libDir = null;
|
||||||
@ -46,8 +46,8 @@ public class KickC implements Callable<Void> {
|
|||||||
@CommandLine.Option(names = {"-F", "-fragmentdir"}, description = "Path to the ASM fragment folder, where the compiler looks for ASM fragments.")
|
@CommandLine.Option(names = {"-F", "-fragmentdir"}, description = "Path to the ASM fragment folder, where the compiler looks for ASM fragments.")
|
||||||
private Path fragmentDir = null;
|
private Path fragmentDir = null;
|
||||||
|
|
||||||
@CommandLine.Option(names = {"-o", "-output"}, description = "Name of the output assembler file. By default it is the same as the input file with extension .asm")
|
@CommandLine.Option(names = {"-o", "-output"}, description = "Name of the output file. By default it is the same as the first input file with the proper extension.")
|
||||||
private String asmFileName = null;
|
private String outputFileName = null;
|
||||||
|
|
||||||
@CommandLine.Option(names = {"-odir"}, description = "Path to the output folder, where the compiler places all generated files. By default the folder of the output file is used.")
|
@CommandLine.Option(names = {"-odir"}, description = "Path to the output folder, where the compiler places all generated files. By default the folder of the output file is used.")
|
||||||
private Path outputDir = null;
|
private Path outputDir = null;
|
||||||
@ -238,11 +238,12 @@ public class KickC implements Callable<Void> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(kcFile != null) {
|
if(kcFiles != null && !kcFiles.isEmpty()) {
|
||||||
|
|
||||||
String fileBaseName = getFileBaseName(kcFile);
|
final Path primaryKcFile = kcFiles.get(0);
|
||||||
|
String primaryFileBaseName = getFileBaseName(primaryKcFile);
|
||||||
|
|
||||||
Path kcFileDir = kcFile.getParent();
|
Path kcFileDir = primaryKcFile.getParent();
|
||||||
if(kcFileDir == null) {
|
if(kcFileDir == null) {
|
||||||
kcFileDir = FileSystems.getDefault().getPath(".");
|
kcFileDir = FileSystems.getDefault().getPath(".");
|
||||||
}
|
}
|
||||||
@ -254,8 +255,15 @@ public class KickC implements Callable<Void> {
|
|||||||
Files.createDirectory(outputDir);
|
Files.createDirectory(outputDir);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(asmFileName == null) {
|
String outputFileNameBase;
|
||||||
asmFileName = fileBaseName + ".asm";
|
if(outputFileName == null) {
|
||||||
|
outputFileNameBase = primaryFileBaseName;
|
||||||
|
} else {
|
||||||
|
final int extensionIdx = outputFileName.lastIndexOf('.');
|
||||||
|
if(extensionIdx>0)
|
||||||
|
outputFileNameBase = outputFileName.substring(0, extensionIdx);
|
||||||
|
else
|
||||||
|
outputFileNameBase = outputFileName;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(optimizeNoUplift) {
|
if(optimizeNoUplift) {
|
||||||
@ -317,16 +325,19 @@ public class KickC implements Callable<Void> {
|
|||||||
compiler.setCallingConvention(callingConvention);
|
compiler.setCallingConvention(callingConvention);
|
||||||
}
|
}
|
||||||
|
|
||||||
System.out.println("Compiling " + kcFile);
|
StringBuilder kcFileNames = new StringBuilder();
|
||||||
|
kcFiles.stream().forEach(path -> kcFileNames.append(path.toString()).append(" "));
|
||||||
|
System.out.println("Compiling " + kcFileNames);
|
||||||
Program program = null;
|
Program program = null;
|
||||||
try {
|
try {
|
||||||
program = compiler.compile(kcFile.toString());
|
program = compiler.compile(kcFiles);
|
||||||
} catch(CompileError e) {
|
} catch(CompileError e) {
|
||||||
// Print the error and exit with compile error
|
// Print the error and exit with compile error
|
||||||
System.err.println(e.getMessage());
|
System.err.println(e.getMessage());
|
||||||
System.exit(COMPILE_ERROR);
|
System.exit(COMPILE_ERROR);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String asmFileName = outputFileNameBase + ".asm";
|
||||||
Path asmPath = outputDir.resolve(asmFileName);
|
Path asmPath = outputDir.resolve(asmFileName);
|
||||||
System.out.println("Writing asm file " + asmPath);
|
System.out.println("Writing asm file " + asmPath);
|
||||||
FileOutputStream asmOutputStream = new FileOutputStream(asmPath.toFile());
|
FileOutputStream asmOutputStream = new FileOutputStream(asmPath.toFile());
|
||||||
@ -352,9 +363,10 @@ public class KickC implements Callable<Void> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Assemble the asm-file if instructed
|
// Assemble the asm-file if instructed
|
||||||
Path prgPath = outputDir.resolve(fileBaseName + ".prg");
|
String prgFileName = outputFileNameBase +".prg";
|
||||||
|
Path prgPath = outputDir.resolve(prgFileName);
|
||||||
if(assemble || execute || debug) {
|
if(assemble || execute || debug) {
|
||||||
Path kasmLogPath = outputDir.resolve(fileBaseName + ".klog");
|
Path kasmLogPath = outputDir.resolve(outputFileNameBase + ".klog");
|
||||||
System.out.println("Assembling to " + prgPath.toString());
|
System.out.println("Assembling to " + prgPath.toString());
|
||||||
String[] assembleCommand = {asmPath.toString(), "-log", kasmLogPath.toString(), "-o", prgPath.toString(), "-vicesymbols", "-showmem", "-debugdump"};
|
String[] assembleCommand = {asmPath.toString(), "-log", kasmLogPath.toString(), "-o", prgPath.toString(), "-vicesymbols", "-showmem", "-debugdump"};
|
||||||
if(verbose) {
|
if(verbose) {
|
||||||
@ -385,7 +397,7 @@ public class KickC implements Callable<Void> {
|
|||||||
// Debug the prg-file if instructed
|
// Debug the prg-file if instructed
|
||||||
if(debug) {
|
if(debug) {
|
||||||
System.out.println("Debugging " + prgPath);
|
System.out.println("Debugging " + prgPath);
|
||||||
Path viceSymbolsPath = outputDir.resolve(fileBaseName + ".vs");
|
Path viceSymbolsPath = outputDir.resolve(outputFileNameBase + ".vs");
|
||||||
String debugCommand = "C64Debugger " + "-symbols " + viceSymbolsPath + " -wait 2500" + " -prg " + prgPath.toString();
|
String debugCommand = "C64Debugger " + "-symbols " + viceSymbolsPath + " -wait 2500" + " -prg " + prgPath.toString();
|
||||||
if(verbose) {
|
if(verbose) {
|
||||||
System.out.println("Debugging command: " + debugCommand);
|
System.out.println("Debugging command: " + debugCommand);
|
||||||
@ -397,7 +409,7 @@ public class KickC implements Callable<Void> {
|
|||||||
// Execute the prg-file if instructed
|
// Execute the prg-file if instructed
|
||||||
if(execute) {
|
if(execute) {
|
||||||
System.out.println("Executing " + prgPath);
|
System.out.println("Executing " + prgPath);
|
||||||
Path viceSymbolsPath = outputDir.resolve(fileBaseName + ".vs");
|
Path viceSymbolsPath = outputDir.resolve(outputFileNameBase + ".vs");
|
||||||
String executeCommand = "x64sc " + "-moncommands " + viceSymbolsPath + " " + prgPath.toString();
|
String executeCommand = "x64sc " + "-moncommands " + viceSymbolsPath + " " + prgPath.toString();
|
||||||
if(verbose) {
|
if(verbose) {
|
||||||
System.out.println("Executing command: " + executeCommand);
|
System.out.println("Executing command: " + executeCommand);
|
||||||
|
@ -19,8 +19,8 @@ public class Program {
|
|||||||
/** The log containing information about the compilation process. */
|
/** The log containing information about the compilation process. */
|
||||||
private CompileLog log;
|
private CompileLog log;
|
||||||
|
|
||||||
/** The name of the file being compiled. PASS 0-5 (STATIC) */
|
/** The name of the primary file being compiled. PASS 0-5 (STATIC) */
|
||||||
private String fileName;
|
private String primaryFileName;
|
||||||
/** Paths used for importing files. PASS 0 (STATIC) */
|
/** Paths used for importing files. PASS 0 (STATIC) */
|
||||||
private List<String> importPaths;
|
private List<String> importPaths;
|
||||||
/** Imported files. PASS 0 (STATIC) */
|
/** Imported files. PASS 0 (STATIC) */
|
||||||
@ -460,12 +460,12 @@ public class Program {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void setFileName(String fileName) {
|
public void setPrimaryFileName(String primaryFileName) {
|
||||||
this.fileName = fileName;
|
this.primaryFileName = primaryFileName;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getFileName() {
|
public String getPrimaryFileName() {
|
||||||
return fileName;
|
return primaryFileName;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -97,19 +97,6 @@ public class CParser {
|
|||||||
return tokenStream;
|
return tokenStream;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Load initial C-file and start parsing it.
|
|
||||||
* This may recursively load other C-files (if they are imported)
|
|
||||||
*
|
|
||||||
* @param fileName The file name to look for (in the search path)
|
|
||||||
* @param currentPath The current path (searched before the search path)
|
|
||||||
* @return The parse result
|
|
||||||
*/
|
|
||||||
public KickCParser.FileContext loadAndParseCFile(String fileName, Path currentPath) {
|
|
||||||
loadCFile(fileName, currentPath);
|
|
||||||
return this.parser.file();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the C parser
|
* Get the C parser
|
||||||
*
|
*
|
||||||
@ -149,23 +136,25 @@ public class CParser {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Loads a C-file (if it has not already been loaded).
|
* Loads a C-file (if it has not already been loaded).
|
||||||
|
*
|
||||||
* The C-file is inserted into the C token stream at the current parse-point - so the parser will parse the entire content of the file before moving on.
|
* The C-file is inserted into the C token stream at the current parse-point - so the parser will parse the entire content of the file before moving on.
|
||||||
*
|
*
|
||||||
* @param fileName The file name of the file
|
* @param fileName The file name of the file
|
||||||
*/
|
*/
|
||||||
public void loadCFile(String fileName, boolean isSystem) {
|
public void includeCFile(String fileName, boolean isSystem) {
|
||||||
final Path currentSourceFolderPath = isSystem ? null : getCurrentSourceFolderPath();
|
final Path currentSourceFolderPath = isSystem ? null : getCurrentSourceFolderPath();
|
||||||
loadCFile(fileName, currentSourceFolderPath);
|
final KickCLexer lexer = loadCFile(fileName, currentSourceFolderPath);
|
||||||
|
addSourceFirst(lexer);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loads a C-file (if it has not already been loaded).
|
* Loads a C-file (if it has not already been loaded).
|
||||||
* The C-file is inserted into the C token stream at the current parse-point - so the parser will parse the entire content of the file before moving on.
|
|
||||||
*
|
*
|
||||||
* @param fileName The file name of the file
|
* @param fileName The file name of the file
|
||||||
* @param currentPath The path of the current folder (searched before the search path).
|
* @param currentPath The path of the current folder (searched before the search path).
|
||||||
|
* @return The lexer to be inserted into the source-list using onw of the {@link #addSourceFirst(KickCLexer)} methods.
|
||||||
*/
|
*/
|
||||||
private void loadCFile(String fileName, Path currentPath) {
|
public KickCLexer loadCFile(String fileName, Path currentPath) {
|
||||||
try {
|
try {
|
||||||
if(fileName.startsWith("\"") || fileName.startsWith("<")) {
|
if(fileName.startsWith("\"") || fileName.startsWith("<")) {
|
||||||
fileName = fileName.substring(1, fileName.length() - 1);
|
fileName = fileName.substring(1, fileName.length() - 1);
|
||||||
@ -176,7 +165,7 @@ public class CParser {
|
|||||||
File file = SourceLoader.loadFile(fileName, currentPath, program);
|
File file = SourceLoader.loadFile(fileName, currentPath, program);
|
||||||
List<String> imported = program.getImported();
|
List<String> imported = program.getImported();
|
||||||
if(imported.contains(file.getAbsolutePath())) {
|
if(imported.contains(file.getAbsolutePath())) {
|
||||||
return;
|
return null;
|
||||||
}
|
}
|
||||||
final CharStream fileStream = CharStreams.fromPath(file.toPath().toAbsolutePath());
|
final CharStream fileStream = CharStreams.fromPath(file.toPath().toAbsolutePath());
|
||||||
imported.add(file.getAbsolutePath());
|
imported.add(file.getAbsolutePath());
|
||||||
@ -184,21 +173,22 @@ public class CParser {
|
|||||||
program.getLog().append("PARSING " + file.getPath().replace("\\", "/"));
|
program.getLog().append("PARSING " + file.getPath().replace("\\", "/"));
|
||||||
program.getLog().append(fileStream.toString());
|
program.getLog().append(fileStream.toString());
|
||||||
}
|
}
|
||||||
KickCLexer lexer = addSource(fileStream);
|
KickCLexer lexer = makeLexer(fileStream);
|
||||||
CFile cFile = new CFile(file, lexer);
|
CFile cFile = new CFile(file, lexer);
|
||||||
cFiles.put(file.getAbsolutePath(), cFile);
|
cFiles.put(file.getAbsolutePath(), cFile);
|
||||||
|
return lexer;
|
||||||
} catch(IOException e) {
|
} catch(IOException e) {
|
||||||
throw new CompileError("Error parsing file " + fileName, e);
|
throw new CompileError("Error parsing file " + fileName, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add source code at the start of the token stream being parsed.
|
* Make a lexer for a char stream
|
||||||
*
|
*
|
||||||
* @param charStream The char stream containing the source code to add
|
* @param charStream the char stream
|
||||||
* @return The lexer for reading the source tokens of the added source
|
* @return the lexer
|
||||||
*/
|
*/
|
||||||
public KickCLexer addSource(CharStream charStream) {
|
public KickCLexer makeLexer(CharStream charStream) {
|
||||||
KickCLexer lexer = new KickCLexer(charStream, this);
|
KickCLexer lexer = new KickCLexer(charStream, this);
|
||||||
lexer.addErrorListener(new BaseErrorListener() {
|
lexer.addErrorListener(new BaseErrorListener() {
|
||||||
@Override
|
@Override
|
||||||
@ -212,8 +202,29 @@ public class CParser {
|
|||||||
throw new CompileError("Error parsing file " + charStream.getSourceName() + "\n - Line: " + line + "\n - Message: " + msg);
|
throw new CompileError("Error parsing file " + charStream.getSourceName() + "\n - Line: " + line + "\n - Message: " + msg);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
cTokenSource.addSource(lexer);
|
|
||||||
return lexer;
|
return lexer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add source code at the start of the token stream being parsed.
|
||||||
|
*
|
||||||
|
* @param lexer The lexer for reading the source tokens
|
||||||
|
*/
|
||||||
|
public void addSourceFirst(KickCLexer lexer) {
|
||||||
|
if(lexer != null)
|
||||||
|
cTokenSource.addSourceFirst(lexer);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add source code at the end of the token stream being parsed.
|
||||||
|
*
|
||||||
|
* @param lexer The lexer for reading the source tokens
|
||||||
|
*/
|
||||||
|
public void addSourceLast(KickCLexer lexer) {
|
||||||
|
if(lexer != null)
|
||||||
|
cTokenSource.addSourceLast(lexer);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -21,19 +21,28 @@ public class CTokenSource implements TokenSource {
|
|||||||
|
|
||||||
public CTokenSource(TokenSource tokenSource) {
|
public CTokenSource(TokenSource tokenSource) {
|
||||||
this.subSources = new LinkedList<>();
|
this.subSources = new LinkedList<>();
|
||||||
addSource(tokenSource);
|
addSourceFirst(tokenSource);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Pushes a token source at the current location ).
|
* Pushes a token source at the current location.
|
||||||
* The pushed source will immediately be used for tokens and only when it is exhausted will tokens resume from the current source
|
* The pushed source will immediately be used for tokens and only when it is exhausted will tokens resume from the current source
|
||||||
*
|
*
|
||||||
* @param source The source to push
|
* @param source The source to push
|
||||||
*/
|
*/
|
||||||
public void addSource(TokenSource source) {
|
public void addSourceFirst(TokenSource source) {
|
||||||
subSources.addFirst(source);
|
subSources.addFirst(source);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a token source at the end of the source.
|
||||||
|
*
|
||||||
|
* @param source The source to add
|
||||||
|
*/
|
||||||
|
public void addSourceLast(TokenSource source) {
|
||||||
|
subSources.addLast(source);
|
||||||
|
}
|
||||||
|
|
||||||
public TokenSource getCurrentSource() {
|
public TokenSource getCurrentSource() {
|
||||||
return subSources.peekFirst();
|
return subSources.peekFirst();
|
||||||
}
|
}
|
||||||
@ -49,7 +58,7 @@ public class CTokenSource implements TokenSource {
|
|||||||
// And push it back to the front of the stack
|
// And push it back to the front of the stack
|
||||||
final ArrayList<Token> tokens = new ArrayList<>();
|
final ArrayList<Token> tokens = new ArrayList<>();
|
||||||
tokens.add(token);
|
tokens.add(token);
|
||||||
addSource(new ListTokenSource(tokens));
|
addSourceFirst(new ListTokenSource(tokens));
|
||||||
return token;
|
return token;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -222,8 +222,8 @@ ASM_COMMENT_BLOCK : '/*' .*? '*/' -> channel(2);
|
|||||||
|
|
||||||
// MODE FOR INCLUDE FILES
|
// MODE FOR INCLUDE FILES
|
||||||
mode IMPORT_MODE;
|
mode IMPORT_MODE;
|
||||||
IMPORT_SYSTEMFILE : '<' [a-zA-Z0-9_./\\\-]+ '>' { popMode();cParser.loadCFile(getText(), true); } ;
|
IMPORT_SYSTEMFILE : '<' [a-zA-Z0-9_./\\\-]+ '>' { popMode();cParser.includeCFile(getText(), true); } ;
|
||||||
IMPORT_LOCALFILE : '"' ('\\"' | ~'"')* '"' { popMode(); cParser.loadCFile(getText(), false); } ;
|
IMPORT_LOCALFILE : '"' ('\\"' | ~'"')* '"' { popMode(); cParser.includeCFile(getText(), false); } ;
|
||||||
// White space on hidden channel 1
|
// White space on hidden channel 1
|
||||||
IMPORT_WS : [ \t\r\n\u00a0]+ -> channel(1);
|
IMPORT_WS : [ \t\r\n\u00a0]+ -> channel(1);
|
||||||
// Comments on hidden channel 2
|
// Comments on hidden channel 2
|
||||||
|
@ -301,14 +301,14 @@ public class KickCLexer extends Lexer {
|
|||||||
private void IMPORT_SYSTEMFILE_action(RuleContext _localctx, int actionIndex) {
|
private void IMPORT_SYSTEMFILE_action(RuleContext _localctx, int actionIndex) {
|
||||||
switch (actionIndex) {
|
switch (actionIndex) {
|
||||||
case 7:
|
case 7:
|
||||||
popMode();cParser.loadCFile(getText(), true);
|
popMode();cParser.includeCFile(getText(), true);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private void IMPORT_LOCALFILE_action(RuleContext _localctx, int actionIndex) {
|
private void IMPORT_LOCALFILE_action(RuleContext _localctx, int actionIndex) {
|
||||||
switch (actionIndex) {
|
switch (actionIndex) {
|
||||||
case 8:
|
case 8:
|
||||||
popMode(); cParser.loadCFile(getText(), false);
|
popMode(); cParser.includeCFile(getText(), false);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -80,7 +80,6 @@ public class Pass4CodeGeneration {
|
|||||||
asm.startChunk(currentScope, null, "File Comments");
|
asm.startChunk(currentScope, null, "File Comments");
|
||||||
generateComments(asm, program.getFileComments());
|
generateComments(asm, program.getFileComments());
|
||||||
|
|
||||||
String outputPrgPath = new File(program.getFileName()).getName() + ".prg";
|
|
||||||
asm.startChunk(currentScope, null, "Upstart");
|
asm.startChunk(currentScope, null, "Upstart");
|
||||||
Number programPc = program.getProgramPc();
|
Number programPc = program.getProgramPc();
|
||||||
if(TargetPlatform.C64BASIC.equals(program.getTargetPlatform())) {
|
if(TargetPlatform.C64BASIC.equals(program.getTargetPlatform())) {
|
||||||
@ -97,7 +96,7 @@ public class Pass4CodeGeneration {
|
|||||||
useSegments = true;
|
useSegments = true;
|
||||||
String linkScriptBody = program.getLinkScriptBody();
|
String linkScriptBody = program.getLinkScriptBody();
|
||||||
if(linkScriptBody != null) {
|
if(linkScriptBody != null) {
|
||||||
String outputFileName = new File(program.getFileName()).getName();
|
String outputFileName = new File(program.getPrimaryFileName()).getName();
|
||||||
linkScriptBody = linkScriptBody.replace("%O", outputFileName);
|
linkScriptBody = linkScriptBody.replace("%O", outputFileName);
|
||||||
linkScriptBody = linkScriptBody.replace("%_O", outputFileName.toLowerCase());
|
linkScriptBody = linkScriptBody.replace("%_O", outputFileName.toLowerCase());
|
||||||
linkScriptBody = linkScriptBody.replace("%^O", outputFileName.toUpperCase());
|
linkScriptBody = linkScriptBody.replace("%^O", outputFileName.toUpperCase());
|
||||||
|
@ -60,12 +60,12 @@ public class Pass5FixLongBranches extends Pass5AsmOptimization {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Generate the ASM file
|
// Generate the ASM file
|
||||||
String fileName = getProgram().getFileName();
|
String outputFileName = getProgram().getPrimaryFileName();
|
||||||
try {
|
try {
|
||||||
//getLog().append("ASM");
|
//getLog().append("ASM");
|
||||||
//getLog().append(getProgram().getAsm().toString(false, true));
|
//getLog().append(getProgram().getAsm().toString(false, true));
|
||||||
|
|
||||||
writeOutputFile(fileName, ".asm", getProgram().getAsm().toString(new AsmProgram.AsmPrintState(false), null));
|
writeOutputFile(outputFileName, ".asm", getProgram().getAsm().toString(new AsmProgram.AsmPrintState(false), null));
|
||||||
|
|
||||||
// Copy Resource Files
|
// Copy Resource Files
|
||||||
for(Path asmResourceFile : getProgram().getAsmResourceFiles()) {
|
for(Path asmResourceFile : getProgram().getAsmResourceFiles()) {
|
||||||
@ -78,8 +78,8 @@ public class Pass5FixLongBranches extends Pass5AsmOptimization {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Compile using KickAssembler - catch the output in a String
|
// Compile using KickAssembler - catch the output in a String
|
||||||
File asmFile = getTmpFile(fileName, ".asm");
|
File asmFile = getTmpFile(outputFileName, ".asm");
|
||||||
File asmPrgFile = getTmpFile(fileName, ".prg");
|
File asmPrgFile = getTmpFile(outputFileName, ".prg");
|
||||||
ByteArrayOutputStream kickAssOut = new ByteArrayOutputStream();
|
ByteArrayOutputStream kickAssOut = new ByteArrayOutputStream();
|
||||||
System.setOut(new PrintStream(kickAssOut));
|
System.setOut(new PrintStream(kickAssOut));
|
||||||
int asmRes = -1;
|
int asmRes = -1;
|
||||||
|
@ -270,7 +270,7 @@ public class CPreprocessor implements TokenSource {
|
|||||||
addTokenToExpandedBody(macroBodyToken, macroNameToken, expandedBody);
|
addTokenToExpandedBody(macroBodyToken, macroNameToken, expandedBody);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
cTokenSource.addSource(new ListTokenSource(expandedBody));
|
cTokenSource.addSourceFirst(new ListTokenSource(expandedBody));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -8,9 +8,6 @@ import org.antlr.v4.runtime.CharStreams;
|
|||||||
import org.antlr.v4.runtime.CodePointCharStream;
|
import org.antlr.v4.runtime.CodePointCharStream;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.net.URISyntaxException;
|
|
||||||
|
|
||||||
import static junit.framework.TestCase.fail;
|
import static junit.framework.TestCase.fail;
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
@ -226,7 +223,7 @@ public class TestPreprocessor {
|
|||||||
private String parse(String program) {
|
private String parse(String program) {
|
||||||
CodePointCharStream charStream = CharStreams.fromString(program);
|
CodePointCharStream charStream = CharStreams.fromString(program);
|
||||||
CParser cParser = new CParser(null);
|
CParser cParser = new CParser(null);
|
||||||
cParser.addSource(charStream);
|
cParser.addSourceFirst(cParser.makeLexer(charStream));
|
||||||
KickCParser.StmtSeqContext stmtSeqContext = cParser.getParser().stmtSeq();
|
KickCParser.StmtSeqContext stmtSeqContext = cParser.getParser().stmtSeq();
|
||||||
ProgramPrinter printVisitor = new ProgramPrinter();
|
ProgramPrinter printVisitor = new ProgramPrinter();
|
||||||
printVisitor.visit(stmtSeqContext);
|
printVisitor.visit(stmtSeqContext);
|
||||||
@ -241,7 +238,6 @@ public class TestPreprocessor {
|
|||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object visitStmtSeq(KickCParser.StmtSeqContext ctx) {
|
public Object visitStmtSeq(KickCParser.StmtSeqContext ctx) {
|
||||||
for(KickCParser.StmtContext stmtContext : ctx.stmt()) {
|
for(KickCParser.StmtContext stmtContext : ctx.stmt()) {
|
||||||
|
@ -21,6 +21,8 @@ import java.net.URISyntaxException;
|
|||||||
import java.nio.file.FileAlreadyExistsException;
|
import java.nio.file.FileAlreadyExistsException;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.Paths;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
import static junit.framework.TestCase.fail;
|
import static junit.framework.TestCase.fail;
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
@ -4022,7 +4024,10 @@ public class TestPrograms {
|
|||||||
if(upliftCombinations != null) {
|
if(upliftCombinations != null) {
|
||||||
compiler.setUpliftCombinations(upliftCombinations);
|
compiler.setUpliftCombinations(upliftCombinations);
|
||||||
}
|
}
|
||||||
Program program = compiler.compile(fileName);
|
final ArrayList<Path> files = new ArrayList<>();
|
||||||
|
final Path filePath = Paths.get(fileName);
|
||||||
|
files.add(filePath);
|
||||||
|
Program program = compiler.compile(files);
|
||||||
|
|
||||||
compileAsm(fileName, program);
|
compileAsm(fileName, program);
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user