org.devzendo.tma.AssemblerMain.scala Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of tma-assembler Show documentation
Show all versions of tma-assembler Show documentation
The Transputer Macro Asesmbler Code
(Apache License v2) 2018-2019 Matt Gumbley, DevZendo.org
The newest version!
/*
* Copyright (C) 2008-2018 Matt Gumbley, DevZendo.org http://devzendo.org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.devzendo.tma
import java.io.File
import org.devzendo.tma.codegen.{AssemblyModel, CodeGenerationException, CodeGenerator, CasedSymbolName, OffsetTransformer}
import org.devzendo.tma.parser.{AssemblyParser, AssemblyParserException, MacroManager}
class AssemblerMain(val argList: List[String]) {
private val logger = org.log4s.getLogger
var argIndex = 0
var asmFile: Option[File] = None
var outputFile: Option[File] = None
var binaryFile: Option[File] = None
var listingFile: Option[File] = None
var debugParser = false
var debugExpansion = false
var showParserOutput = false
var debugCodegen = false
def existingFile(fileType: String, f: String): Option[File] = {
val file = new File(f)
if (file.exists()) {
Some(file)
} else {
logger.error(s"The $fileType file '$f' does not exist")
quit()
None // won't get here
}
}
while (argIndex < argList.length)
{
val f = argList(argIndex)
def expectFileName(): Option[File] = {
if (argIndex == argList.length - 1) {
logger.error(s"$f requires a file as its argument")
quit()
None // won't get here
}
val ret = Some(new File(argList(argIndex + 1)))
argIndex += 1
ret
}
logger.debug("ARG: [" + f + "]")
f match {
case "--help" => usage(); exit()
case "-?" => usage(); exit()
case "--version" => version(); exit()
case "-p" | "--parser" => debugParser = true
case "-e" | "--expansion" => debugExpansion = true
case "-P" | "--parserOutput" => showParserOutput = true
case "-c" | "--codegen" => debugCodegen = true
case "-x" | "--caseSensitive" => CasedSymbolName.setCaseSensitivity(true)
case "-o" | "--output" =>
outputFile = expectFileName()
case "-b" | "--binary" =>
binaryFile = expectFileName()
case "-l" | "--listing" =>
listingFile = expectFileName()
case _ =>
if (f.startsWith("-")) {
logger.error(s"Unknown command line option: '$f'")
logger.error("")
usage()
quit()
}
asmFile = existingFile("assembly", f)
}
argIndex += 1
}
if (asmFile.isEmpty) {
errorQuit("An assembly file must be specified")
}
if (outputFile.isEmpty && binaryFile.isEmpty) {
errorQuit("No output or binary output specified")
}
def start(): Unit = {
val macroManager = new MacroManager(debugExpansion)
val parser = new AssemblyParser(debugParser, showParserOutput, macroManager)
val inmodel = new AssemblyModel(debugCodegen)
val codegen = new CodeGenerator(debugCodegen, inmodel)
codegen.addStatementTransformer(new OffsetTransformer(inmodel).transform)
val controller = new AssemblerController(macroManager, parser, codegen)
val asm = asmFile.get
logger.debug(s"Start of parsing from from ${asm.getName}")
val startParseTime = System.currentTimeMillis()
controller.parseFile(asm)
val endParseTime = System.currentTimeMillis()
logger.debug(s"Parsing complete in ${endParseTime - startParseTime} ms")
val parserExceptions = controller.getParseExceptions
if (parserExceptions.nonEmpty) {
logger.error("Parse errors:")
parserExceptions.foreach( (f: AssemblyParserException) => logger.error(f.getMessage))
errorQuit("Cannot continue")
}
val startCodegenTime = System.currentTimeMillis()
val model = controller.generateModel()
val endCodegenTime = System.currentTimeMillis()
logger.debug(s"Code generation complete in ${endCodegenTime - startCodegenTime} ms")
val codeGenerationExceptions = controller.getCodeGenerationExceptions
if (codeGenerationExceptions.nonEmpty) {
logger.error("Code generation errors:")
codeGenerationExceptions.foreach( (f: CodeGenerationException) => logger.error(f.getMessage))
errorQuit("Cannot continue")
}
val startOutputTime = System.currentTimeMillis()
controller.output(model, outputFile, binaryFile, listingFile)
val endOutputTime = System.currentTimeMillis()
logger.debug(s"Output complete in ${endOutputTime - startOutputTime} ms")
}
// -----------------------------------------------------------------------------------------------------------------
def errorQuit(str: String): Unit = {
logger.error(str)
quit()
}
def usage() {
version()
logger.info("tmasm [options] file.asm")
logger.info("Assembler options:")
logger.info("--help, -? - just display this help text")
logger.info("--version - just display the version of tmasm")
logger.info("-o|--output output.o - create an ELF output file")
logger.info("-b|--binary output - create a binary output file")
logger.info("-l|--listing output.lst - create a listing file")
logger.info("-x|--caseSensitive - treat variable, constant and label names as case-sensitive")
logger.info(" (default is insensitive: they are converted to upper case)")
logger.info("Diagnostics:")
logger.info("-e|--expansion - enable macro expansion diagnostics")
logger.info("-p|--parser - enable parser diagnostics")
logger.info("-P|--showParserOutput - show parser text input and AST output")
logger.info("-c|--codegen - enable code generation diagnostics")
logger.info("Logging output control options:")
logger.info("--debug - set the log level to debug (default is info)")
logger.info("--warn - set the log level to warning")
logger.info("--level - show log levels of each log line output")
logger.info("--classes - show class names in each log line output")
logger.info("--threads - show thread names in each log line output")
logger.info("--times - show timing data in each log line output")
}
def version() {
logger.info(s"${AssemblerMain.appName} ${Version.getPropertiesVersion()}")
}
def quit() {
System.exit(1)
}
def exit() {
System.exit(0)
}
}
object AssemblerMain {
private val appName = "Transputer Macro Assembler"
/**
* @param args the command line arguments.
*/
def main(args: Array[String]) {
val finalArgList = LogbackLogging.setupLoggingFromArgs(args.toList)
new AssemblerMain(finalArgList).start()
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy