From 6e19bb560d474736d45f5be011ff0830c7019991 Mon Sep 17 00:00:00 2001 From: Dimitar Trendafilov Date: Mon, 5 Nov 2018 23:34:00 +0200 Subject: Squashed 'spasm/' content from commit 08ee95d git-subtree-dir: spasm git-subtree-split: 08ee95d89054ba0d33697d613799a0a013aedf89 --- .clang-format | 148 +++++ .gitignore | 1 + doc/Doxyfile | 1252 ++++++++++++++++++++++++++++++++++++ solution/Makefile | 46 ++ solution/genie.lua | 54 ++ solution/spasm.make | 197 ++++++ solution/spasm.sln | 37 ++ solution/spasm.vcxproj | 133 ++++ solution/spasm.vcxproj.filters | 34 + solution/spasm.vcxproj.user | 11 + solution/sprt.make | 178 ++++++ solution/sprt.vcxproj | 125 ++++ solution/sprt.vcxproj.filters | 19 + solution/sprt.vcxproj.user | 11 + solution/sprun.make | 161 +++++ solution/sprun.vcxproj | 126 ++++ solution/sprun.vcxproj.filters | 13 + solution/sprun.vcxproj.user | 11 + src/asm/assembler.cpp | 79 +++ src/asm/assembler.hpp | 36 ++ src/asm/bytecode.cpp | 74 +++ src/asm/bytecode.hpp | 87 +++ src/asm/dfa.dot | 180 ++++++ src/asm/dfa.svg | 1367 ++++++++++++++++++++++++++++++++++++++++ src/asm/lexdump.cpp | 83 +++ src/asm/lexdump3.cpp | 62 ++ src/asm/lexer.cpp | 1123 +++++++++++++++++++++++++++++++++ src/asm/lexer.hpp | 70 ++ src/asm/lexer.re | 307 +++++++++ src/asm/main.cpp | 21 + src/asm/symbol.cpp | 120 ++++ src/asm/symbol.hpp | 69 ++ src/asm/token.cpp | 65 ++ src/asm/token.hpp | 85 +++ src/asm/tokenizer.cpp | 51 ++ src/asm/tokenizer.hpp | 35 + src/dstack.cpp | 172 +++++ src/dstack.hpp | 46 ++ src/frames.cpp | 130 ++++ src/frames.hpp | 51 ++ src/main.cpp | 33 + src/program.spa | 12 + src/spasm.cpp | 348 ++++++++++ src/spasm.hpp | 13 + src/spasm_impl.hpp | 97 +++ src/types.hpp | 17 + 46 files changed, 7390 insertions(+) create mode 100644 .clang-format create mode 100644 .gitignore create mode 100644 doc/Doxyfile create mode 100644 solution/Makefile create mode 100644 solution/genie.lua create mode 100644 solution/spasm.make create mode 100644 solution/spasm.sln create mode 100644 solution/spasm.vcxproj create mode 100644 solution/spasm.vcxproj.filters create mode 100644 solution/spasm.vcxproj.user create mode 100644 solution/sprt.make create mode 100644 solution/sprt.vcxproj create mode 100644 solution/sprt.vcxproj.filters create mode 100644 solution/sprt.vcxproj.user create mode 100644 solution/sprun.make create mode 100644 solution/sprun.vcxproj create mode 100644 solution/sprun.vcxproj.filters create mode 100644 solution/sprun.vcxproj.user create mode 100644 src/asm/assembler.cpp create mode 100644 src/asm/assembler.hpp create mode 100644 src/asm/bytecode.cpp create mode 100644 src/asm/bytecode.hpp create mode 100644 src/asm/dfa.dot create mode 100644 src/asm/dfa.svg create mode 100644 src/asm/lexdump.cpp create mode 100644 src/asm/lexdump3.cpp create mode 100644 src/asm/lexer.cpp create mode 100644 src/asm/lexer.hpp create mode 100644 src/asm/lexer.re create mode 100644 src/asm/main.cpp create mode 100644 src/asm/symbol.cpp create mode 100644 src/asm/symbol.hpp create mode 100644 src/asm/token.cpp create mode 100644 src/asm/token.hpp create mode 100644 src/asm/tokenizer.cpp create mode 100644 src/asm/tokenizer.hpp create mode 100644 src/dstack.cpp create mode 100644 src/dstack.hpp create mode 100644 src/frames.cpp create mode 100644 src/frames.hpp create mode 100644 src/main.cpp create mode 100644 src/program.spa create mode 100644 src/spasm.cpp create mode 100644 src/spasm.hpp create mode 100644 src/spasm_impl.hpp create mode 100644 src/types.hpp diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..b34a670 --- /dev/null +++ b/.clang-format @@ -0,0 +1,148 @@ +--- +Language: Cpp +# BasedOnStyle: Chromium +AccessModifierOffset: -1 +AlignAfterOpenBracket: Align +AlignConsecutiveAssignments: false +AlignConsecutiveDeclarations: false +AlignEscapedNewlines: Left +AlignOperands: true +AlignTrailingComments: true +AllowAllParametersOfDeclarationOnNextLine: false +AllowShortBlocksOnASingleLine: false +AllowShortCaseLabelsOnASingleLine: false +AllowShortFunctionsOnASingleLine: Inline +AllowShortIfStatementsOnASingleLine: false +AllowShortLoopsOnASingleLine: false +AlwaysBreakAfterDefinitionReturnType: None +AlwaysBreakAfterReturnType: None +AlwaysBreakBeforeMultilineStrings: true +AlwaysBreakTemplateDeclarations: Yes +BinPackArguments: true +BinPackParameters: false +BraceWrapping: + AfterClass: false + AfterControlStatement: false + AfterEnum: false + AfterFunction: false + AfterNamespace: false + AfterObjCDeclaration: false + AfterStruct: false + AfterUnion: false + AfterExternBlock: false + BeforeCatch: false + BeforeElse: false + IndentBraces: false + SplitEmptyFunction: true + SplitEmptyRecord: true + SplitEmptyNamespace: true +BreakBeforeBinaryOperators: None +BreakBeforeBraces: Allman +BreakBeforeInheritanceComma: false +BreakInheritanceList: BeforeColon +BreakBeforeTernaryOperators: true +BreakConstructorInitializersBeforeComma: false +BreakConstructorInitializers: BeforeColon +BreakAfterJavaFieldAnnotations: false +BreakStringLiterals: true +ColumnLimit: 80 +CommentPragmas: '^ IWYU pragma:' +CompactNamespaces: false +ConstructorInitializerAllOnOneLineOrOnePerLine: true +ConstructorInitializerIndentWidth: 4 +ContinuationIndentWidth: 4 +Cpp11BracedListStyle: true +DerivePointerAlignment: false +DisableFormat: false +ExperimentalAutoDetectBinPacking: false +FixNamespaceComments: true +ForEachMacros: + - foreach + - Q_FOREACH + - BOOST_FOREACH +IncludeBlocks: Preserve +IncludeCategories: + - Regex: '^' + Priority: 2 + - Regex: '^<.*\.h>' + Priority: 1 + - Regex: '^<.*' + Priority: 2 + - Regex: '.*' + Priority: 3 +IncludeIsMainRegex: '([-_](test|unittest))?$' +IndentCaseLabels: true +IndentPPDirectives: None +IndentWidth: 4 +IndentWrappedFunctionNames: false +JavaScriptQuotes: Leave +JavaScriptWrapImports: true +KeepEmptyLinesAtTheStartOfBlocks: false +MacroBlockBegin: '' +MacroBlockEnd: '' +MaxEmptyLinesToKeep: 1 +NamespaceIndentation: None +ObjCBinPackProtocolList: Never +ObjCBlockIndentWidth: 2 +ObjCSpaceAfterProperty: false +ObjCSpaceBeforeProtocolList: true +PenaltyBreakAssignment: 2 +PenaltyBreakBeforeFirstCallParameter: 1 +PenaltyBreakComment: 300 +PenaltyBreakFirstLessLess: 120 +PenaltyBreakString: 1000 +PenaltyBreakTemplateDeclaration: 10 +PenaltyExcessCharacter: 1000000 +PenaltyReturnTypeOnItsOwnLine: 200 +PointerAlignment: Left +RawStringFormats: + - Language: Cpp + Delimiters: + - cc + - CC + - cpp + - Cpp + - CPP + - 'c++' + - 'C++' + CanonicalDelimiter: '' + BasedOnStyle: google + - Language: TextProto + Delimiters: + - pb + - PB + - proto + - PROTO + EnclosingFunctions: + - EqualsProto + - EquivToProto + - PARSE_PARTIAL_TEXT_PROTO + - PARSE_TEST_PROTO + - PARSE_TEXT_PROTO + - ParseTextOrDie + - ParseTextProtoOrDie + CanonicalDelimiter: '' + BasedOnStyle: google +ReflowComments: true +SortIncludes: true +SortUsingDeclarations: true +SpaceAfterCStyleCast: false +SpaceAfterTemplateKeyword: true +SpaceBeforeAssignmentOperators: true +SpaceBeforeCpp11BracedList: false +SpaceBeforeCtorInitializerColon: true +SpaceBeforeInheritanceColon: true +SpaceBeforeParens: ControlStatements +SpaceBeforeRangeBasedForLoopColon: true +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 2 +SpacesInAngles: false +SpacesInContainerLiterals: true +SpacesInCStyleCastParentheses: false +SpacesInParentheses: false +SpacesInSquareBrackets: false +Standard: Auto +TabWidth: 8 +UseTab: Never +... + diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..567609b --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +build/ diff --git a/doc/Doxyfile b/doc/Doxyfile new file mode 100644 index 0000000..e7e3eb3 --- /dev/null +++ b/doc/Doxyfile @@ -0,0 +1,1252 @@ +# Doxyfile 1.5.1 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project +# +# All text after a hash (#) is considered a comment and will be ignored +# The format is: +# TAG = value [value, ...] +# For lists items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (" ") + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded +# by quotes) that should identify the project. + +PROJECT_NAME = spasm + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. +# This could be handy for archiving the generated documentation or +# if some version control system is used. + +PROJECT_NUMBER = 0.0.1 + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) +# base path where the generated documentation will be put. +# If a relative path is entered, it will be relative to the location +# where doxygen was started. If left blank the current directory will be used. + +OUTPUT_DIRECTORY = + +# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create +# 4096 sub-directories (in 2 levels) under the output directory of each output +# format and will distribute the generated files over these directories. +# Enabling this option can be useful when feeding doxygen a huge amount of +# source files, where putting all generated files in the same directory would +# otherwise cause performance problems for the file system. + +CREATE_SUBDIRS = NO + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# The default language is English, other supported languages are: +# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, +# Croatian, Czech, Danish, Dutch, Finnish, French, German, Greek, Hungarian, +# Italian, Japanese, Japanese-en (Japanese with English messages), Korean, +# Korean-en, Lithuanian, Norwegian, Polish, Portuguese, Romanian, Russian, +# Serbian, Slovak, Slovene, Spanish, Swedish, and Ukrainian. + +OUTPUT_LANGUAGE = English + +# This tag can be used to specify the encoding used in the generated output. +# The encoding is not always determined by the language that is chosen, +# but also whether or not the output is meant for Windows or non-Windows users. +# In case there is a difference, setting the USE_WINDOWS_ENCODING tag to YES +# forces the Windows encoding (this is the default for the Windows binary), +# whereas setting the tag to NO uses a Unix-style encoding (the default for +# all platforms other than Windows). + +USE_WINDOWS_ENCODING = NO + +# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will +# include brief member descriptions after the members that are listed in +# the file and class documentation (similar to JavaDoc). +# Set to NO to disable this. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend +# the brief description of a member or function before the detailed description. +# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. + +REPEAT_BRIEF = YES + +# This tag implements a quasi-intelligent brief description abbreviator +# that is used to form the text in various listings. Each string +# in this list, if found as the leading text of the brief description, will be +# stripped from the text and the result after processing the whole list, is +# used as the annotated text. Otherwise, the brief description is used as-is. +# If left blank, the following values are used ("$name" is automatically +# replaced with the name of the entity): "The $name class" "The $name widget" +# "The $name file" "is" "provides" "specifies" "contains" +# "represents" "a" "an" "the" + +ABBREVIATE_BRIEF = + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# Doxygen will generate a detailed section even if there is only a brief +# description. + +ALWAYS_DETAILED_SEC = NO + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment +# operators of the base classes will not be shown. + +INLINE_INHERITED_MEMB = NO + +# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full +# path before files name in the file list and in the header files. If set +# to NO the shortest path that makes the file name unique will be used. + +FULL_PATH_NAMES = NO + +# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag +# can be used to strip a user-defined part of the path. Stripping is +# only done if one of the specified strings matches the left-hand part of +# the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the +# path to strip. + +STRIP_FROM_PATH = + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of +# the path mentioned in the documentation of a class, which tells +# the reader which header file to include in order to use a class. +# If left blank only the name of the header file containing the class +# definition is used. Otherwise one should specify the include paths that +# are normally passed to the compiler using the -I flag. + +STRIP_FROM_INC_PATH = + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter +# (but less readable) file names. This can be useful is your file systems +# doesn't support long names like on DOS, Mac, or CD-ROM. + +SHORT_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen +# will interpret the first line (until the first dot) of a JavaDoc-style +# comment as the brief description. If set to NO, the JavaDoc +# comments will behave just like the Qt-style comments (thus requiring an +# explicit @brief command for a brief description. + +JAVADOC_AUTOBRIEF = NO + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen +# treat a multi-line C++ special comment block (i.e. a block of //! or /// +# comments) as a brief description. This used to be the default behaviour. +# The new default is to treat a multi-line C++ comment block as a detailed +# description. Set this tag to YES if you prefer the old behaviour instead. + +MULTILINE_CPP_IS_BRIEF = NO + +# If the DETAILS_AT_TOP tag is set to YES then Doxygen +# will output the detailed description near the top, like JavaDoc. +# If set to NO, the detailed description appears after the member +# documentation. + +DETAILS_AT_TOP = NO + +# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented +# member inherits the documentation from any documented member that it +# re-implements. + +INHERIT_DOCS = YES + +# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce +# a new page for each member. If set to NO, the documentation of a member will +# be part of the file/class/namespace that contains it. + +SEPARATE_MEMBER_PAGES = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. +# Doxygen uses this value to replace tabs by spaces in code fragments. + +TAB_SIZE = 4 + +# This tag can be used to specify a number of aliases that acts +# as commands in the documentation. An alias has the form "name=value". +# For example adding "sideeffect=\par Side Effects:\n" will allow you to +# put the command \sideeffect (or @sideeffect) in the documentation, which +# will result in a user-defined paragraph with heading "Side Effects:". +# You can put \n's in the value part of an alias to insert newlines. + +ALIASES = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C +# sources only. Doxygen will then generate output that is more tailored for C. +# For instance, some of the names that are used will be different. The list +# of all members will be omitted, etc. + +OPTIMIZE_OUTPUT_FOR_C = NO + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java +# sources only. Doxygen will then generate output that is more tailored for Java. +# For instance, namespaces will be presented as packages, qualified scopes +# will look different, etc. + +OPTIMIZE_OUTPUT_JAVA = NO + +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want to +# include (a tag file for) the STL sources as input, then you should +# set this tag to YES in order to let doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); v.s. +# func(std::string) {}). This also make the inheritance and collaboration +# diagrams that involve STL classes more complete and accurate. + +BUILTIN_STL_SUPPORT = NO + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES, then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. + +DISTRIBUTE_GROUP_DOC = NO + +# Set the SUBGROUPING tag to YES (the default) to allow class member groups of +# the same type (for instance a group of public functions) to be put as a +# subgroup of that type (e.g. under the Public Functions section). Set it to +# NO to prevent subgrouping. Alternatively, this can be done per class using +# the \nosubgrouping command. + +SUBGROUPING = YES + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in +# documentation are documented, even if no documentation was available. +# Private class members and static file members will be hidden unless +# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES + +EXTRACT_ALL = NO + +# If the EXTRACT_PRIVATE tag is set to YES all private members of a class +# will be included in the documentation. + +EXTRACT_PRIVATE = YES + +# If the EXTRACT_STATIC tag is set to YES all static members of a file +# will be included in the documentation. + +EXTRACT_STATIC = YES + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) +# defined locally in source files will be included in the documentation. +# If set to NO only classes defined in header files are included. + +EXTRACT_LOCAL_CLASSES = YES + +# This flag is only useful for Objective-C code. When set to YES local +# methods, which are defined in the implementation section but not in +# the interface are included in the documentation. +# If set to NO (the default) only methods in the interface are included. + +EXTRACT_LOCAL_METHODS = NO + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all +# undocumented members of documented classes, files or namespaces. +# If set to NO (the default) these members will be included in the +# various overviews, but no documentation section is generated. +# This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. +# If set to NO (the default) these classes will be included in the various +# overviews. This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_CLASSES = NO + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all +# friend (class|struct|union) declarations. +# If set to NO (the default) these declarations will be included in the +# documentation. + +HIDE_FRIEND_COMPOUNDS = NO + +# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any +# documentation blocks found inside the body of a function. +# If set to NO (the default) these blocks will be appended to the +# function's detailed documentation block. + +HIDE_IN_BODY_DOCS = NO + +# The INTERNAL_DOCS tag determines if documentation +# that is typed after a \internal command is included. If the tag is set +# to NO (the default) then the documentation will be excluded. +# Set it to YES to include the internal documentation. + +INTERNAL_DOCS = NO + +# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate +# file names in lower-case letters. If set to YES upper-case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# and Mac users are advised to set this option to NO. + +CASE_SENSE_NAMES = YES + +# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen +# will show members with their full class and namespace scopes in the +# documentation. If set to YES the scope will be hidden. + +HIDE_SCOPE_NAMES = NO + +# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen +# will put a list of the files that are included by a file in the documentation +# of that file. + +SHOW_INCLUDE_FILES = YES + +# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] +# is inserted in the documentation for inline members. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen +# will sort the (detailed) documentation of file and class members +# alphabetically by member name. If set to NO the members will appear in +# declaration order. + +SORT_MEMBER_DOCS = YES + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the +# brief documentation of file, namespace and class members alphabetically +# by member name. If set to NO (the default) the members will appear in +# declaration order. + +SORT_BRIEF_DOCS = NO + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be +# sorted by fully-qualified names, including namespaces. If set to +# NO (the default), the class list will be sorted only by class name, +# not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the +# alphabetical list. + +SORT_BY_SCOPE_NAME = NO + +# The GENERATE_TODOLIST tag can be used to enable (YES) or +# disable (NO) the todo list. This list is created by putting \todo +# commands in the documentation. + +GENERATE_TODOLIST = YES + +# The GENERATE_TESTLIST tag can be used to enable (YES) or +# disable (NO) the test list. This list is created by putting \test +# commands in the documentation. + +GENERATE_TESTLIST = YES + +# The GENERATE_BUGLIST tag can be used to enable (YES) or +# disable (NO) the bug list. This list is created by putting \bug +# commands in the documentation. + +GENERATE_BUGLIST = YES + +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or +# disable (NO) the deprecated list. This list is created by putting +# \deprecated commands in the documentation. + +GENERATE_DEPRECATEDLIST= YES + +# The ENABLED_SECTIONS tag can be used to enable conditional +# documentation sections, marked by \if sectionname ... \endif. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines +# the initial value of a variable or define consists of for it to appear in +# the documentation. If the initializer consists of more lines than specified +# here it will be hidden. Use a value of 0 to hide initializers completely. +# The appearance of the initializer of individual variables and defines in the +# documentation can be controlled using \showinitializer or \hideinitializer +# command in the documentation regardless of this setting. + +MAX_INITIALIZER_LINES = 30 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated +# at the bottom of the documentation of classes and structs. If set to YES the +# list will mention the files that were used to generate the documentation. + +SHOW_USED_FILES = YES + +# If the sources in your project are distributed over multiple directories +# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy +# in the documentation. The default is NO. + +SHOW_DIRECTORIES = NO + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from the +# version control system). Doxygen will invoke the program by executing (via +# popen()) the command , where is the value of +# the FILE_VERSION_FILTER tag, and is the name of an input file +# provided by doxygen. Whatever the program writes to standard output +# is used as the file version. See the manual for examples. + +FILE_VERSION_FILTER = + +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated +# by doxygen. Possible values are YES and NO. If left blank NO is used. + +QUIET = NO + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated by doxygen. Possible values are YES and NO. If left blank +# NO is used. + +WARNINGS = YES + +# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings +# for undocumented members. If EXTRACT_ALL is set to YES then this flag will +# automatically be disabled. + +WARN_IF_UNDOCUMENTED = YES + +# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some +# parameters in a documented function, or documenting parameters that +# don't exist or using markup commands wrongly. + +WARN_IF_DOC_ERROR = YES + +# This WARN_NO_PARAMDOC option can be abled to get warnings for +# functions that are documented, but have no documentation for their parameters +# or return value. If set to NO (the default) doxygen will only warn about +# wrong or incomplete parameter documentation, but not about the absence of +# documentation. + +WARN_NO_PARAMDOC = NO + +# The WARN_FORMAT tag determines the format of the warning messages that +# doxygen can produce. The string should contain the $file, $line, and $text +# tags, which will be replaced by the file and line number from which the +# warning originated and the warning text. Optionally the format may contain +# $version, which will be replaced by the version of the file (if it could +# be obtained via FILE_VERSION_FILTER) + +WARN_FORMAT = "$file:$line: $text" + +# The WARN_LOGFILE tag can be used to specify a file to which warning +# and error messages should be written. If left blank the output is written +# to stderr. + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag can be used to specify the files and/or directories that contain +# documented source files. You may enter file names like "myfile.cpp" or +# directories like "/usr/src/myproject". Separate the files or directories +# with spaces. + +INPUT = ../src + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank the following patterns are tested: +# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx +# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py + +FILE_PATTERNS = + +# The RECURSIVE tag can be used to turn specify whether or not subdirectories +# should be searched for input files as well. Possible values are YES and NO. +# If left blank NO is used. + +RECURSIVE = NO + +# The EXCLUDE tag can be used to specify files and/or directories that should +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. + +EXCLUDE = + +# The EXCLUDE_SYMLINKS tag can be used select whether or not files or +# directories that are symbolic links (a Unix filesystem feature) are excluded +# from the input. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. Note that the wildcards are matched +# against the file with absolute path, so to exclude all test directories +# for example use the pattern */test/* + +EXCLUDE_PATTERNS = + +# The EXAMPLE_PATH tag can be used to specify one or more files or +# directories that contain example code fragments that are included (see +# the \include command). + +EXAMPLE_PATH = + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank all files are included. + +EXAMPLE_PATTERNS = + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude +# commands irrespective of the value of the RECURSIVE tag. +# Possible values are YES and NO. If left blank NO is used. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or +# directories that contain image that are included in the documentation (see +# the \image command). + +IMAGE_PATH = + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command , where +# is the value of the INPUT_FILTER tag, and is the name of an +# input file. Doxygen will then use the output that the filter program writes +# to standard output. If FILTER_PATTERNS is specified, this tag will be +# ignored. + +INPUT_FILTER = + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. The filters are a list of the form: +# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further +# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER +# is applied to all files. + +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will be used to filter the input files when producing source +# files to browse (i.e. when SOURCE_BROWSER is set to YES). + +FILTER_SOURCE_FILES = NO + +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will +# be generated. Documented entities will be cross-referenced with these sources. +# Note: To get rid of all source code in the generated output, make sure also +# VERBATIM_HEADERS is set to NO. + +SOURCE_BROWSER = NO + +# Setting the INLINE_SOURCES tag to YES will include the body +# of functions and classes directly in the documentation. + +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct +# doxygen to hide any special comment blocks from generated source code +# fragments. Normal C and C++ comments will always remain visible. + +STRIP_CODE_COMMENTS = YES + +# If the REFERENCED_BY_RELATION tag is set to YES (the default) +# then for each documented function all documented +# functions referencing it will be listed. + +REFERENCED_BY_RELATION = YES + +# If the REFERENCES_RELATION tag is set to YES (the default) +# then for each documented function all documented entities +# called/used by that function will be listed. + +REFERENCES_RELATION = YES + +# If the REFERENCES_LINK_SOURCE tag is set to YES (the default) +# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from +# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will +# link to the source code. Otherwise they will link to the documentstion. + +REFERENCES_LINK_SOURCE = YES + +# If the USE_HTAGS tag is set to YES then the references to source code +# will point to the HTML generated by the htags(1) tool instead of doxygen +# built-in source browser. The htags tool is part of GNU's global source +# tagging system (see http://www.gnu.org/software/global/global.html). You +# will need version 4.8.6 or higher. + +USE_HTAGS = NO + +# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen +# will generate a verbatim copy of the header file for each class for +# which an include is specified. Set to NO to disable this. + +VERBATIM_HEADERS = YES + +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index +# of all compounds will be generated. Enable this if the project +# contains a lot of classes, structs, unions or interfaces. + +ALPHABETICAL_INDEX = NO + +# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then +# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns +# in which this list will be split (can be a number in the range [1..20]) + +COLS_IN_ALPHA_INDEX = 5 + +# In case all classes in a project start with a common prefix, all +# classes will be put under the same header in the alphabetical index. +# The IGNORE_PREFIX tag can be used to specify one or more prefixes that +# should be ignored while generating the index headers. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES (the default) Doxygen will +# generate HTML output. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `html' will be used as the default path. + +HTML_OUTPUT = html + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for +# each generated HTML page (for example: .htm,.php,.asp). If it is left blank +# doxygen will generate files with .html extension. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a personal HTML header for +# each generated HTML page. If it is left blank doxygen will generate a +# standard header. + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a personal HTML footer for +# each generated HTML page. If it is left blank doxygen will generate a +# standard footer. + +HTML_FOOTER = + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading +# style sheet that is used by each HTML page. It can be used to +# fine-tune the look of the HTML output. If the tag is left blank doxygen +# will generate a default style sheet. Note that doxygen will try to copy +# the style sheet file to the HTML output directory, so don't put your own +# stylesheet in the HTML output directory as well, or it will be erased! + +HTML_STYLESHEET = + +# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, +# files or namespaces will be aligned in HTML using tables. If set to +# NO a bullet list will be used. + +HTML_ALIGN_MEMBERS = YES + +# If the GENERATE_HTMLHELP tag is set to YES, additional index files +# will be generated that can be used as input for tools like the +# Microsoft HTML help workshop to generate a compressed HTML help file (.chm) +# of the generated HTML documentation. + +GENERATE_HTMLHELP = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can +# be used to specify the file name of the resulting .chm file. You +# can add a path in front of the file if the result should not be +# written to the html output directory. + +CHM_FILE = + +# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can +# be used to specify the location (absolute path including file name) of +# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run +# the HTML help compiler on the generated index.hhp. + +HHC_LOCATION = + +# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag +# controls if a separate .chi index file is generated (YES) or that +# it should be included in the master .chm file (NO). + +GENERATE_CHI = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag +# controls whether a binary table of contents is generated (YES) or a +# normal table of contents (NO) in the .chm file. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members +# to the contents of the HTML help documentation and to the tree view. + +TOC_EXPAND = NO + +# The DISABLE_INDEX tag can be used to turn on/off the condensed index at +# top of each HTML page. The value NO (the default) enables the index and +# the value YES disables it. + +DISABLE_INDEX = NO + +# This tag can be used to set the number of enum values (range [1..20]) +# that doxygen will group on one line in the generated HTML documentation. + +ENUM_VALUES_PER_LINE = 4 + +# If the GENERATE_TREEVIEW tag is set to YES, a side panel will be +# generated containing a tree-like index structure (just like the one that +# is generated for HTML Help). For this to work a browser that supports +# JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+, +# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are +# probably better off using the HTML help feature. + +GENERATE_TREEVIEW = NO + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be +# used to set the initial width (in pixels) of the frame in which the tree +# is shown. + +TREEVIEW_WIDTH = 250 + +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- + +# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will +# generate Latex output. + +GENERATE_LATEX = NO + +# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `latex' will be used as the default path. + +LATEX_OUTPUT = latex + +# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be +# invoked. If left blank `latex' will be used as the default command name. + +LATEX_CMD_NAME = latex + +# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to +# generate index for LaTeX. If left blank `makeindex' will be used as the +# default command name. + +MAKEINDEX_CMD_NAME = makeindex + +# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact +# LaTeX documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_LATEX = NO + +# The PAPER_TYPE tag can be used to set the paper type that is used +# by the printer. Possible values are: a4, a4wide, letter, legal and +# executive. If left blank a4wide will be used. + +PAPER_TYPE = a4wide + +# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX +# packages that should be included in the LaTeX output. + +EXTRA_PACKAGES = + +# The LATEX_HEADER tag can be used to specify a personal LaTeX header for +# the generated latex document. The header should contain everything until +# the first chapter. If it is left blank doxygen will generate a +# standard header. Notice: only use this tag if you know what you are doing! + +LATEX_HEADER = + +# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated +# is prepared for conversion to pdf (using ps2pdf). The pdf file will +# contain links (just like the HTML output) instead of page references +# This makes the output suitable for online browsing using a pdf viewer. + +PDF_HYPERLINKS = NO + +# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of +# plain latex in the generated Makefile. Set this option to YES to get a +# higher quality PDF documentation. + +USE_PDFLATEX = NO + +# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. +# command to the generated LaTeX files. This will instruct LaTeX to keep +# running if errors occur, instead of asking the user for help. +# This option is also used when generating formulas in HTML. + +LATEX_BATCHMODE = NO + +# If LATEX_HIDE_INDICES is set to YES then doxygen will not +# include the index chapters (such as File Index, Compound Index, etc.) +# in the output. + +LATEX_HIDE_INDICES = NO + +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- + +# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output +# The RTF output is optimized for Word 97 and may not look very pretty with +# other RTF readers or editors. + +GENERATE_RTF = NO + +# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `rtf' will be used as the default path. + +RTF_OUTPUT = rtf + +# If the COMPACT_RTF tag is set to YES Doxygen generates more compact +# RTF documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_RTF = NO + +# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated +# will contain hyperlink fields. The RTF file will +# contain links (just like the HTML output) instead of page references. +# This makes the output suitable for online browsing using WORD or other +# programs which support those fields. +# Note: wordpad (write) and others do not support links. + +RTF_HYPERLINKS = NO + +# Load stylesheet definitions from file. Syntax is similar to doxygen's +# config file, i.e. a series of assignments. You only have to provide +# replacements, missing definitions are set to their default value. + +RTF_STYLESHEET_FILE = + +# Set optional variables used in the generation of an rtf document. +# Syntax is similar to doxygen's config file. + +RTF_EXTENSIONS_FILE = + +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- + +# If the GENERATE_MAN tag is set to YES (the default) Doxygen will +# generate man pages + +GENERATE_MAN = NO + +# The MAN_OUTPUT tag is used to specify where the man pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `man' will be used as the default path. + +MAN_OUTPUT = man + +# The MAN_EXTENSION tag determines the extension that is added to +# the generated man pages (default is the subroutine's section .3) + +MAN_EXTENSION = .3 + +# If the MAN_LINKS tag is set to YES and Doxygen generates man output, +# then it will generate one additional man file for each entity +# documented in the real man page(s). These additional files +# only source the real man page, but without them the man command +# would be unable to find the correct page. The default is NO. + +MAN_LINKS = NO + +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- + +# If the GENERATE_XML tag is set to YES Doxygen will +# generate an XML file that captures the structure of +# the code including all documentation. + +GENERATE_XML = NO + +# The XML_OUTPUT tag is used to specify where the XML pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `xml' will be used as the default path. + +XML_OUTPUT = xml + +# The XML_SCHEMA tag can be used to specify an XML schema, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_SCHEMA = + +# The XML_DTD tag can be used to specify an XML DTD, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_DTD = + +# If the XML_PROGRAMLISTING tag is set to YES Doxygen will +# dump the program listings (including syntax highlighting +# and cross-referencing information) to the XML output. Note that +# enabling this will significantly increase the size of the XML output. + +XML_PROGRAMLISTING = YES + +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- + +# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will +# generate an AutoGen Definitions (see autogen.sf.net) file +# that captures the structure of the code including all +# documentation. Note that this feature is still experimental +# and incomplete at the moment. + +GENERATE_AUTOGEN_DEF = NO + +#--------------------------------------------------------------------------- +# configuration options related to the Perl module output +#--------------------------------------------------------------------------- + +# If the GENERATE_PERLMOD tag is set to YES Doxygen will +# generate a Perl module file that captures the structure of +# the code including all documentation. Note that this +# feature is still experimental and incomplete at the +# moment. + +GENERATE_PERLMOD = NO + +# If the PERLMOD_LATEX tag is set to YES Doxygen will generate +# the necessary Makefile rules, Perl scripts and LaTeX code to be able +# to generate PDF and DVI output from the Perl module output. + +PERLMOD_LATEX = NO + +# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be +# nicely formatted so it can be parsed by a human reader. This is useful +# if you want to understand what is going on. On the other hand, if this +# tag is set to NO the size of the Perl module output will be much smaller +# and Perl will parse it just the same. + +PERLMOD_PRETTY = YES + +# The names of the make variables in the generated doxyrules.make file +# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. +# This is useful so different doxyrules.make files included by the same +# Makefile don't overwrite each other's variables. + +PERLMOD_MAKEVAR_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- + +# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will +# evaluate all C-preprocessor directives found in the sources and include +# files. + +ENABLE_PREPROCESSING = YES + +# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro +# names in the source code. If set to NO (the default) only conditional +# compilation will be performed. Macro expansion can be done in a controlled +# way by setting EXPAND_ONLY_PREDEF to YES. + +MACRO_EXPANSION = NO + +# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES +# then the macro expansion is limited to the macros specified with the +# PREDEFINED and EXPAND_AS_DEFINED tags. + +EXPAND_ONLY_PREDEF = NO + +# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files +# in the INCLUDE_PATH (see below) will be search if a #include is found. + +SEARCH_INCLUDES = YES + +# The INCLUDE_PATH tag can be used to specify one or more directories that +# contain include files that are not input files but should be processed by +# the preprocessor. + +INCLUDE_PATH = + +# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard +# patterns (like *.h and *.hpp) to filter out the header-files in the +# directories. If left blank, the patterns specified with FILE_PATTERNS will +# be used. + +INCLUDE_FILE_PATTERNS = + +# The PREDEFINED tag can be used to specify one or more macro names that +# are defined before the preprocessor is started (similar to the -D option of +# gcc). The argument of the tag is a list of macros of the form: name +# or name=definition (no spaces). If the definition and the = are +# omitted =1 is assumed. To prevent a macro definition from being +# undefined via #undef or recursively expanded use the := operator +# instead of the = operator. + +PREDEFINED = + +# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then +# this tag can be used to specify a list of macro names that should be expanded. +# The macro definition that is found in the sources will be used. +# Use the PREDEFINED tag if you want to use a different macro definition. + +EXPAND_AS_DEFINED = + +# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then +# doxygen's preprocessor will remove all function-like macros that are alone +# on a line, have an all uppercase name, and do not end with a semicolon. Such +# function macros are typically used for boiler-plate code, and will confuse +# the parser if not removed. + +SKIP_FUNCTION_MACROS = YES + +#--------------------------------------------------------------------------- +# Configuration::additions related to external references +#--------------------------------------------------------------------------- + +# The TAGFILES option can be used to specify one or more tagfiles. +# Optionally an initial location of the external documentation +# can be added for each tagfile. The format of a tag file without +# this location is as follows: +# TAGFILES = file1 file2 ... +# Adding location for the tag files is done as follows: +# TAGFILES = file1=loc1 "file2 = loc2" ... +# where "loc1" and "loc2" can be relative or absolute paths or +# URLs. If a location is present for each tag, the installdox tool +# does not have to be run to correct the links. +# Note that each tag file must have a unique name +# (where the name does NOT include the path) +# If a tag file is not located in the directory in which doxygen +# is run, you must also specify the path to the tagfile here. + +TAGFILES = + +# When a file name is specified after GENERATE_TAGFILE, doxygen will create +# a tag file that is based on the input files it reads. + +GENERATE_TAGFILE = + +# If the ALLEXTERNALS tag is set to YES all external classes will be listed +# in the class index. If set to NO only the inherited external classes +# will be listed. + +ALLEXTERNALS = NO + +# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed +# in the modules index. If set to NO, only the current project's groups will +# be listed. + +EXTERNAL_GROUPS = YES + +# The PERL_PATH should be the absolute path and name of the perl script +# interpreter (i.e. the result of `which perl'). + +PERL_PATH = /usr/bin/perl + +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- + +# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will +# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base +# or super classes. Setting the tag to NO turns the diagrams off. Note that +# this option is superseded by the HAVE_DOT option below. This is only a +# fallback. It is recommended to install and use dot, since it yields more +# powerful graphs. + +CLASS_DIAGRAMS = YES + +# If set to YES, the inheritance and collaboration graphs will hide +# inheritance and usage relations if the target is undocumented +# or is not a class. + +HIDE_UNDOC_RELATIONS = YES + +# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is +# available from the path. This tool is part of Graphviz, a graph visualization +# toolkit from AT&T and Lucent Bell Labs. The other options in this section +# have no effect if this option is set to NO (the default) + +HAVE_DOT = NO + +# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect inheritance relations. Setting this tag to YES will force the +# the CLASS_DIAGRAMS tag to NO. + +CLASS_GRAPH = YES + +# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect implementation dependencies (inheritance, containment, and +# class references variables) of the class with other documented classes. + +COLLABORATION_GRAPH = YES + +# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for groups, showing the direct groups dependencies + +GROUP_GRAPHS = YES + +# If the UML_LOOK tag is set to YES doxygen will generate inheritance and +# collaboration diagrams in a style similar to the OMG's Unified Modeling +# Language. + +UML_LOOK = NO + +# If set to YES, the inheritance and collaboration graphs will show the +# relations between templates and their instances. + +TEMPLATE_RELATIONS = NO + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT +# tags are set to YES then doxygen will generate a graph for each documented +# file showing the direct and indirect include dependencies of the file with +# other documented files. + +INCLUDE_GRAPH = YES + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and +# HAVE_DOT tags are set to YES then doxygen will generate a graph for each +# documented header file showing the documented files that directly or +# indirectly include this file. + +INCLUDED_BY_GRAPH = YES + +# If the CALL_GRAPH and HAVE_DOT tags are set to YES then doxygen will +# generate a call dependency graph for every global function or class method. +# Note that enabling this option will significantly increase the time of a run. +# So in most cases it will be better to enable call graphs for selected +# functions only using the \callgraph command. + +CALL_GRAPH = NO + +# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then doxygen will +# generate a caller dependency graph for every global function or class method. +# Note that enabling this option will significantly increase the time of a run. +# So in most cases it will be better to enable caller graphs for selected +# functions only using the \callergraph command. + +CALLER_GRAPH = NO + +# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen +# will graphical hierarchy of all classes instead of a textual one. + +GRAPHICAL_HIERARCHY = YES + +# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES +# then doxygen will show the dependencies a directory has on other directories +# in a graphical way. The dependency relations are determined by the #include +# relations between the files in the directories. + +DIRECTORY_GRAPH = YES + +# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images +# generated by dot. Possible values are png, jpg, or gif +# If left blank png will be used. + +DOT_IMAGE_FORMAT = png + +# The tag DOT_PATH can be used to specify the path where the dot tool can be +# found. If left blank, it is assumed the dot tool can be found in the path. + +DOT_PATH = + +# The DOTFILE_DIRS tag can be used to specify one or more directories that +# contain dot files that are included in the documentation (see the +# \dotfile command). + +DOTFILE_DIRS = + +# The MAX_DOT_GRAPH_WIDTH tag can be used to set the maximum allowed width +# (in pixels) of the graphs generated by dot. If a graph becomes larger than +# this value, doxygen will try to truncate the graph, so that it fits within +# the specified constraint. Beware that most browsers cannot cope with very +# large images. + +MAX_DOT_GRAPH_WIDTH = 1024 + +# The MAX_DOT_GRAPH_HEIGHT tag can be used to set the maximum allows height +# (in pixels) of the graphs generated by dot. If a graph becomes larger than +# this value, doxygen will try to truncate the graph, so that it fits within +# the specified constraint. Beware that most browsers cannot cope with very +# large images. + +MAX_DOT_GRAPH_HEIGHT = 1024 + +# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the +# graphs generated by dot. A depth value of 3 means that only nodes reachable +# from the root by following a path via at most 3 edges will be shown. Nodes +# that lay further from the root node will be omitted. Note that setting this +# option to 1 or 2 may greatly reduce the computation time needed for large +# code bases. Also note that a graph may be further truncated if the graph's +# image dimensions are not sufficient to fit the graph (see MAX_DOT_GRAPH_WIDTH +# and MAX_DOT_GRAPH_HEIGHT). If 0 is used for the depth value (the default), +# the graph is not depth-constrained. + +MAX_DOT_GRAPH_DEPTH = 0 + +# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent +# background. This is disabled by default, which results in a white background. +# Warning: Depending on the platform used, enabling this option may lead to +# badly anti-aliased labels on the edges of a graph (i.e. they become hard to +# read). + +DOT_TRANSPARENT = NO + +# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output +# files in one run (i.e. multiple -o and -T options on the command line). This +# makes dot run faster, but since only newer versions of dot (>1.8.10) +# support this, this feature is disabled by default. + +DOT_MULTI_TARGETS = NO + +# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will +# generate a legend page explaining the meaning of the various boxes and +# arrows in the dot generated graphs. + +GENERATE_LEGEND = YES + +# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will +# remove the intermediate dot files that are used to generate +# the various graphs. + +DOT_CLEANUP = YES + +#--------------------------------------------------------------------------- +# Configuration::additions related to the search engine +#--------------------------------------------------------------------------- + +# The SEARCHENGINE tag specifies whether or not a search engine should be +# used. If set to NO the values of all tags below this one will be ignored. + +SEARCHENGINE = NO diff --git a/solution/Makefile b/solution/Makefile new file mode 100644 index 0000000..665d251 --- /dev/null +++ b/solution/Makefile @@ -0,0 +1,46 @@ +# GNU Make solution makefile autogenerated by GENie +# Type "make help" for usage help + +ifndef config + config=debug64 +endif +export config + +PROJECTS := spasm sprt sprun + +.PHONY: all clean help $(PROJECTS) + +all: $(PROJECTS) + +sprt: + @echo "==== Building sprt ($(config)) ====" + @${MAKE} --no-print-directory -C . -f sprt.make + +spasm: + @echo "==== Building spasm ($(config)) ====" + @${MAKE} --no-print-directory -C . -f spasm.make + +sprun: sprt + @echo "==== Building sprun ($(config)) ====" + @${MAKE} --no-print-directory -C . -f sprun.make + +clean: + @${MAKE} --no-print-directory -C . -f sprt.make clean + @${MAKE} --no-print-directory -C . -f spasm.make clean + @${MAKE} --no-print-directory -C . -f sprun.make clean + +help: + @echo "Usage: make [config=name] [target]" + @echo "" + @echo "CONFIGURATIONS:" + @echo " debug64" + @echo " release64" + @echo "" + @echo "TARGETS:" + @echo " all (default)" + @echo " clean" + @echo " sprt" + @echo " spasm" + @echo " sprun" + @echo "" + @echo "For more information, see https://github.com/bkaradzic/genie" diff --git a/solution/genie.lua b/solution/genie.lua new file mode 100644 index 0000000..b3bb00f --- /dev/null +++ b/solution/genie.lua @@ -0,0 +1,54 @@ +solution 'spasm' + configurations {'Debug', 'Release'} + platforms { 'x64' } + flags { + 'FatalWarnings', + 'ExtraWarnings', + 'Cpp14', + 'Symbols', + } + + defines { + '_SCL_SECURE_NO_WARNINGS', + } + + local root = '../build/' + + configuration 'Debug' + targetdir(root .. 'bin/Debug') + objdir(root .. 'obj/Debug') + + configuration 'Release' + flags 'OptimizeSpeed' + targetdir(root .. 'bin/Release') + objdir(root .. 'obj/Release') + configuration '*' + + project 'sprt' + kind 'StaticLib' + language 'C++' + uuid(os.uuid('sprt')) + files '../src/*.cpp' + removefiles '../src/main.cpp' + files '../src/*.h' + + project 'spasm' + kind 'ConsoleApp' + language 'C++' + uuid(os.uuid('spasm')) + files '../src/asm/*.cpp' + removefiles { + '../src/asm/lexdump.cpp', + '../src/asm/lexdump3.cpp', + } + files '../src/asm/*.h' + + project 'sprun' + kind 'ConsoleApp' + language 'C++' + uuid(os.uuid('sprun')) + files '../src/main.cpp' + links 'sprt' + + -- include '../test' + startproject 'sprun' diff --git a/solution/spasm.make b/solution/spasm.make new file mode 100644 index 0000000..4d90252 --- /dev/null +++ b/solution/spasm.make @@ -0,0 +1,197 @@ +# GNU Make project makefile autogenerated by GENie +ifndef config + config=debug64 +endif + +ifndef verbose + SILENT = @ +endif + +SHELLTYPE := msdos +ifeq (,$(ComSpec)$(COMSPEC)) + SHELLTYPE := posix +endif +ifeq (/bin,$(findstring /bin,$(SHELL))) + SHELLTYPE := posix +endif +ifeq (/bin,$(findstring /bin,$(MAKESHELL))) + SHELLTYPE := posix +endif + +ifeq (posix,$(SHELLTYPE)) + MKDIR = $(SILENT) mkdir -p "$(1)" + COPY = $(SILENT) cp -fR "$(1)" "$(2)" + RM = $(SILENT) rm -f "$(1)" +else + MKDIR = $(SILENT) mkdir "$(subst /,\\,$(1))" 2> nul || exit 0 + COPY = $(SILENT) copy /Y "$(subst /,\\,$(1))" "$(subst /,\\,$(2))" + RM = $(SILENT) del /F "$(subst /,\\,$(1))" 2> nul || exit 0 +endif + +CC = gcc +CXX = g++ +AR = ar + +ifndef RESCOMP + ifdef WINDRES + RESCOMP = $(WINDRES) + else + RESCOMP = windres + endif +endif + +MAKEFILE = spasm.make + +ifeq ($(config),debug64) + OBJDIR = ../build/obj/Debug/x64/Debug/spasm + TARGETDIR = ../build/bin/Debug + TARGET = $(TARGETDIR)/spasm + DEFINES += -D_SCL_SECURE_NO_WARNINGS + ALL_CPPFLAGS += $(CPPFLAGS) -MMD -MP -MP $(DEFINES) $(INCLUDES) + ALL_ASMFLAGS += $(ASMFLAGS) $(CFLAGS) $(ALL_CPPFLAGS) $(ARCH) -Werror -Wall -Wextra -g -m64 + ALL_CFLAGS += $(CFLAGS) $(ALL_CPPFLAGS) $(ARCH) -Werror -Wall -Wextra -g -m64 + ALL_CXXFLAGS += $(CXXFLAGS) $(CFLAGS) $(ALL_CPPFLAGS) $(ARCH) -Werror -Wall -Wextra -g -m64 -std=c++14 + ALL_OBJCFLAGS += $(CFLAGS) $(ALL_CPPFLAGS) $(ARCH) -Werror -Wall -Wextra -g -m64 + ALL_OBJCPPFLAGS += $(CXXFLAGS) $(CFLAGS) $(ALL_CPPFLAGS) $(ARCH) -Werror -Wall -Wextra -g -m64 -std=c++14 + ALL_RESFLAGS += $(RESFLAGS) $(DEFINES) $(INCLUDES) + ALL_LDFLAGS += $(LDFLAGS) -m64 + LDDEPS += + LIBS += $(LDDEPS) + EXTERNAL_LIBS += + LINKOBJS = $(OBJECTS) + LINKCMD = $(CXX) -o $(TARGET) $(LINKOBJS) $(RESOURCES) $(ARCH) $(ALL_LDFLAGS) $(LIBS) + OBJECTS := \ + $(OBJDIR)/src/asm/assembler.o \ + $(OBJDIR)/src/asm/bytecode.o \ + $(OBJDIR)/src/asm/lexer.o \ + $(OBJDIR)/src/asm/main.o \ + $(OBJDIR)/src/asm/symbol.o \ + $(OBJDIR)/src/asm/token.o \ + $(OBJDIR)/src/asm/tokenizer.o \ + + define PREBUILDCMDS + endef + define PRELINKCMDS + endef + define POSTBUILDCMDS + endef +endif + +ifeq ($(config),release64) + OBJDIR = ../build/obj/Release/x64/Release/spasm + TARGETDIR = ../build/bin/Release + TARGET = $(TARGETDIR)/spasm + DEFINES += -D_SCL_SECURE_NO_WARNINGS + ALL_CPPFLAGS += $(CPPFLAGS) -MMD -MP -MP $(DEFINES) $(INCLUDES) + ALL_ASMFLAGS += $(ASMFLAGS) $(CFLAGS) $(ALL_CPPFLAGS) $(ARCH) -Werror -Wall -Wextra -g -O3 -m64 + ALL_CFLAGS += $(CFLAGS) $(ALL_CPPFLAGS) $(ARCH) -Werror -Wall -Wextra -g -O3 -m64 + ALL_CXXFLAGS += $(CXXFLAGS) $(CFLAGS) $(ALL_CPPFLAGS) $(ARCH) -Werror -Wall -Wextra -g -O3 -m64 -std=c++14 + ALL_OBJCFLAGS += $(CFLAGS) $(ALL_CPPFLAGS) $(ARCH) -Werror -Wall -Wextra -g -O3 -m64 + ALL_OBJCPPFLAGS += $(CXXFLAGS) $(CFLAGS) $(ALL_CPPFLAGS) $(ARCH) -Werror -Wall -Wextra -g -O3 -m64 -std=c++14 + ALL_RESFLAGS += $(RESFLAGS) $(DEFINES) $(INCLUDES) + ALL_LDFLAGS += $(LDFLAGS) -m64 + LDDEPS += + LIBS += $(LDDEPS) + EXTERNAL_LIBS += + LINKOBJS = $(OBJECTS) + LINKCMD = $(CXX) -o $(TARGET) $(LINKOBJS) $(RESOURCES) $(ARCH) $(ALL_LDFLAGS) $(LIBS) + OBJECTS := \ + $(OBJDIR)/src/asm/assembler.o \ + $(OBJDIR)/src/asm/bytecode.o \ + $(OBJDIR)/src/asm/lexer.o \ + $(OBJDIR)/src/asm/main.o \ + $(OBJDIR)/src/asm/symbol.o \ + $(OBJDIR)/src/asm/token.o \ + $(OBJDIR)/src/asm/tokenizer.o \ + + define PREBUILDCMDS + endef + define PRELINKCMDS + endef + define POSTBUILDCMDS + endef +endif + +OBJDIRS := \ + $(OBJDIR) \ + $(OBJDIR)/src/asm \ + +RESOURCES := \ + +.PHONY: clean prebuild prelink + +all: $(OBJDIRS) $(TARGETDIR) prebuild prelink $(TARGET) + @: + +$(TARGET): $(GCH) $(OBJECTS) $(LDDEPS) $(EXTERNAL_LIBS) $(RESOURCES) | $(TARGETDIR) $(OBJDIRS) + @echo Linking spasm + $(SILENT) $(LINKCMD) + $(POSTBUILDCMDS) + +$(TARGETDIR): + @echo Creating $(TARGETDIR) + -$(call MKDIR,$(TARGETDIR)) + +$(OBJDIRS): + @echo Creating $(@) + -$(call MKDIR,$@) + +clean: + @echo Cleaning spasm +ifeq (posix,$(SHELLTYPE)) + $(SILENT) rm -f $(TARGET) + $(SILENT) rm -rf $(OBJDIR) +else + $(SILENT) if exist $(subst /,\\,$(TARGET)) del $(subst /,\\,$(TARGET)) + $(SILENT) if exist $(subst /,\\,$(OBJDIR)) rmdir /s /q $(subst /,\\,$(OBJDIR)) +endif + +prebuild: + $(PREBUILDCMDS) + +prelink: + $(PRELINKCMDS) + +ifneq (,$(PCH)) +$(GCH): $(PCH) $(MAKEFILE) | $(OBJDIR) + @echo $(notdir $<) + $(SILENT) $(CXX) $(ALL_CXXFLAGS) -x c++-header $(DEFINES) $(INCLUDES) -o "$@" -c "$<" + +$(GCH_OBJC): $(PCH) $(MAKEFILE) | $(OBJDIR) + @echo $(notdir $<) + $(SILENT) $(CXX) $(ALL_OBJCPPFLAGS) -x objective-c++-header $(DEFINES) $(INCLUDES) -o "$@" -c "$<" +endif + +$(OBJDIR)/src/asm/assembler.o: ../src/asm/assembler.cpp $(GCH) $(MAKEFILE) | $(OBJDIR)/src/asm + @echo $(notdir $<) + $(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -c "$<" + +$(OBJDIR)/src/asm/bytecode.o: ../src/asm/bytecode.cpp $(GCH) $(MAKEFILE) | $(OBJDIR)/src/asm + @echo $(notdir $<) + $(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -c "$<" + +$(OBJDIR)/src/asm/lexer.o: ../src/asm/lexer.cpp $(GCH) $(MAKEFILE) | $(OBJDIR)/src/asm + @echo $(notdir $<) + $(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -c "$<" + +$(OBJDIR)/src/asm/main.o: ../src/asm/main.cpp $(GCH) $(MAKEFILE) | $(OBJDIR)/src/asm + @echo $(notdir $<) + $(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -c "$<" + +$(OBJDIR)/src/asm/symbol.o: ../src/asm/symbol.cpp $(GCH) $(MAKEFILE) | $(OBJDIR)/src/asm + @echo $(notdir $<) + $(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -c "$<" + +$(OBJDIR)/src/asm/token.o: ../src/asm/token.cpp $(GCH) $(MAKEFILE) | $(OBJDIR)/src/asm + @echo $(notdir $<) + $(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -c "$<" + +$(OBJDIR)/src/asm/tokenizer.o: ../src/asm/tokenizer.cpp $(GCH) $(MAKEFILE) | $(OBJDIR)/src/asm + @echo $(notdir $<) + $(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -c "$<" + +-include $(OBJECTS:%.o=%.d) +ifneq (,$(PCH)) + -include $(OBJDIR)/$(notdir $(PCH)).d + -include $(OBJDIR)/$(notdir $(PCH))_objc.d +endif diff --git a/solution/spasm.sln b/solution/spasm.sln new file mode 100644 index 0000000..1f36001 --- /dev/null +++ b/solution/spasm.sln @@ -0,0 +1,37 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 14 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sprun", "sprun.vcxproj", "{FD605F10-6975-87C1-32F7-2A219ECA83F2}" + ProjectSection(ProjectDependencies) = postProject + {AE0A9E7C-9A41-9F0D-432E-85102F441B0F} = {AE0A9E7C-9A41-9F0D-432E-85102F441B0F} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sprt", "sprt.vcxproj", "{AE0A9E7C-9A41-9F0D-432E-85102F441B0F}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "spasm", "spasm.vcxproj", "{69185F10-D52C-87C1-9EAE-2A210A8283F2}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {FD605F10-6975-87C1-32F7-2A219ECA83F2}.Debug|x64.ActiveCfg = Debug|x64 + {FD605F10-6975-87C1-32F7-2A219ECA83F2}.Debug|x64.Build.0 = Debug|x64 + {FD605F10-6975-87C1-32F7-2A219ECA83F2}.Release|x64.ActiveCfg = Release|x64 + {FD605F10-6975-87C1-32F7-2A219ECA83F2}.Release|x64.Build.0 = Release|x64 + {AE0A9E7C-9A41-9F0D-432E-85102F441B0F}.Debug|x64.ActiveCfg = Debug|x64 + {AE0A9E7C-9A41-9F0D-432E-85102F441B0F}.Debug|x64.Build.0 = Debug|x64 + {AE0A9E7C-9A41-9F0D-432E-85102F441B0F}.Release|x64.ActiveCfg = Release|x64 + {AE0A9E7C-9A41-9F0D-432E-85102F441B0F}.Release|x64.Build.0 = Release|x64 + {69185F10-D52C-87C1-9EAE-2A210A8283F2}.Debug|x64.ActiveCfg = Debug|x64 + {69185F10-D52C-87C1-9EAE-2A210A8283F2}.Debug|x64.Build.0 = Debug|x64 + {69185F10-D52C-87C1-9EAE-2A210A8283F2}.Release|x64.ActiveCfg = Release|x64 + {69185F10-D52C-87C1-9EAE-2A210A8283F2}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + EndGlobalSection +EndGlobal diff --git a/solution/spasm.vcxproj b/solution/spasm.vcxproj new file mode 100644 index 0000000..801feb8 --- /dev/null +++ b/solution/spasm.vcxproj @@ -0,0 +1,133 @@ + + + + + Debug + x64 + + + Release + x64 + + + + {69185F10-D52C-87C1-9EAE-2A210A8283F2} + spasm + 8.1 + Win32Proj + + + + Application + true + v140 + x64 + + + Application + false + v140 + x64 + + + + + + + + + + + + + ..\build\bin\Debug\ + ..\build\obj\Debug\x64\Debug\spasm\ + spasm + .exe + true + + + ..\build\bin\Release\ + ..\build\obj\Release\x64\Release\spasm\ + spasm + .exe + false + + + + %(AdditionalOptions) + Disabled + _SCL_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + false + EnableFastChecks + MultiThreadedDebugDLL + true + true + + Level4 + true + EditAndContinue + $(IntDir)spasm.compile.pdb + + + _SCL_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + + + Console + true + $(OutDir)spasm.pdb + $(OutDir)spasm.exe + mainCRTStartup + MachineX64 + + + + + %(AdditionalOptions) + MaxSpeed + _SCL_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + false + true + MultiThreadedDLL + true + true + + Level4 + true + ProgramDatabase + $(IntDir)spasm.compile.pdb + + + _SCL_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + + + Console + true + $(OutDir)spasm.pdb + true + true + $(OutDir)spasm.exe + mainCRTStartup + MachineX64 + + + + + + + + + + + + + + + + + + + + + + diff --git a/solution/spasm.vcxproj.filters b/solution/spasm.vcxproj.filters new file mode 100644 index 0000000..77f6487 --- /dev/null +++ b/solution/spasm.vcxproj.filters @@ -0,0 +1,34 @@ + + + + + {2DAB880B-99B4-887C-2230-9F7C8E38947C} + + + {6A9848A9-D677-C744-DF8F-521B4BEE2DA6} + + + + + src\asm + + + src\asm + + + src\asm + + + src\asm + + + src\asm + + + src\asm + + + src\asm + + + diff --git a/solution/spasm.vcxproj.user b/solution/spasm.vcxproj.user new file mode 100644 index 0000000..99820f1 --- /dev/null +++ b/solution/spasm.vcxproj.user @@ -0,0 +1,11 @@ + + + + WindowsLocalDebugger + + + + WindowsLocalDebugger + + + diff --git a/solution/sprt.make b/solution/sprt.make new file mode 100644 index 0000000..8d85739 --- /dev/null +++ b/solution/sprt.make @@ -0,0 +1,178 @@ +# GNU Make project makefile autogenerated by GENie +ifndef config + config=debug64 +endif + +ifndef verbose + SILENT = @ +endif + +SHELLTYPE := msdos +ifeq (,$(ComSpec)$(COMSPEC)) + SHELLTYPE := posix +endif +ifeq (/bin,$(findstring /bin,$(SHELL))) + SHELLTYPE := posix +endif +ifeq (/bin,$(findstring /bin,$(MAKESHELL))) + SHELLTYPE := posix +endif + +ifeq (posix,$(SHELLTYPE)) + MKDIR = $(SILENT) mkdir -p "$(1)" + COPY = $(SILENT) cp -fR "$(1)" "$(2)" + RM = $(SILENT) rm -f "$(1)" +else + MKDIR = $(SILENT) mkdir "$(subst /,\\,$(1))" 2> nul || exit 0 + COPY = $(SILENT) copy /Y "$(subst /,\\,$(1))" "$(subst /,\\,$(2))" + RM = $(SILENT) del /F "$(subst /,\\,$(1))" 2> nul || exit 0 +endif + +CC = gcc +CXX = g++ +AR = ar + +ifndef RESCOMP + ifdef WINDRES + RESCOMP = $(WINDRES) + else + RESCOMP = windres + endif +endif + +MAKEFILE = sprt.make + +ifeq ($(config),debug64) + OBJDIR = ../build/obj/Debug/x64/Debug/sprt + TARGETDIR = ../build/bin/Debug + TARGET = $(TARGETDIR)/libsprt.a + DEFINES += -D_SCL_SECURE_NO_WARNINGS + ALL_CPPFLAGS += $(CPPFLAGS) -MMD -MP -MP $(DEFINES) $(INCLUDES) + ALL_ASMFLAGS += $(ASMFLAGS) $(CFLAGS) $(ALL_CPPFLAGS) $(ARCH) -Werror -Wall -Wextra -g -m64 + ALL_CFLAGS += $(CFLAGS) $(ALL_CPPFLAGS) $(ARCH) -Werror -Wall -Wextra -g -m64 + ALL_CXXFLAGS += $(CXXFLAGS) $(CFLAGS) $(ALL_CPPFLAGS) $(ARCH) -Werror -Wall -Wextra -g -m64 -std=c++14 + ALL_OBJCFLAGS += $(CFLAGS) $(ALL_CPPFLAGS) $(ARCH) -Werror -Wall -Wextra -g -m64 + ALL_OBJCPPFLAGS += $(CXXFLAGS) $(CFLAGS) $(ALL_CPPFLAGS) $(ARCH) -Werror -Wall -Wextra -g -m64 -std=c++14 + ALL_RESFLAGS += $(RESFLAGS) $(DEFINES) $(INCLUDES) + ALL_LDFLAGS += $(LDFLAGS) -m64 + LDDEPS += + LIBS += $(LDDEPS) + EXTERNAL_LIBS += + LINKOBJS = $(OBJECTS) + LINKCMD = $(AR) -rcs $(TARGET) + OBJECTS := \ + $(OBJDIR)/src/dstack.o \ + $(OBJDIR)/src/frames.o \ + $(OBJDIR)/src/spasm.o \ + + define PREBUILDCMDS + endef + define PRELINKCMDS + endef + define POSTBUILDCMDS + endef +endif + +ifeq ($(config),release64) + OBJDIR = ../build/obj/Release/x64/Release/sprt + TARGETDIR = ../build/bin/Release + TARGET = $(TARGETDIR)/libsprt.a + DEFINES += -D_SCL_SECURE_NO_WARNINGS + ALL_CPPFLAGS += $(CPPFLAGS) -MMD -MP -MP $(DEFINES) $(INCLUDES) + ALL_ASMFLAGS += $(ASMFLAGS) $(CFLAGS) $(ALL_CPPFLAGS) $(ARCH) -Werror -Wall -Wextra -g -O3 -m64 + ALL_CFLAGS += $(CFLAGS) $(ALL_CPPFLAGS) $(ARCH) -Werror -Wall -Wextra -g -O3 -m64 + ALL_CXXFLAGS += $(CXXFLAGS) $(CFLAGS) $(ALL_CPPFLAGS) $(ARCH) -Werror -Wall -Wextra -g -O3 -m64 -std=c++14 + ALL_OBJCFLAGS += $(CFLAGS) $(ALL_CPPFLAGS) $(ARCH) -Werror -Wall -Wextra -g -O3 -m64 + ALL_OBJCPPFLAGS += $(CXXFLAGS) $(CFLAGS) $(ALL_CPPFLAGS) $(ARCH) -Werror -Wall -Wextra -g -O3 -m64 -std=c++14 + ALL_RESFLAGS += $(RESFLAGS) $(DEFINES) $(INCLUDES) + ALL_LDFLAGS += $(LDFLAGS) -m64 + LDDEPS += + LIBS += $(LDDEPS) + EXTERNAL_LIBS += + LINKOBJS = $(OBJECTS) + LINKCMD = $(AR) -rcs $(TARGET) + OBJECTS := \ + $(OBJDIR)/src/dstack.o \ + $(OBJDIR)/src/frames.o \ + $(OBJDIR)/src/spasm.o \ + + define PREBUILDCMDS + endef + define PRELINKCMDS + endef + define POSTBUILDCMDS + endef +endif + +OBJDIRS := \ + $(OBJDIR) \ + $(OBJDIR)/src \ + +RESOURCES := \ + +.PHONY: clean prebuild prelink + +all: $(OBJDIRS) $(TARGETDIR) prebuild prelink $(TARGET) + @: + +$(TARGET): $(GCH) $(OBJECTS) $(LDDEPS) $(EXTERNAL_LIBS) $(RESOURCES) | $(TARGETDIR) $(OBJDIRS) + @echo Archiving sprt +ifeq (posix,$(SHELLTYPE)) + $(SILENT) rm -f $(TARGET) +else + $(SILENT) if exist $(subst /,\\,$(TARGET)) del $(subst /,\\,$(TARGET)) +endif + $(SILENT) $(LINKCMD) $(LINKOBJS) + $(POSTBUILDCMDS) + +$(TARGETDIR): + @echo Creating $(TARGETDIR) + -$(call MKDIR,$(TARGETDIR)) + +$(OBJDIRS): + @echo Creating $(@) + -$(call MKDIR,$@) + +clean: + @echo Cleaning sprt +ifeq (posix,$(SHELLTYPE)) + $(SILENT) rm -f $(TARGET) + $(SILENT) rm -rf $(OBJDIR) +else + $(SILENT) if exist $(subst /,\\,$(TARGET)) del $(subst /,\\,$(TARGET)) + $(SILENT) if exist $(subst /,\\,$(OBJDIR)) rmdir /s /q $(subst /,\\,$(OBJDIR)) +endif + +prebuild: + $(PREBUILDCMDS) + +prelink: + $(PRELINKCMDS) + +ifneq (,$(PCH)) +$(GCH): $(PCH) $(MAKEFILE) | $(OBJDIR) + @echo $(notdir $<) + $(SILENT) $(CXX) $(ALL_CXXFLAGS) -x c++-header $(DEFINES) $(INCLUDES) -o "$@" -c "$<" + +$(GCH_OBJC): $(PCH) $(MAKEFILE) | $(OBJDIR) + @echo $(notdir $<) + $(SILENT) $(CXX) $(ALL_OBJCPPFLAGS) -x objective-c++-header $(DEFINES) $(INCLUDES) -o "$@" -c "$<" +endif + +$(OBJDIR)/src/dstack.o: ../src/dstack.cpp $(GCH) $(MAKEFILE) | $(OBJDIR)/src + @echo $(notdir $<) + $(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -c "$<" + +$(OBJDIR)/src/frames.o: ../src/frames.cpp $(GCH) $(MAKEFILE) | $(OBJDIR)/src + @echo $(notdir $<) + $(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -c "$<" + +$(OBJDIR)/src/spasm.o: ../src/spasm.cpp $(GCH) $(MAKEFILE) | $(OBJDIR)/src + @echo $(notdir $<) + $(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -c "$<" + +-include $(OBJECTS:%.o=%.d) +ifneq (,$(PCH)) + -include $(OBJDIR)/$(notdir $(PCH)).d + -include $(OBJDIR)/$(notdir $(PCH))_objc.d +endif diff --git a/solution/sprt.vcxproj b/solution/sprt.vcxproj new file mode 100644 index 0000000..760d501 --- /dev/null +++ b/solution/sprt.vcxproj @@ -0,0 +1,125 @@ + + + + + Debug + x64 + + + Release + x64 + + + + {AE0A9E7C-9A41-9F0D-432E-85102F441B0F} + sprt + 8.1 + Win32Proj + + + + StaticLibrary + true + v140 + x64 + + + StaticLibrary + false + v140 + x64 + + + + + + + + + + + + + ..\build\bin\Debug\ + ..\build\obj\Debug\x64\Debug\sprt\ + sprt + .lib + + + ..\build\bin\Release\ + ..\build\obj\Release\x64\Release\sprt\ + sprt + .lib + + + + %(AdditionalOptions) + Disabled + _SCL_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + false + EnableFastChecks + MultiThreadedDebugDLL + true + true + + Level4 + true + EditAndContinue + $(OutDir)sprt.pdb + + + _SCL_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + + + $(OutDir)sprt.lib + MachineX64 + + + Windows + true + $(OutDir)sprt.pdb + + + + + %(AdditionalOptions) + MaxSpeed + _SCL_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + false + true + MultiThreadedDLL + true + true + + Level4 + true + ProgramDatabase + $(OutDir)sprt.pdb + + + _SCL_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + + + $(OutDir)sprt.lib + MachineX64 + + + Windows + true + $(OutDir)sprt.pdb + true + true + + + + + + + + + + + + + + diff --git a/solution/sprt.vcxproj.filters b/solution/sprt.vcxproj.filters new file mode 100644 index 0000000..c111a28 --- /dev/null +++ b/solution/sprt.vcxproj.filters @@ -0,0 +1,19 @@ + + + + + {2DAB880B-99B4-887C-2230-9F7C8E38947C} + + + + + src + + + src + + + src + + + diff --git a/solution/sprt.vcxproj.user b/solution/sprt.vcxproj.user new file mode 100644 index 0000000..99820f1 --- /dev/null +++ b/solution/sprt.vcxproj.user @@ -0,0 +1,11 @@ + + + + WindowsLocalDebugger + + + + WindowsLocalDebugger + + + diff --git a/solution/sprun.make b/solution/sprun.make new file mode 100644 index 0000000..7b9be59 --- /dev/null +++ b/solution/sprun.make @@ -0,0 +1,161 @@ +# GNU Make project makefile autogenerated by GENie +ifndef config + config=debug64 +endif + +ifndef verbose + SILENT = @ +endif + +SHELLTYPE := msdos +ifeq (,$(ComSpec)$(COMSPEC)) + SHELLTYPE := posix +endif +ifeq (/bin,$(findstring /bin,$(SHELL))) + SHELLTYPE := posix +endif +ifeq (/bin,$(findstring /bin,$(MAKESHELL))) + SHELLTYPE := posix +endif + +ifeq (posix,$(SHELLTYPE)) + MKDIR = $(SILENT) mkdir -p "$(1)" + COPY = $(SILENT) cp -fR "$(1)" "$(2)" + RM = $(SILENT) rm -f "$(1)" +else + MKDIR = $(SILENT) mkdir "$(subst /,\\,$(1))" 2> nul || exit 0 + COPY = $(SILENT) copy /Y "$(subst /,\\,$(1))" "$(subst /,\\,$(2))" + RM = $(SILENT) del /F "$(subst /,\\,$(1))" 2> nul || exit 0 +endif + +CC = gcc +CXX = g++ +AR = ar + +ifndef RESCOMP + ifdef WINDRES + RESCOMP = $(WINDRES) + else + RESCOMP = windres + endif +endif + +MAKEFILE = sprun.make + +ifeq ($(config),debug64) + OBJDIR = ../build/obj/Debug/x64/Debug/sprun + TARGETDIR = ../build/bin/Debug + TARGET = $(TARGETDIR)/sprun + DEFINES += -D_SCL_SECURE_NO_WARNINGS + ALL_CPPFLAGS += $(CPPFLAGS) -MMD -MP -MP $(DEFINES) $(INCLUDES) + ALL_ASMFLAGS += $(ASMFLAGS) $(CFLAGS) $(ALL_CPPFLAGS) $(ARCH) -Werror -Wall -Wextra -g -m64 + ALL_CFLAGS += $(CFLAGS) $(ALL_CPPFLAGS) $(ARCH) -Werror -Wall -Wextra -g -m64 + ALL_CXXFLAGS += $(CXXFLAGS) $(CFLAGS) $(ALL_CPPFLAGS) $(ARCH) -Werror -Wall -Wextra -g -m64 -std=c++14 + ALL_OBJCFLAGS += $(CFLAGS) $(ALL_CPPFLAGS) $(ARCH) -Werror -Wall -Wextra -g -m64 + ALL_OBJCPPFLAGS += $(CXXFLAGS) $(CFLAGS) $(ALL_CPPFLAGS) $(ARCH) -Werror -Wall -Wextra -g -m64 -std=c++14 + ALL_RESFLAGS += $(RESFLAGS) $(DEFINES) $(INCLUDES) + ALL_LDFLAGS += $(LDFLAGS) -L"../build/bin/Debug" -m64 + LDDEPS += ../build/bin/Debug/libsprt.a + LIBS += $(LDDEPS) + EXTERNAL_LIBS += + LINKOBJS = $(OBJECTS) + LINKCMD = $(CXX) -o $(TARGET) $(LINKOBJS) $(RESOURCES) $(ARCH) $(ALL_LDFLAGS) $(LIBS) + OBJECTS := \ + $(OBJDIR)/src/main.o \ + + define PREBUILDCMDS + endef + define PRELINKCMDS + endef + define POSTBUILDCMDS + endef +endif + +ifeq ($(config),release64) + OBJDIR = ../build/obj/Release/x64/Release/sprun + TARGETDIR = ../build/bin/Release + TARGET = $(TARGETDIR)/sprun + DEFINES += -D_SCL_SECURE_NO_WARNINGS + ALL_CPPFLAGS += $(CPPFLAGS) -MMD -MP -MP $(DEFINES) $(INCLUDES) + ALL_ASMFLAGS += $(ASMFLAGS) $(CFLAGS) $(ALL_CPPFLAGS) $(ARCH) -Werror -Wall -Wextra -g -O3 -m64 + ALL_CFLAGS += $(CFLAGS) $(ALL_CPPFLAGS) $(ARCH) -Werror -Wall -Wextra -g -O3 -m64 + ALL_CXXFLAGS += $(CXXFLAGS) $(CFLAGS) $(ALL_CPPFLAGS) $(ARCH) -Werror -Wall -Wextra -g -O3 -m64 -std=c++14 + ALL_OBJCFLAGS += $(CFLAGS) $(ALL_CPPFLAGS) $(ARCH) -Werror -Wall -Wextra -g -O3 -m64 + ALL_OBJCPPFLAGS += $(CXXFLAGS) $(CFLAGS) $(ALL_CPPFLAGS) $(ARCH) -Werror -Wall -Wextra -g -O3 -m64 -std=c++14 + ALL_RESFLAGS += $(RESFLAGS) $(DEFINES) $(INCLUDES) + ALL_LDFLAGS += $(LDFLAGS) -L"../build/bin/Release" -m64 + LDDEPS += ../build/bin/Release/libsprt.a + LIBS += $(LDDEPS) + EXTERNAL_LIBS += + LINKOBJS = $(OBJECTS) + LINKCMD = $(CXX) -o $(TARGET) $(LINKOBJS) $(RESOURCES) $(ARCH) $(ALL_LDFLAGS) $(LIBS) + OBJECTS := \ + $(OBJDIR)/src/main.o \ + + define PREBUILDCMDS + endef + define PRELINKCMDS + endef + define POSTBUILDCMDS + endef +endif + +OBJDIRS := \ + $(OBJDIR) \ + $(OBJDIR)/src \ + +RESOURCES := \ + +.PHONY: clean prebuild prelink + +all: $(OBJDIRS) $(TARGETDIR) prebuild prelink $(TARGET) + @: + +$(TARGET): $(GCH) $(OBJECTS) $(LDDEPS) $(EXTERNAL_LIBS) $(RESOURCES) | $(TARGETDIR) $(OBJDIRS) + @echo Linking sprun + $(SILENT) $(LINKCMD) + $(POSTBUILDCMDS) + +$(TARGETDIR): + @echo Creating $(TARGETDIR) + -$(call MKDIR,$(TARGETDIR)) + +$(OBJDIRS): + @echo Creating $(@) + -$(call MKDIR,$@) + +clean: + @echo Cleaning sprun +ifeq (posix,$(SHELLTYPE)) + $(SILENT) rm -f $(TARGET) + $(SILENT) rm -rf $(OBJDIR) +else + $(SILENT) if exist $(subst /,\\,$(TARGET)) del $(subst /,\\,$(TARGET)) + $(SILENT) if exist $(subst /,\\,$(OBJDIR)) rmdir /s /q $(subst /,\\,$(OBJDIR)) +endif + +prebuild: + $(PREBUILDCMDS) + +prelink: + $(PRELINKCMDS) + +ifneq (,$(PCH)) +$(GCH): $(PCH) $(MAKEFILE) | $(OBJDIR) + @echo $(notdir $<) + $(SILENT) $(CXX) $(ALL_CXXFLAGS) -x c++-header $(DEFINES) $(INCLUDES) -o "$@" -c "$<" + +$(GCH_OBJC): $(PCH) $(MAKEFILE) | $(OBJDIR) + @echo $(notdir $<) + $(SILENT) $(CXX) $(ALL_OBJCPPFLAGS) -x objective-c++-header $(DEFINES) $(INCLUDES) -o "$@" -c "$<" +endif + +$(OBJDIR)/src/main.o: ../src/main.cpp $(GCH) $(MAKEFILE) | $(OBJDIR)/src + @echo $(notdir $<) + $(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -c "$<" + +-include $(OBJECTS:%.o=%.d) +ifneq (,$(PCH)) + -include $(OBJDIR)/$(notdir $(PCH)).d + -include $(OBJDIR)/$(notdir $(PCH))_objc.d +endif diff --git a/solution/sprun.vcxproj b/solution/sprun.vcxproj new file mode 100644 index 0000000..08ee433 --- /dev/null +++ b/solution/sprun.vcxproj @@ -0,0 +1,126 @@ + + + + + Debug + x64 + + + Release + x64 + + + + {FD605F10-6975-87C1-32F7-2A219ECA83F2} + sprun + 8.1 + Win32Proj + + + + Application + true + v140 + x64 + + + Application + false + v140 + x64 + + + + + + + + + + + + + ..\build\bin\Debug\ + ..\build\obj\Debug\x64\Debug\sprun\ + sprun + .exe + true + + + ..\build\bin\Release\ + ..\build\obj\Release\x64\Release\sprun\ + sprun + .exe + false + + + + %(AdditionalOptions) + Disabled + _SCL_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + false + EnableFastChecks + MultiThreadedDebugDLL + true + true + + Level4 + true + EditAndContinue + $(IntDir)sprun.compile.pdb + + + _SCL_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + + + Console + true + $(OutDir)sprun.pdb + $(OutDir)sprun.exe + mainCRTStartup + MachineX64 + + + + + %(AdditionalOptions) + MaxSpeed + _SCL_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + false + true + MultiThreadedDLL + true + true + + Level4 + true + ProgramDatabase + $(IntDir)sprun.compile.pdb + + + _SCL_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + + + Console + true + $(OutDir)sprun.pdb + true + true + $(OutDir)sprun.exe + mainCRTStartup + MachineX64 + + + + + + + + + {AE0A9E7C-9A41-9F0D-432E-85102F441B0F} + + + + + + diff --git a/solution/sprun.vcxproj.filters b/solution/sprun.vcxproj.filters new file mode 100644 index 0000000..daeea8c --- /dev/null +++ b/solution/sprun.vcxproj.filters @@ -0,0 +1,13 @@ + + + + + {2DAB880B-99B4-887C-2230-9F7C8E38947C} + + + + + src + + + diff --git a/solution/sprun.vcxproj.user b/solution/sprun.vcxproj.user new file mode 100644 index 0000000..99820f1 --- /dev/null +++ b/solution/sprun.vcxproj.user @@ -0,0 +1,11 @@ + + + + WindowsLocalDebugger + + + + WindowsLocalDebugger + + + diff --git a/src/asm/assembler.cpp b/src/asm/assembler.cpp new file mode 100644 index 0000000..25ed377 --- /dev/null +++ b/src/asm/assembler.cpp @@ -0,0 +1,79 @@ +#include + +#include "assembler.hpp" +#include "bytecode.hpp" +#include "symbol.hpp" +#include "tokenizer.hpp" + +namespace SpasmImpl +{ +namespace ASM +{ +Assembler::Assembler(Lexer::Tokenizer& tokenizer, Bytecode_Stream& bytecode) + : _tokenizer(&tokenizer), _bytecode(&bytecode) +{ +} + +void Assembler::assemble() +{ + Lexer::Token token = _tokenizer->next_token(); + + while (token.type() != Lexer::Token::endinput) + { + switch (token.type()) + { + case Lexer::Token::ident: + assemble_identifier(token); + break; + case Lexer::Token::label: + token = _tokenizer->next_token(); + assert(token.type() == Lexer::Token::ident); + _symbols.define(token.value_str(), _bytecode->size()); + break; + case Lexer::Token::integer: + case Lexer::Token::xinteger: + _bytecode->push_integer(token.value_int()); + break; + default: + _bytecode->push_opcode((Bytecode_Stream::Opcode_t)token.type()); + } + + token = _tokenizer->next_token(); + } + + Symbol_Table::const_iterator i = _symbols.begin(); + while (i != _symbols.end()) + { + backpatch(i->second); + ++i; + } +} + +void Assembler::backpatch(const Symbol* symbol) +{ + Symbol::Positions_t::const_iterator i = symbol->positions_begin(); + while (i != symbol->positions_end()) + { + _bytecode->set_location(*i, symbol->definition()); + ++i; + } +} + +void Assembler::assemble_identifier(const Lexer::Token& token) +{ + Symbol* symbol = _symbols.insert(token.value_str(), _bytecode->size()); + _bytecode->push_location(symbol->definition()); +} + +bool compile(std::istream& istr, Bytecode_Memory& bytecode) +{ + Lexer::Tokenizer tokenizer(istr); + Assembler assembler(tokenizer, bytecode); + + assembler.assemble(); + + return true; +} + +} // namespace ASM +} // namespace SpasmImpl diff --git a/src/asm/assembler.hpp b/src/asm/assembler.hpp new file mode 100644 index 0000000..d29139b --- /dev/null +++ b/src/asm/assembler.hpp @@ -0,0 +1,36 @@ +#ifndef ASSEMBPLER_HPP +#define ASSEMBPLER_HPP + +#include + +#include "bytecode.hpp" +#include "symbol.hpp" +#include "tokenizer.hpp" + +namespace SpasmImpl +{ +namespace ASM +{ +class Assembler +{ + public: + Assembler(Lexer::Tokenizer&, Bytecode_Stream&); + + void assemble(); + + private: + void backpatch(const Symbol*); + void assemble_identifier(const Lexer::Token&); + + Lexer::Tokenizer* _tokenizer; + Bytecode_Stream* _bytecode; + + Symbol_Table _symbols; + +}; // class Assembler + +bool compile(std::istream&, Bytecode_Memory& bytecode); +} // namespace ASM +} // namespace SpasmImpl + +#endif // ASSEMBPLER_HPP diff --git a/src/asm/bytecode.cpp b/src/asm/bytecode.cpp new file mode 100644 index 0000000..27fed2b --- /dev/null +++ b/src/asm/bytecode.cpp @@ -0,0 +1,74 @@ +#include +#include +#include +#include + +#include "bytecode.hpp" + +namespace SpasmImpl +{ +namespace ASM +{ +Bytecode_Stream::~Bytecode_Stream() {} + +Bytecode_File::Bytecode_File(const std::string& filename) + : _bytecode(filename.c_str(), std::ios_base::out | std::ios_base::binary) +{ +} + +void Bytecode_File::push_byte(Bytecode_Stream::byte byte) +{ + _bytecode.put(byte); +} + +void Bytecode_File::push_opcode(Bytecode_Stream::Opcode_t opcode) +{ + push_byte(opcode); +} + +void Bytecode_File::push_integer(int number) +{ + for (size_t i = 0; i < sizeof(int); ++i) + push_byte((number >> (i << 3)) & 0xff); +} + +void Bytecode_Memory::push_byte(Bytecode_Stream::byte byte) +{ + _bytecode.push_back(byte); +} + +void Bytecode_Memory::push_opcode(Bytecode_Stream::Opcode_t opcode) +{ + push_byte(opcode); +} + +void Bytecode_Memory::push_integer(int number) +{ + for (size_t i = 0; i < sizeof(int); ++i) + push_byte((number >> (i << 3)) & 0xff); +} + +void Bytecode_Memory::set_location(size_t index, size_t location) +{ + for (size_t i = 0; i < sizeof(size_t); ++i) + _bytecode.at(index + i) = ((location >> (i << 3)) & 0xff); +} + +void Bytecode_Memory::push_location(size_t location) +{ + for (size_t i = 0; i < sizeof(size_t); ++i) + _bytecode.push_back((location >> (i << 3)) & 0xff); +} + +const Bytecode_Memory::Bytecode& Bytecode_Memory::bytecode() const +{ + return _bytecode; +} + +size_t Bytecode_Memory::size() const +{ + return _bytecode.size(); +} + +} // namespace ASM +} // namespace SpasmImpl diff --git a/src/asm/bytecode.hpp b/src/asm/bytecode.hpp new file mode 100644 index 0000000..c08da46 --- /dev/null +++ b/src/asm/bytecode.hpp @@ -0,0 +1,87 @@ +#ifndef BYTECODE_HPP +#define BYTECODE_HPP + +#include +#include +#include +#include + +namespace SpasmImpl +{ +namespace ASM +{ +class Bytecode_Stream +{ + public: + typedef unsigned char byte; + enum Opcode_t : byte + { + halt = 0, + push, + pop, + dup, + print, + read, + plus, + minus, + multiply, + divide, + modulus, + gotrue, + gofalse, + go, + call, + ret, + load, + store, + less, + lesseq + }; + + + virtual ~Bytecode_Stream(); + virtual void push_opcode(Opcode_t) = 0; + virtual void push_integer(int) = 0; + virtual void push_location(size_t) = 0; + virtual void set_location(size_t, size_t) = 0; + virtual size_t size() const = 0; +}; // class Bytecode_Stream + +class Bytecode_File : public Bytecode_Stream +{ + public: + Bytecode_File(const std::string&); + + virtual void push_opcode(Opcode_t); + virtual void push_integer(int); + + private: + Bytecode_File(const Bytecode_File&); + Bytecode_File& operator=(const Bytecode_File&); + void push_byte(Bytecode_Stream::byte); + + std::ofstream _bytecode; + +}; // class Bytecode_File + +class Bytecode_Memory : public Bytecode_Stream +{ + public: + virtual void push_opcode(Opcode_t); + virtual void push_integer(int); + virtual void push_location(size_t); + virtual void set_location(size_t, size_t); + virtual size_t size() const; + + typedef std::vector Bytecode; + const Bytecode& bytecode() const; + + private: + void push_byte(Bytecode_Stream::byte); + + std::vector _bytecode; +}; // class Bytecode_Memory +} // namespace ASM +} // namespace SpasmImpl + +#endif // BYTECODE_HPP diff --git a/src/asm/dfa.dot b/src/asm/dfa.dot new file mode 100644 index 0000000..ff38d77 --- /dev/null +++ b/src/asm/dfa.dot @@ -0,0 +1,180 @@ +/* Generated by re2c 0.16 on Thu Oct 11 01:51:09 2018 */ + +digraph re2c { + +1 -> 2 [label="[0x00]"] +1 -> 4 [label="[0x01-0x08][0x0B-0x1F][!-$][&-)][,][.][:-;][=-@][[-^][`][{-0xFF]"] +1 -> 6 [label="[0x09][ ]"] +1 -> 9 [label="[0x0A]"] +1 -> 11 [label="[%]"] +1 -> 13 [label="[*]"] +1 -> 15 [label="[+]"] +1 -> 17 [label="[-]"] +1 -> 19 [label="[/]"] +1 -> 21 [label="[0]"] +1 -> 23 [label="[1-9]"] +1 -> 25 [label="[<]"] +1 -> 27 [label="[A-Z][_][a-b][e-f][h-k][m-o][q][t-z]"] +1 -> 30 [label="[c]"] +1 -> 31 [label="[d]"] +1 -> 32 [label="[g]"] +1 -> 33 [label="[l]"] +1 -> 34 [label="[p]"] +1 -> 35 [label="[r]"] +1 -> 36 [label="[s]"] +2 -> 3 +3 [label="lexer.re:233"] +4 -> 5 +5 [label="lexer.re:239"] +6 -> 7 +7 -> 8 [label="[0x00-0x08][0x0A-0x1F][!-0xFF]"] +7 -> 6 [label="[0x09][ ]"] +8 [label="lexer.re:220"] +9 -> 10 +10 [label="lexer.re:226"] +11 -> 12 +12 [label="lexer.re:137"] +13 -> 14 +14 [label="lexer.re:123"] +15 -> 16 +16 [label="lexer.re:109"] +17 -> 18 [label="[0x00-/][1-0xFF]"] +17 -> 37 [label="[0]"] +18 [label="lexer.re:116"] +19 -> 20 +20 [label="lexer.re:130"] +21 -> 22 [label="[0x00-W][Y-w][y-0xFF]"] +21 -> 38 [label="[X][x]"] +22 [label="lexer.re:58"] +23 -> 24 +24 -> 22 [label="[0x00-/][:-0xFF]"] +24 -> 23 [label="[0-9]"] +25 -> 26 [label="[0x00-<][>-0xFF]"] +25 -> 40 [label="[=]"] +26 [label="lexer.re:198"] +27 -> 28 +28 -> 29 [label="[0x00-/][:-@][[-^][`][{-0xFF]"] +28 -> 27 [label="[0-9][A-Z][_][a-z]"] +29 [label="lexer.re:212"] +30 -> 28 [label="[0x00-`][b-0xFF]"] +30 -> 42 [label="[a]"] +31 -> 28 [label="[0x00-t][v-0xFF]"] +31 -> 43 [label="[u]"] +32 -> 28 [label="[0x00-n][p-0xFF]"] +32 -> 44 [label="[o]"] +33 -> 28 [label="[0x00-`][b-n][p-0xFF]"] +33 -> 46 [label="[a]"] +33 -> 47 [label="[o]"] +34 -> 28 [label="[0x00-n][p-q][s-t][v-0xFF]"] +34 -> 48 [label="[o]"] +34 -> 49 [label="[r]"] +34 -> 50 [label="[u]"] +35 -> 28 [label="[0x00-d][f-0xFF]"] +35 -> 51 [label="[e]"] +36 -> 28 [label="[0x00-s][u-0xFF]"] +36 -> 52 [label="[t]"] +37 -> 22 +38 -> 39 [label="[0x00-/][:-@][G-`][g-0xFF]"] +38 -> 53 [label="[0-9][A-F][a-f]"] +39 -> 22 +40 -> 41 +41 [label="lexer.re:192"] +42 -> 28 [label="[0x00-k][m-0xFF]"] +42 -> 56 [label="[l]"] +43 -> 28 [label="[0x00-o][q-0xFF]"] +43 -> 57 [label="[p]"] +44 -> 45 [label="[0x00-/][:-@][[-^][`][{-0xFF]"] +44 -> 27 [label="[0-9][A-Z][_][a-e][g-s][u-z]"] +44 -> 59 [label="[f]"] +44 -> 60 [label="[t]"] +45 [label="lexer.re:158"] +46 -> 28 [label="[0x00-a][c-0xFF]"] +46 -> 61 [label="[b]"] +47 -> 28 [label="[0x00-`][b-0xFF]"] +47 -> 62 [label="[a]"] +48 -> 28 [label="[0x00-o][q-0xFF]"] +48 -> 63 [label="[p]"] +49 -> 28 [label="[0x00-h][j-0xFF]"] +49 -> 65 [label="[i]"] +50 -> 28 [label="[0x00-r][t-0xFF]"] +50 -> 66 [label="[s]"] +51 -> 28 [label="[0x00-`][b-s][u-0xFF]"] +51 -> 67 [label="[a]"] +51 -> 68 [label="[t]"] +52 -> 28 [label="[0x00-n][p-0xFF]"] +52 -> 70 [label="[o]"] +53 -> 54 +54 -> 55 [label="[0x00-/][:-@][G-`][g-0xFF]"] +54 -> 53 [label="[0-9][A-F][a-f]"] +55 [label="lexer.re:66"] +56 -> 28 [label="[0x00-k][m-0xFF]"] +56 -> 71 [label="[l]"] +57 -> 58 [label="[0x00-/][:-@][[-^][`][{-0xFF]"] +57 -> 27 [label="[0-9][A-Z][_][a-z]"] +58 [label="lexer.re:88"] +59 -> 28 [label="[0x00-`][b-0xFF]"] +59 -> 73 [label="[a]"] +60 -> 28 [label="[0x00-q][s-0xFF]"] +60 -> 74 [label="[r]"] +61 -> 28 [label="[0x00-d][f-0xFF]"] +61 -> 75 [label="[e]"] +62 -> 28 [label="[0x00-c][e-0xFF]"] +62 -> 76 [label="[d]"] +63 -> 64 [label="[0x00-/][:-@][[-^][`][{-0xFF]"] +63 -> 27 [label="[0-9][A-Z][_][a-z]"] +64 [label="lexer.re:81"] +65 -> 28 [label="[0x00-m][o-0xFF]"] +65 -> 78 [label="[n]"] +66 -> 28 [label="[0x00-g][i-0xFF]"] +66 -> 79 [label="[h]"] +67 -> 28 [label="[0x00-c][e-0xFF]"] +67 -> 81 [label="[d]"] +68 -> 69 [label="[0x00-/][:-@][[-^][`][{-0xFF]"] +68 -> 27 [label="[0-9][A-Z][_][a-z]"] +69 [label="lexer.re:172"] +70 -> 28 [label="[0x00-q][s-0xFF]"] +70 -> 83 [label="[r]"] +71 -> 72 [label="[0x00-/][:-@][[-^][`][{-0xFF]"] +71 -> 27 [label="[0-9][A-Z][_][a-z]"] +72 [label="lexer.re:165"] +73 -> 28 [label="[0x00-k][m-0xFF]"] +73 -> 84 [label="[l]"] +74 -> 28 [label="[0x00-t][v-0xFF]"] +74 -> 85 [label="[u]"] +75 -> 28 [label="[0x00-k][m-0xFF]"] +75 -> 86 [label="[l]"] +76 -> 77 [label="[0x00-/][:-@][[-^][`][{-0xFF]"] +76 -> 27 [label="[0-9][A-Z][_][a-z]"] +77 [label="lexer.re:179"] +78 -> 28 [label="[0x00-s][u-0xFF]"] +78 -> 88 [label="[t]"] +79 -> 80 [label="[0x00-/][:-@][[-^][`][{-0xFF]"] +79 -> 27 [label="[0-9][A-Z][_][a-z]"] +80 [label="lexer.re:74"] +81 -> 82 [label="[0x00-/][:-@][[-^][`][{-0xFF]"] +81 -> 27 [label="[0-9][A-Z][_][a-z]"] +82 [label="lexer.re:95"] +83 -> 28 [label="[0x00-d][f-0xFF]"] +83 -> 90 [label="[e]"] +84 -> 28 [label="[0x00-r][t-0xFF]"] +84 -> 92 [label="[s]"] +85 -> 28 [label="[0x00-d][f-0xFF]"] +85 -> 93 [label="[e]"] +86 -> 87 [label="[0x00-/][:-@][[-^][`][{-0xFF]"] +86 -> 27 [label="[0-9][A-Z][_][a-z]"] +87 [label="lexer.re:205"] +88 -> 89 [label="[0x00-/][:-@][[-^][`][{-0xFF]"] +88 -> 27 [label="[0-9][A-Z][_][a-z]"] +89 [label="lexer.re:102"] +90 -> 91 [label="[0x00-/][:-@][[-^][`][{-0xFF]"] +90 -> 27 [label="[0-9][A-Z][_][a-z]"] +91 [label="lexer.re:186"] +92 -> 28 [label="[0x00-d][f-0xFF]"] +92 -> 95 [label="[e]"] +93 -> 94 [label="[0x00-/][:-@][[-^][`][{-0xFF]"] +93 -> 27 [label="[0-9][A-Z][_][a-z]"] +94 [label="lexer.re:144"] +95 -> 96 [label="[0x00-/][:-@][[-^][`][{-0xFF]"] +95 -> 27 [label="[0-9][A-Z][_][a-z]"] +96 [label="lexer.re:151"] +} diff --git a/src/asm/dfa.svg b/src/asm/dfa.svg new file mode 100644 index 0000000..0bd3660 --- /dev/null +++ b/src/asm/dfa.svg @@ -0,0 +1,1367 @@ + + + + + + +re2c + + +1 + +1 + + +2 + +2 + + +1->2 + + +[0x00] + + +4 + +4 + + +1->4 + + +[0x01-0x08][0x0B-0x1F][!-$][&-)][,][.][:-;][=-@][[-^][`][{-0xFF] + + +6 + +6 + + +1->6 + + +[0x09][ ] + + +9 + +9 + + +1->9 + + +[0x0A] + + +11 + +11 + + +1->11 + + +[%] + + +13 + +13 + + +1->13 + + +[*] + + +15 + +15 + + +1->15 + + +[+] + + +17 + +17 + + +1->17 + + +[-] + + +19 + +19 + + +1->19 + + +[/] + + +21 + +21 + + +1->21 + + +[0] + + +23 + +23 + + +1->23 + + +[1-9] + + +25 + +25 + + +1->25 + + +[<] + + +27 + +27 + + +1->27 + + +[A-Z][_][a-b][e-f][h-k][m-o][q][t-z] + + +30 + +30 + + +1->30 + + +[c] + + +31 + +31 + + +1->31 + + +[d] + + +32 + +32 + + +1->32 + + +[g] + + +33 + +33 + + +1->33 + + +[l] + + +34 + +34 + + +1->34 + + +[p] + + +35 + +35 + + +1->35 + + +[r] + + +36 + +36 + + +1->36 + + +[s] + + +3 + +lexer.re:233 + + +2->3 + + + + +5 + +lexer.re:239 + + +4->5 + + + + +7 + +7 + + +6->7 + + + + +10 + +lexer.re:226 + + +9->10 + + + + +12 + +lexer.re:137 + + +11->12 + + + + +14 + +lexer.re:123 + + +13->14 + + + + +16 + +lexer.re:109 + + +15->16 + + + + +18 + +lexer.re:116 + + +17->18 + + +[0x00-/][1-0xFF] + + +37 + +37 + + +17->37 + + +[0] + + +20 + +lexer.re:130 + + +19->20 + + + + +22 + +lexer.re:58 + + +21->22 + + +[0x00-W][Y-w][y-0xFF] + + +38 + +38 + + +21->38 + + +[X][x] + + +24 + +24 + + +23->24 + + + + +26 + +lexer.re:198 + + +25->26 + + +[0x00-<][>-0xFF] + + +40 + +40 + + +25->40 + + +[=] + + +28 + +28 + + +27->28 + + + + +30->28 + + +[0x00-`][b-0xFF] + + +42 + +42 + + +30->42 + + +[a] + + +31->28 + + +[0x00-t][v-0xFF] + + +43 + +43 + + +31->43 + + +[u] + + +32->28 + + +[0x00-n][p-0xFF] + + +44 + +44 + + +32->44 + + +[o] + + +33->28 + + +[0x00-`][b-n][p-0xFF] + + +46 + +46 + + +33->46 + + +[a] + + +47 + +47 + + +33->47 + + +[o] + + +34->28 + + +[0x00-n][p-q][s-t][v-0xFF] + + +48 + +48 + + +34->48 + + +[o] + + +49 + +49 + + +34->49 + + +[r] + + +50 + +50 + + +34->50 + + +[u] + + +35->28 + + +[0x00-d][f-0xFF] + + +51 + +51 + + +35->51 + + +[e] + + +36->28 + + +[0x00-s][u-0xFF] + + +52 + +52 + + +36->52 + + +[t] + + +7->6 + + +[0x09][ ] + + +8 + +lexer.re:220 + + +7->8 + + +[0x00-0x08][0x0A-0x1F][!-0xFF] + + +37->22 + + + + +39 + +39 + + +38->39 + + +[0x00-/][:-@][G-`][g-0xFF] + + +53 + +53 + + +38->53 + + +[0-9][A-F][a-f] + + +24->23 + + +[0-9] + + +24->22 + + +[0x00-/][:-0xFF] + + +41 + +lexer.re:192 + + +40->41 + + + + +28->27 + + +[0-9][A-Z][_][a-z] + + +29 + +lexer.re:212 + + +28->29 + + +[0x00-/][:-@][[-^][`][{-0xFF] + + +42->28 + + +[0x00-k][m-0xFF] + + +56 + +56 + + +42->56 + + +[l] + + +43->28 + + +[0x00-o][q-0xFF] + + +57 + +57 + + +43->57 + + +[p] + + +44->27 + + +[0-9][A-Z][_][a-e][g-s][u-z] + + +45 + +lexer.re:158 + + +44->45 + + +[0x00-/][:-@][[-^][`][{-0xFF] + + +59 + +59 + + +44->59 + + +[f] + + +60 + +60 + + +44->60 + + +[t] + + +46->28 + + +[0x00-a][c-0xFF] + + +61 + +61 + + +46->61 + + +[b] + + +47->28 + + +[0x00-`][b-0xFF] + + +62 + +62 + + +47->62 + + +[a] + + +48->28 + + +[0x00-o][q-0xFF] + + +63 + +63 + + +48->63 + + +[p] + + +49->28 + + +[0x00-h][j-0xFF] + + +65 + +65 + + +49->65 + + +[i] + + +50->28 + + +[0x00-r][t-0xFF] + + +66 + +66 + + +50->66 + + +[s] + + +51->28 + + +[0x00-`][b-s][u-0xFF] + + +67 + +67 + + +51->67 + + +[a] + + +68 + +68 + + +51->68 + + +[t] + + +52->28 + + +[0x00-n][p-0xFF] + + +70 + +70 + + +52->70 + + +[o] + + +39->22 + + + + +54 + +54 + + +53->54 + + + + +56->28 + + +[0x00-k][m-0xFF] + + +71 + +71 + + +56->71 + + +[l] + + +57->27 + + +[0-9][A-Z][_][a-z] + + +58 + +lexer.re:88 + + +57->58 + + +[0x00-/][:-@][[-^][`][{-0xFF] + + +59->28 + + +[0x00-`][b-0xFF] + + +73 + +73 + + +59->73 + + +[a] + + +60->28 + + +[0x00-q][s-0xFF] + + +74 + +74 + + +60->74 + + +[r] + + +61->28 + + +[0x00-d][f-0xFF] + + +75 + +75 + + +61->75 + + +[e] + + +62->28 + + +[0x00-c][e-0xFF] + + +76 + +76 + + +62->76 + + +[d] + + +63->27 + + +[0-9][A-Z][_][a-z] + + +64 + +lexer.re:81 + + +63->64 + + +[0x00-/][:-@][[-^][`][{-0xFF] + + +65->28 + + +[0x00-m][o-0xFF] + + +78 + +78 + + +65->78 + + +[n] + + +66->28 + + +[0x00-g][i-0xFF] + + +79 + +79 + + +66->79 + + +[h] + + +67->28 + + +[0x00-c][e-0xFF] + + +81 + +81 + + +67->81 + + +[d] + + +68->27 + + +[0-9][A-Z][_][a-z] + + +69 + +lexer.re:172 + + +68->69 + + +[0x00-/][:-@][[-^][`][{-0xFF] + + +70->28 + + +[0x00-q][s-0xFF] + + +83 + +83 + + +70->83 + + +[r] + + +54->53 + + +[0-9][A-F][a-f] + + +55 + +lexer.re:66 + + +54->55 + + +[0x00-/][:-@][G-`][g-0xFF] + + +71->27 + + +[0-9][A-Z][_][a-z] + + +72 + +lexer.re:165 + + +71->72 + + +[0x00-/][:-@][[-^][`][{-0xFF] + + +73->28 + + +[0x00-k][m-0xFF] + + +84 + +84 + + +73->84 + + +[l] + + +74->28 + + +[0x00-t][v-0xFF] + + +85 + +85 + + +74->85 + + +[u] + + +75->28 + + +[0x00-k][m-0xFF] + + +86 + +86 + + +75->86 + + +[l] + + +76->27 + + +[0-9][A-Z][_][a-z] + + +77 + +lexer.re:179 + + +76->77 + + +[0x00-/][:-@][[-^][`][{-0xFF] + + +78->28 + + +[0x00-s][u-0xFF] + + +88 + +88 + + +78->88 + + +[t] + + +79->27 + + +[0-9][A-Z][_][a-z] + + +80 + +lexer.re:74 + + +79->80 + + +[0x00-/][:-@][[-^][`][{-0xFF] + + +81->27 + + +[0-9][A-Z][_][a-z] + + +82 + +lexer.re:95 + + +81->82 + + +[0x00-/][:-@][[-^][`][{-0xFF] + + +83->28 + + +[0x00-d][f-0xFF] + + +90 + +90 + + +83->90 + + +[e] + + +84->28 + + +[0x00-r][t-0xFF] + + +92 + +92 + + +84->92 + + +[s] + + +85->28 + + +[0x00-d][f-0xFF] + + +93 + +93 + + +85->93 + + +[e] + + +86->27 + + +[0-9][A-Z][_][a-z] + + +87 + +lexer.re:205 + + +86->87 + + +[0x00-/][:-@][[-^][`][{-0xFF] + + +88->27 + + +[0-9][A-Z][_][a-z] + + +89 + +lexer.re:102 + + +88->89 + + +[0x00-/][:-@][[-^][`][{-0xFF] + + +90->27 + + +[0-9][A-Z][_][a-z] + + +91 + +lexer.re:186 + + +90->91 + + +[0x00-/][:-@][[-^][`][{-0xFF] + + +92->28 + + +[0x00-d][f-0xFF] + + +95 + +95 + + +92->95 + + +[e] + + +93->27 + + +[0-9][A-Z][_][a-z] + + +94 + +lexer.re:144 + + +93->94 + + +[0x00-/][:-@][[-^][`][{-0xFF] + + +95->27 + + +[0-9][A-Z][_][a-z] + + +96 + +lexer.re:151 + + +95->96 + + +[0x00-/][:-@][[-^][`][{-0xFF] + + + diff --git a/src/asm/lexdump.cpp b/src/asm/lexdump.cpp new file mode 100644 index 0000000..440ff1e --- /dev/null +++ b/src/asm/lexdump.cpp @@ -0,0 +1,83 @@ +#include +#include + +#include + +#include "lexer.hpp" +#include "token.hpp" + +using namespace SpasmImpl::ASM::Lexer; + +#define TOKENS \ + TOK(push) \ + TOK(pop) \ + TOK(dup) \ + TOK(print) \ + TOK(read) \ + TOK(plus) \ + TOK(minus) \ + TOK(multiply) \ + TOK(divide) \ + TOK(modulus) \ + TOK(gotrue) \ + TOK(gofalse) \ + TOK(go) \ + TOK(call) \ + TOK(ret) \ + TOK(load) \ + TOK(store) \ + TOK(label) \ + TOK(ident) \ + TOK(integer) \ + TOK(xinteger) \ + TOK(endinput) + +class TokenDumper : public TokenStream +{ + public: + TokenDumper() : end_reached(false) {} + void push_token(const Token& token) + { + Token::Token_type ttype = token.type(); + std::cout.width(8); + std::cout << token.lineno(); + std::cout << ": " << token_name[ttype]; + if (ttype == Token::integer || ttype == Token::xinteger) + std::cout << '|' << token.value_int() << '|'; + else if (ttype == Token::ident) + std::cout << '|' << token.value_str() << '|'; + std::cout << std::endl; + if (token.type() == Token::endinput) + end_reached = true; + } + + bool input_end() const { return end_reached; } + + private: + bool end_reached; + + static const char* token_name[24]; +}; + +const char* TokenDumper::token_name[24] = {"halt", +#define TOK(x) #x, + TOKENS +#undef TOK + "notused!!!"}; + +int main() +{ + Lexer lex(std::cin); + TokenDumper td; + Token token; + + lex.buffer_init(); + + while (!td.input_end()) + { + lex.read(1); + lex.tokenize(td); + } + + return 0; +} diff --git a/src/asm/lexdump3.cpp b/src/asm/lexdump3.cpp new file mode 100644 index 0000000..4e4ce9e --- /dev/null +++ b/src/asm/lexdump3.cpp @@ -0,0 +1,62 @@ +#include +#include + +#include + +#include "token.hpp" +#include "tokenizer.hpp" + +using namespace SpasmImpl::ASM::Lexer; + +#define TOKENS \ + TOK(push) \ + TOK(pop) \ + TOK(dup) \ + TOK(print) \ + TOK(read) \ + TOK(plus) \ + TOK(minus) \ + TOK(multiply) \ + TOK(divide) \ + TOK(modulus) \ + TOK(gotrue) \ + TOK(gofalse) \ + TOK(go) \ + TOK(call) \ + TOK(ret) \ + TOK(load) \ + TOK(store) \ + TOK(label) \ + TOK(ident) \ + TOK(integer) \ + TOK(xinteger) \ + TOK(endinput) + +const char* token_name[24] = {"halt", +#define TOK(x) #x, + TOKENS +#undef TOK + "notused!!!"}; + +int main() +{ + Tokenizer td(std::cin); + Token token; + + token = td.next_token(); + while (token.type() != Token::endinput) + { + token = td.next_token(); + Token::Token_type ttype = token.type(); + std::cout.width(8); + std::cout << token.lineno(); + std::cout << ": " << token_name[ttype]; + if (ttype == Token::integer || ttype == Token::xinteger) + std::cout << '|' << token.value_int() << '|'; + else if (ttype == Token::ident) + std::cout << '|' << token.value_str() << '|'; + std::cout << std::endl; + } + + return 0; +} diff --git a/src/asm/lexer.cpp b/src/asm/lexer.cpp new file mode 100644 index 0000000..ef650e4 --- /dev/null +++ b/src/asm/lexer.cpp @@ -0,0 +1,1123 @@ +/* Generated by re2c 0.13.5 on Wed Jun 25 12:01:36 2008 */ +#line 1 "lexer.re" +#include + +#include "lexer.hpp" + +#include "token.hpp" + +namespace SpasmImpl +{ +namespace ASM +{ +//! Namespace for all lexical analisys classes +namespace Lexer +{ +Lexer::Lexer(std::istream& _file, size_t _buffer_size) + : file(&_file), buffer_size(_buffer_size), state(unsigned(-1)), lineno(0) +{ + buffer = new char[buffer_size]; + cursor = limit = marker = token_start = NULL; +} + +Lexer::~Lexer() +{ + delete[] buffer; +} + +bool Lexer::tokenize(TokenStream& ts) +{ +#line 43 "lexer.re" + + switch (state) + { + default: + goto yy0; + case 0: + goto yyFillLabel0; + case 1: + goto yyFillLabel1; + case 2: + goto yyFillLabel2; + case 3: + goto yyFillLabel3; + case 4: + goto yyFillLabel4; + } + + while (1) + { +#line 48 "lexer.cpp" + + yy0: + state = (0); + if ((limit - cursor) < 8) + return true; + yyFillLabel0: + yych = *cursor; + if (yych <= '<') + { + if (yych <= ')') + { + if (yych <= '\n') + { + if (yych <= 0x00) + goto yy30; + if (yych <= 0x08) + goto yy32; + if (yych <= '\t') + goto yy26; + goto yy28; + } + else + { + if (yych <= ' ') + { + if (yych <= 0x1F) + goto yy32; + goto yy26; + } + else + { + if (yych == '%') + goto yy17; + goto yy32; + } + } + } + else + { + if (yych <= '.') + { + if (yych <= '+') + { + if (yych <= '*') + goto yy13; + goto yy11; + } + else + { + if (yych != '-') + goto yy32; + } + } + else + { + if (yych <= '0') + { + if (yych <= '/') + goto yy15; + goto yy4; + } + else + { + if (yych <= '9') + goto yy6; + if (yych <= ';') + goto yy32; + goto yy23; + } + } + } + } + else + { + if (yych <= 'f') + { + if (yych <= '_') + { + if (yych <= '@') + goto yy32; + if (yych <= 'Z') + goto yy25; + if (yych <= '^') + goto yy32; + goto yy25; + } + else + { + if (yych <= 'b') + { + if (yych <= '`') + goto yy32; + goto yy25; + } + else + { + if (yych <= 'c') + goto yy20; + if (yych <= 'd') + goto yy9; + goto yy25; + } + } + } + else + { + if (yych <= 'p') + { + if (yych <= 'k') + { + if (yych <= 'g') + goto yy19; + goto yy25; + } + else + { + if (yych <= 'l') + goto yy21; + if (yych <= 'o') + goto yy25; + goto yy7; + } + } + else + { + if (yych <= 'r') + { + if (yych <= 'q') + goto yy25; + goto yy10; + } + else + { + if (yych <= 's') + goto yy22; + if (yych <= 'z') + goto yy25; + goto yy32; + } + } + } + } + ++cursor; + if ((yych = *cursor) == '0') + goto yy99; +#line 116 "lexer.re" + { + ts.push_token(Token(Token::minus, lineno)); + token_start = cursor; + + continue; + } +#line 138 "lexer.cpp" + yy4: + yych = *(marker = ++cursor); + if (yych == 'X') + goto yy94; + if (yych == 'x') + goto yy94; + yy5: +#line 58 "lexer.re" + { + ts.push_token(Token(Token::integer, lineno, token_start, cursor)); + token_start = cursor; + + continue; + } +#line 152 "lexer.cpp" + yy6: + yych = *++cursor; + goto yy93; + yy7: + ++cursor; + if ((yych = *cursor) <= 'q') + { + if (yych == 'o') + goto yy80; + goto yy37; + } + else + { + if (yych <= 'r') + goto yy81; + if (yych == 'u') + goto yy82; + goto yy37; + } + yy8: +#line 212 "lexer.re" + { + ts.push_token(Token(Token::ident, lineno, token_start, cursor)); + token_start = cursor; + + continue; + } +#line 175 "lexer.cpp" + yy9: + yych = *++cursor; + if (yych == 'u') + goto yy77; + goto yy37; + yy10: + yych = *++cursor; + if (yych == 'e') + goto yy71; + goto yy37; + yy11: + ++cursor; +#line 109 "lexer.re" + { + ts.push_token(Token(Token::plus, lineno)); + token_start = cursor; + + continue; + } +#line 193 "lexer.cpp" + yy13: + ++cursor; +#line 123 "lexer.re" + { + ts.push_token(Token(Token::multiply, lineno)); + token_start = cursor; + + continue; + } +#line 203 "lexer.cpp" + yy15: + ++cursor; +#line 130 "lexer.re" + { + ts.push_token(Token(Token::divide, lineno)); + token_start = cursor; + + continue; + } +#line 213 "lexer.cpp" + yy17: + ++cursor; +#line 137 "lexer.re" + { + ts.push_token(Token(Token::modulus, lineno)); + token_start = cursor; + + continue; + } +#line 223 "lexer.cpp" + yy19: + yych = *++cursor; + if (yych == 'o') + goto yy58; + goto yy37; + yy20: + yych = *++cursor; + if (yych == 'a') + goto yy54; + goto yy37; + yy21: + yych = *++cursor; + if (yych == 'a') + goto yy45; + if (yych == 'o') + goto yy46; + goto yy37; + yy22: + yych = *++cursor; + if (yych == 't') + goto yy40; + goto yy37; + yy23: + ++cursor; + if ((yych = *cursor) == '=') + goto yy38; +#line 198 "lexer.re" + { + ts.push_token(Token(Token::less, lineno)); + token_start = cursor; + + continue; + } +#line 251 "lexer.cpp" + yy25: + yych = *++cursor; + goto yy37; + yy26: + ++cursor; + yych = *cursor; + goto yy35; + yy27: +#line 220 "lexer.re" + { + token_start = cursor; + + continue; + } +#line 266 "lexer.cpp" + yy28: + ++cursor; +#line 226 "lexer.re" + { + ++lineno; + token_start = cursor; + + continue; + } +#line 276 "lexer.cpp" + yy30: + ++cursor; +#line 233 "lexer.re" + { + ts.push_token(Token(Token::endinput, lineno)); + + break; + } +#line 285 "lexer.cpp" + yy32: + ++cursor; +#line 239 "lexer.re" + { + return false; + } +#line 292 "lexer.cpp" + yy34: + ++cursor; + state = (1); + if (limit <= cursor) + return true; + yyFillLabel1: + yych = *cursor; + yy35: + if (yych == '\t') + goto yy34; + if (yych == ' ') + goto yy34; + goto yy27; + yy36: + ++cursor; + state = (2); + if (limit <= cursor) + return true; + yyFillLabel2: + yych = *cursor; + yy37: + if (yych <= 'Z') + { + if (yych <= '/') + goto yy8; + if (yych <= '9') + goto yy36; + if (yych <= '@') + goto yy8; + goto yy36; + } + else + { + if (yych <= '_') + { + if (yych <= '^') + goto yy8; + goto yy36; + } + else + { + if (yych <= '`') + goto yy8; + if (yych <= 'z') + goto yy36; + goto yy8; + } + } + yy38: + ++cursor; +#line 192 "lexer.re" + { + ts.push_token(Token(Token::lesseq, lineno)); + token_start = cursor; + + continue; + } +#line 334 "lexer.cpp" + yy40: + yych = *++cursor; + if (yych != 'o') + goto yy37; + yych = *++cursor; + if (yych != 'r') + goto yy37; + yych = *++cursor; + if (yych != 'e') + goto yy37; + ++cursor; + if ((yych = *cursor) <= 'Z') + { + if (yych <= '/') + goto yy44; + if (yych <= '9') + goto yy36; + if (yych >= 'A') + goto yy36; + } + else + { + if (yych <= '_') + { + if (yych >= '_') + goto yy36; + } + else + { + if (yych <= '`') + goto yy44; + if (yych <= 'z') + goto yy36; + } + } + yy44: +#line 186 "lexer.re" + { + ts.push_token(Token(Token::store, lineno)); + token_start = cursor; + + continue; + } +#line 363 "lexer.cpp" + yy45: + yych = *++cursor; + if (yych == 'b') + goto yy50; + goto yy37; + yy46: + yych = *++cursor; + if (yych != 'a') + goto yy37; + yych = *++cursor; + if (yych != 'd') + goto yy37; + ++cursor; + if ((yych = *cursor) <= 'Z') + { + if (yych <= '/') + goto yy49; + if (yych <= '9') + goto yy36; + if (yych >= 'A') + goto yy36; + } + else + { + if (yych <= '_') + { + if (yych >= '_') + goto yy36; + } + else + { + if (yych <= '`') + goto yy49; + if (yych <= 'z') + goto yy36; + } + } + yy49: +#line 179 "lexer.re" + { + ts.push_token(Token(Token::load, lineno)); + token_start = cursor; + + continue; + } +#line 394 "lexer.cpp" + yy50: + yych = *++cursor; + if (yych != 'e') + goto yy37; + yych = *++cursor; + if (yych != 'l') + goto yy37; + ++cursor; + if ((yych = *cursor) <= 'Z') + { + if (yych <= '/') + goto yy53; + if (yych <= '9') + goto yy36; + if (yych >= 'A') + goto yy36; + } + else + { + if (yych <= '_') + { + if (yych >= '_') + goto yy36; + } + else + { + if (yych <= '`') + goto yy53; + if (yych <= 'z') + goto yy36; + } + } + yy53: +#line 205 "lexer.re" + { + ts.push_token(Token(Token::label, lineno)); + token_start = cursor; + + continue; + } +#line 421 "lexer.cpp" + yy54: + yych = *++cursor; + if (yych != 'l') + goto yy37; + yych = *++cursor; + if (yych != 'l') + goto yy37; + ++cursor; + if ((yych = *cursor) <= 'Z') + { + if (yych <= '/') + goto yy57; + if (yych <= '9') + goto yy36; + if (yych >= 'A') + goto yy36; + } + else + { + if (yych <= '_') + { + if (yych >= '_') + goto yy36; + } + else + { + if (yych <= '`') + goto yy57; + if (yych <= 'z') + goto yy36; + } + } + yy57: +#line 165 "lexer.re" + { + ts.push_token(Token(Token::call, lineno)); + token_start = cursor; + + continue; + } +#line 448 "lexer.cpp" + yy58: + ++cursor; + if ((yych = *cursor) <= '_') + { + if (yych <= '@') + { + if (yych <= '/') + goto yy59; + if (yych <= '9') + goto yy36; + } + else + { + if (yych <= 'Z') + goto yy36; + if (yych >= '_') + goto yy36; + } + } + else + { + if (yych <= 'f') + { + if (yych <= '`') + goto yy59; + if (yych <= 'e') + goto yy36; + goto yy61; + } + else + { + if (yych == 't') + goto yy60; + if (yych <= 'z') + goto yy36; + } + } + yy59: +#line 158 "lexer.re" + { + ts.push_token(Token(Token::go, lineno)); + token_start = cursor; + + continue; + } +#line 477 "lexer.cpp" + yy60: + yych = *++cursor; + if (yych == 'r') + goto yy67; + goto yy37; + yy61: + yych = *++cursor; + if (yych != 'a') + goto yy37; + yych = *++cursor; + if (yych != 'l') + goto yy37; + yych = *++cursor; + if (yych != 's') + goto yy37; + yych = *++cursor; + if (yych != 'e') + goto yy37; + ++cursor; + if ((yych = *cursor) <= 'Z') + { + if (yych <= '/') + goto yy66; + if (yych <= '9') + goto yy36; + if (yych >= 'A') + goto yy36; + } + else + { + if (yych <= '_') + { + if (yych >= '_') + goto yy36; + } + else + { + if (yych <= '`') + goto yy66; + if (yych <= 'z') + goto yy36; + } + } + yy66: +#line 151 "lexer.re" + { + ts.push_token(Token(Token::gofalse, lineno)); + token_start = cursor; + + continue; + } +#line 512 "lexer.cpp" + yy67: + yych = *++cursor; + if (yych != 'u') + goto yy37; + yych = *++cursor; + if (yych != 'e') + goto yy37; + ++cursor; + if ((yych = *cursor) <= 'Z') + { + if (yych <= '/') + goto yy70; + if (yych <= '9') + goto yy36; + if (yych >= 'A') + goto yy36; + } + else + { + if (yych <= '_') + { + if (yych >= '_') + goto yy36; + } + else + { + if (yych <= '`') + goto yy70; + if (yych <= 'z') + goto yy36; + } + } + yy70: +#line 144 "lexer.re" + { + ts.push_token(Token(Token::gotrue, lineno)); + token_start = cursor; + + continue; + } +#line 539 "lexer.cpp" + yy71: + yych = *++cursor; + if (yych == 'a') + goto yy72; + if (yych == 't') + goto yy73; + goto yy37; + yy72: + yych = *++cursor; + if (yych == 'd') + goto yy75; + goto yy37; + yy73: + ++cursor; + if ((yych = *cursor) <= 'Z') + { + if (yych <= '/') + goto yy74; + if (yych <= '9') + goto yy36; + if (yych >= 'A') + goto yy36; + } + else + { + if (yych <= '_') + { + if (yych >= '_') + goto yy36; + } + else + { + if (yych <= '`') + goto yy74; + if (yych <= 'z') + goto yy36; + } + } + yy74: +#line 172 "lexer.re" + { + ts.push_token(Token(Token::ret, lineno)); + token_start = cursor; + + continue; + } +#line 571 "lexer.cpp" + yy75: + ++cursor; + if ((yych = *cursor) <= 'Z') + { + if (yych <= '/') + goto yy76; + if (yych <= '9') + goto yy36; + if (yych >= 'A') + goto yy36; + } + else + { + if (yych <= '_') + { + if (yych >= '_') + goto yy36; + } + else + { + if (yych <= '`') + goto yy76; + if (yych <= 'z') + goto yy36; + } + } + yy76: +#line 95 "lexer.re" + { + ts.push_token(Token(Token::read, lineno)); + token_start = cursor; + + continue; + } +#line 594 "lexer.cpp" + yy77: + yych = *++cursor; + if (yych != 'p') + goto yy37; + ++cursor; + if ((yych = *cursor) <= 'Z') + { + if (yych <= '/') + goto yy79; + if (yych <= '9') + goto yy36; + if (yych >= 'A') + goto yy36; + } + else + { + if (yych <= '_') + { + if (yych >= '_') + goto yy36; + } + else + { + if (yych <= '`') + goto yy79; + if (yych <= 'z') + goto yy36; + } + } + yy79: +#line 88 "lexer.re" + { + ts.push_token(Token(Token::dup, lineno)); + token_start = cursor; + + continue; + } +#line 619 "lexer.cpp" + yy80: + yych = *++cursor; + if (yych == 'p') + goto yy90; + goto yy37; + yy81: + yych = *++cursor; + if (yych == 'i') + goto yy86; + goto yy37; + yy82: + yych = *++cursor; + if (yych != 's') + goto yy37; + yych = *++cursor; + if (yych != 'h') + goto yy37; + ++cursor; + if ((yych = *cursor) <= 'Z') + { + if (yych <= '/') + goto yy85; + if (yych <= '9') + goto yy36; + if (yych >= 'A') + goto yy36; + } + else + { + if (yych <= '_') + { + if (yych >= '_') + goto yy36; + } + else + { + if (yych <= '`') + goto yy85; + if (yych <= 'z') + goto yy36; + } + } + yy85: +#line 74 "lexer.re" + { + ts.push_token(Token(Token::push, lineno)); + token_start = cursor; + + continue; + } +#line 654 "lexer.cpp" + yy86: + yych = *++cursor; + if (yych != 'n') + goto yy37; + yych = *++cursor; + if (yych != 't') + goto yy37; + ++cursor; + if ((yych = *cursor) <= 'Z') + { + if (yych <= '/') + goto yy89; + if (yych <= '9') + goto yy36; + if (yych >= 'A') + goto yy36; + } + else + { + if (yych <= '_') + { + if (yych >= '_') + goto yy36; + } + else + { + if (yych <= '`') + goto yy89; + if (yych <= 'z') + goto yy36; + } + } + yy89: +#line 102 "lexer.re" + { + ts.push_token(Token(Token::print, lineno)); + token_start = cursor; + + continue; + } +#line 681 "lexer.cpp" + yy90: + ++cursor; + if ((yych = *cursor) <= 'Z') + { + if (yych <= '/') + goto yy91; + if (yych <= '9') + goto yy36; + if (yych >= 'A') + goto yy36; + } + else + { + if (yych <= '_') + { + if (yych >= '_') + goto yy36; + } + else + { + if (yych <= '`') + goto yy91; + if (yych <= 'z') + goto yy36; + } + } + yy91: +#line 81 "lexer.re" + { + ts.push_token(Token(Token::pop, lineno)); + token_start = cursor; + + continue; + } +#line 704 "lexer.cpp" + yy92: + ++cursor; + state = (3); + if (limit <= cursor) + return true; + yyFillLabel3: + yych = *cursor; + yy93: + if (yych <= '/') + goto yy5; + if (yych <= '9') + goto yy92; + goto yy5; + yy94: + yych = *++cursor; + if (yych <= '@') + { + if (yych <= '/') + goto yy95; + if (yych <= '9') + goto yy96; + } + else + { + if (yych <= 'F') + goto yy96; + if (yych <= '`') + goto yy95; + if (yych <= 'f') + goto yy96; + } + yy95: + cursor = marker; + goto yy5; + yy96: + ++cursor; + state = (4); + if (limit <= cursor) + return true; + yyFillLabel4: + yych = *cursor; + if (yych <= '@') + { + if (yych <= '/') + goto yy98; + if (yych <= '9') + goto yy96; + } + else + { + if (yych <= 'F') + goto yy96; + if (yych <= '`') + goto yy98; + if (yych <= 'f') + goto yy96; + } + yy98: +#line 66 "lexer.re" + { + ts.push_token(Token(Token::xinteger, lineno, token_start, cursor)); + token_start = cursor; + + continue; + } +#line 751 "lexer.cpp" + yy99: + ++cursor; + yych = *cursor; + goto yy5; +#line 243 "lexer.re" + } + return true; +} + +/*! +** Fills up the buffer when neccessary. +** Note the buffer is always filled to the maximum, not just the +** number of bytes neccessary for the lexer to continue. +** +** \param nbytes - the number of bytes +*/ + +void Lexer::buffer_grow(size_t new_size) +{ + char* new_buffer = new char[new_size]; + + std::copy(buffer, limit, new_buffer); + + token_start = new_buffer + (token_start - buffer); + cursor = new_buffer + (cursor - buffer); + limit = new_buffer + new_size; + + buffer_size = new_size; + + delete[] buffer; + buffer = new_buffer; +} + +void Lexer::read(size_t nbytes) +{ + if (token_start + nbytes > limit) + { // we need larger buffer + buffer_grow(token_start - buffer + nbytes); + } + + std::copy(token_start, limit, buffer); + cursor -= token_start - buffer; + char* old_limit = limit - (token_start - buffer); + token_start = buffer; + + file->read(old_limit, limit - old_limit); + if (file->eof()) + { + size_t bytes = file->gcount(); + std::fill(old_limit + bytes, limit, '\0'); + } +} + +void Lexer::buffer_init() +{ + file->read(buffer, buffer_size); + if (file->eof()) + { + size_t bytes = file->gcount(); + std::fill(buffer + bytes, buffer + buffer_size, '\0'); + } + + cursor = marker = token_start = buffer; + limit = buffer + buffer_size; +} + +} // namespace Lexer + +} // namespace ASM +} // namespace SpasmImpl diff --git a/src/asm/lexer.hpp b/src/asm/lexer.hpp new file mode 100644 index 0000000..ece4a07 --- /dev/null +++ b/src/asm/lexer.hpp @@ -0,0 +1,70 @@ +#ifndef LEXER_HPP +#define LEXER_HPP + +#include + +#include "token.hpp" + +namespace SpasmImpl +{ +// ! Namespace for all classes and functions dealing with assembler +namespace ASM +{ +//! Namespace for all lexical analisys classes +namespace Lexer +{ +/*! +** Class for lexers for the assembler-like language for spasm +*/ +class Lexer +{ + public: + Lexer(std::istream&, size_t = 4096); + ~Lexer(); + bool tokenize(TokenStream&); + + //! fills the buffer called when the lexer needs more data + void read(size_t = 1); + void buffer_init(); + + private: + Lexer(const Lexer&); + Lexer& operator=(const Lexer&); + + void buffer_grow(size_t); + + //! input stream for the lexer + std::istream* file; + + //! buffer for the lexer + char* buffer; + + //! size of the buffer + size_t buffer_size; + + //! cursor for re2c generated lexer + char* cursor; + + //! limit for re2c generated lexer + char* limit; + + //! marker for re2c generated lexer + char* marker; + + //! pointer to the start of the just recognized token + char* token_start; + + //! saves the state of the lexer + unsigned int state; + + //! current char + char yych; + + //! number of current line + size_t lineno; +}; +} // namespace Lexer +} // namespace ASM +} // namespace SpasmImpl + +#endif diff --git a/src/asm/lexer.re b/src/asm/lexer.re new file mode 100644 index 0000000..5e21796 --- /dev/null +++ b/src/asm/lexer.re @@ -0,0 +1,307 @@ +#include + +#include "lexer.hpp" + +#include "token.hpp" + +namespace SpasmImpl +{ + namespace ASM + { + //! Namespace for all lexical analisys classes + namespace Lexer + { + + Lexer::Lexer (std::istream & _file, size_t _buffer_size) + : file (&_file), buffer_size (_buffer_size), state (unsigned(-1)), + lineno (0) + { + buffer = new char[buffer_size]; + cursor = limit = marker = token_start = NULL; + } + + Lexer::~Lexer () + { + delete [] buffer; + } + + bool Lexer::tokenize (TokenStream &ts) + { +/*!re2c +re2c:indent:top = 5; + +re2c:define:YYFILL="return true;"; +re2c:define:YYFILL:naked=1; +re2c:define:YYCTYPE="char"; +re2c:define:YYCURSOR=cursor; +re2c:define:YYLIMIT=limit; +re2c:define:YYMARKER=marker; +re2c:define:YYGETSTATE=state; +re2c:define:YYGETSTATE:naked=1; +re2c:define:YYSETSTATE="state = "; +re2c:define:YYSETSTATE:naked=1; +*/ + +/*!getstate:re2c */ + + while (1) { + +/*!re2c + +DIGIT = [0-9] ; +XDIGIT = [0-9a-fA-F] ; + +INTEGER = "-"? "0" | ([1-9] DIGIT*) ; +XINTEGER = "0" [xX] XDIGIT+ ; +IDENTIFIER = [a-zA-Z_] [0-9a-zA-Z_]* ; + +INTEGER { + ts.push_token (Token (Token::integer, lineno, + token_start, cursor)); + token_start = cursor; + + continue; + } + +XINTEGER { + ts.push_token (Token (Token::xinteger, lineno, + token_start, cursor)); + token_start = cursor; + + continue; + } + +"push" { + ts.push_token (Token (Token::push, lineno)); + token_start = cursor; + + continue; + } + +"pop" { + ts.push_token (Token (Token::pop, lineno)); + token_start = cursor; + + continue; + } + +"dup" { + ts.push_token (Token (Token::dup, lineno)); + token_start = cursor; + + continue; + } + +"read" { + ts.push_token (Token (Token::read, lineno)); + token_start = cursor; + + continue; + } + +"print" { + ts.push_token (Token (Token::print, lineno)); + token_start = cursor; + + continue; + } + +"+" { + ts.push_token (Token (Token::plus, lineno)); + token_start = cursor; + + continue; + } + +"-" { + ts.push_token (Token (Token::minus, lineno)); + token_start = cursor; + + continue; + } + +"*" { + ts.push_token (Token (Token::multiply, lineno)); + token_start = cursor; + + continue; + } + +"/" { + ts.push_token (Token (Token::divide, lineno)); + token_start = cursor; + + continue; + } + +"%" { + ts.push_token (Token (Token::modulus, lineno)); + token_start = cursor; + + continue; + } + +"gotrue" { + ts.push_token (Token (Token::gotrue, lineno)); + token_start = cursor; + + continue; + } + +"gofalse" { + ts.push_token (Token (Token::gofalse, lineno)); + token_start = cursor; + + continue; + } + +"go" { + ts.push_token (Token (Token::go, lineno)); + token_start = cursor; + + continue; + } + +"call" { + ts.push_token (Token (Token::call, lineno)); + token_start = cursor; + + continue; + } + +"ret" { + ts.push_token (Token (Token::ret, lineno)); + token_start = cursor; + + continue; + } + +"load" { + ts.push_token (Token (Token::load, lineno)); + token_start = cursor; + + continue; + } + +"store" { + ts.push_token (Token (Token::store, lineno)); + token_start = cursor; + + continue; + } +"<=" { + ts.push_token (Token (Token::lesseq, lineno)); + token_start = cursor; + + continue; + } +"<" { + ts.push_token (Token (Token::less, lineno)); + token_start = cursor; + + continue; + } + +"label" { + ts.push_token (Token (Token::label, lineno)); + token_start = cursor; + + continue; + } + +IDENTIFIER { + ts.push_token (Token (Token::ident, lineno, token_start, + cursor)); + token_start = cursor; + + continue; + } + +[ ]+ { + token_start = cursor; + + continue; + } + +"\n" { + ++lineno; + token_start = cursor; + + continue; + } + +"\000" { + ts.push_token (Token (Token::endinput, lineno)); + + break; + } + +[^] { + return false; + } + +*/ + } + return true; + } + + /*! + ** Fills up the buffer when neccessary. + ** Note the buffer is always filled to the maximum, not just the + ** number of bytes neccessary for the lexer to continue. + ** + ** \param nbytes - the number of bytes + */ + + void Lexer::buffer_grow (size_t new_size) + { + char *new_buffer = new char[new_size]; + + std::copy (buffer, limit, new_buffer); + + token_start = new_buffer + (token_start - buffer); + cursor = new_buffer + (cursor - buffer); + limit = new_buffer + new_size; + + buffer_size = new_size; + + delete [] buffer; + buffer = new_buffer; + } + + void Lexer::read (size_t nbytes) + { + if (token_start + nbytes > limit) { // we need larger buffer + buffer_grow (token_start - buffer + nbytes); + } + + std::copy (token_start, limit, buffer); + cursor -= token_start - buffer; + char *old_limit = limit - (token_start - buffer); + token_start = buffer; + + file->read (old_limit, limit - old_limit); + if (file->eof ()) { + size_t bytes = file->gcount (); + std::fill (old_limit + bytes, limit, '\0'); + } + } + + void Lexer::buffer_init () + { + file->read (buffer, buffer_size); + if (file->eof ()) { + size_t bytes = file->gcount (); + std::fill (buffer + bytes, buffer + buffer_size, '\0'); + } + + cursor = marker = token_start = buffer; + limit = buffer + buffer_size; + } + + + } // namespace Lexer + + } // namespace ASM +} // namespace SpasmImpl + diff --git a/src/asm/main.cpp b/src/asm/main.cpp new file mode 100644 index 0000000..da8fcf6 --- /dev/null +++ b/src/asm/main.cpp @@ -0,0 +1,21 @@ +#include +#include +#include "assembler.hpp" + +int main(int argc, const char* argv[]) +{ + if (argc != 2) + return 1; + SpasmImpl::ASM::Bytecode_Memory bytecode; + SpasmImpl::ASM::compile(std::cin, bytecode); + + std::ofstream output(argv[1], std::ios_base::out | std::ios_base::binary); + + // output.write ("SPASM", 5); + auto& bc = bytecode.bytecode(); + auto size = bc.size(); + output.write(reinterpret_cast(&size), sizeof(size)); + output.write(reinterpret_cast(bc.data()), size); + + return 0; +} diff --git a/src/asm/symbol.cpp b/src/asm/symbol.cpp new file mode 100644 index 0000000..7964142 --- /dev/null +++ b/src/asm/symbol.cpp @@ -0,0 +1,120 @@ +#include +#include + +#include "symbol.hpp" + +namespace SpasmImpl +{ +namespace ASM +{ +const size_t Symbol::notdefined = ~0ull; + +Symbol::Symbol() : _definition(notdefined) {} + +Symbol::Symbol(const std::string& identifier, size_t definition) + : _identifier(identifier), _definition(definition) +{ +} + +const std::string& Symbol::identifier() const +{ + return _identifier; +} + +size_t Symbol::definition() const +{ + return _definition; +} + +void Symbol::define(size_t definition) +{ + _definition = definition; +} + +size_t Symbol::add_position(size_t position) +{ + _positions.push_back(position); + + return _definition; +} + +Symbol::Positions_t::const_iterator Symbol::positions_begin() const +{ + return _positions.begin(); +} + +Symbol::Positions_t::const_iterator Symbol::positions_end() const +{ + return _positions.end(); +} + +Symbol_Table::Symbol_Table() {} + +/*! +** Search the table for symbol by identifier +** +** \param identifier - identifier of the symbol +** +** \return pointer to the symbol if it exists or NULL otherwise. +*/ +Symbol* Symbol_Table::find(const std::string& identifier) const +{ + const_iterator i = _table.find(identifier); + return (i != _table.end()) ? i->second : NULL; +} + +/*! +** Insert symbol with identifier indentifier on position position +** of just add new position for symbol. +** \param identifier - identifer of the symbol +** \param position - position of the symbol +** +** \return pointer to the symbol +*/ +Symbol* Symbol_Table::insert(const std::string& identifier, size_t position) +{ + Symbol* psymbol = find(identifier); + if (psymbol == NULL) + { + psymbol = new Symbol(identifier); + _table.insert(std::make_pair(identifier, psymbol)); + } + psymbol->add_position(position); + + return psymbol; +} + +/*! +** define symbol with identifier indentifier +** If the symbol already exists its definition is changed +** \param identifier - identifer of the symbol +** \param definition - definition of the symbol +** +** \return pointer to the symbol +*/ +Symbol* Symbol_Table::define(const std::string& identifier, size_t definition) +{ + Symbol* psymbol = find(identifier); + if (psymbol == NULL) + { + psymbol = new Symbol(identifier, definition); + _table.insert(std::make_pair(identifier, psymbol)); + } + else + psymbol->define(definition); + + return psymbol; +} + +Symbol_Table::const_iterator Symbol_Table::begin() const +{ + return _table.begin(); +} + +Symbol_Table::const_iterator Symbol_Table::end() const +{ + return _table.end(); +} + +} // namespace ASM +} // namespace SpasmImpl diff --git a/src/asm/symbol.hpp b/src/asm/symbol.hpp new file mode 100644 index 0000000..6ce4dbf --- /dev/null +++ b/src/asm/symbol.hpp @@ -0,0 +1,69 @@ +#ifndef SYMBOL_HPP +#define SYMBOL_HPP + +#include +#include +#include + +namespace SpasmImpl +{ +namespace ASM +{ +//! Represents symbol table entry for the assembler +class Symbol +{ + public: + typedef std::list Positions_t; + static const size_t notdefined; + Symbol(); + Symbol(const std::string&, size_t = 0); + + const std::string& identifier() const; + size_t definition() const; + + void define(size_t); + + size_t add_position(size_t); + + Positions_t::const_iterator positions_begin() const; + Positions_t::const_iterator positions_end() const; + + private: + //! identifier of the symbol + std::string _identifier; + + //! position of definition of the identifier + size_t _definition; + + //! list of uses of the identifier (positions) + Positions_t _positions; +}; + +//! This is the symbol table of the assembler +class Symbol_Table +{ + private: + typedef std::map Table_t; + typedef Table_t::iterator iterator; + + public: + Symbol_Table(); + typedef Table_t::const_iterator const_iterator; + + Symbol* find(const std::string&) const; + Symbol* insert(const std::string&, size_t); + Symbol* define(const std::string&, size_t); + + const_iterator begin() const; + const_iterator end() const; + + private: + Symbol_Table(const Symbol_Table&); + Symbol_Table& operator=(const Symbol_Table&); + + Table_t _table; +}; +} // namespace ASM +} // namespace SpasmImpl + +#endif // SYMBOL_HPP diff --git a/src/asm/token.cpp b/src/asm/token.cpp new file mode 100644 index 0000000..6c88bef --- /dev/null +++ b/src/asm/token.cpp @@ -0,0 +1,65 @@ +#include +#include +#include +#include + +#include "token.hpp" + +namespace SpasmImpl +{ +namespace ASM +{ +namespace Lexer +{ +Token::Token(Token_type type) + : _type(type), _lineno(0), _value_int(0), _value_str("") +{ +} + +Token::Token(Token::Token_type type, + size_t lineno, + const char* start, + const char* end) + : _type(type), _lineno(lineno) +{ + if (_type == integer || _type == xinteger) + { + _value_int = strtol(start, NULL, 0); + } + else if (_type == ident) + { + if (end) + { + _value_str = std::string(start, end); + } + else + { + _value_str = std::string(start); + } + } +} + +Token::Token_type Token::type() const +{ + return _type; +} + +int Token::value_int() const +{ + return _value_int; +} + +const std::string& Token::value_str() const +{ + return _value_str; +} + +size_t Token::lineno() const +{ + return _lineno; +} + +} // namespace Lexer + +} // namespace ASM +} // namespace SpasmImpl diff --git a/src/asm/token.hpp b/src/asm/token.hpp new file mode 100644 index 0000000..4ef7ce0 --- /dev/null +++ b/src/asm/token.hpp @@ -0,0 +1,85 @@ +#ifndef TOKEN_HPP +#define TOKEN_HPP + +#include + +#define TOKENS \ + TOK(push) \ + TOK(pop) \ + TOK(dup) \ + TOK(print) \ + TOK(read) \ + TOK(plus) \ + TOK(minus) \ + TOK(multiply) \ + TOK(divide) \ + TOK(modulus) \ + TOK(gotrue) \ + TOK(gofalse) \ + TOK(go) \ + TOK(call) \ + TOK(ret) \ + TOK(load) \ + TOK(store) \ + TOK(less) \ + TOK(lesseq) \ + TOK(label) \ + TOK(ident) \ + TOK(integer) \ + TOK(xinteger) \ + TOK(endinput) + +namespace SpasmImpl +{ +namespace ASM +{ +namespace Lexer +{ +class Token +{ + public: + enum Token_type + { + halt = 0, +#define TOK(x) x, + TOKENS +#undef TOK + notused + }; + + Token(Token_type = notused); + + Token(Token_type, size_t, const char* = NULL, const char* = NULL); + + Token_type type() const; + + size_t lineno() const; + + int value_int() const; + + const std::string& value_str() const; + + private: + Token_type _type; + + size_t _lineno; + + int _value_int; + + std::string _value_str; +}; + +class TokenStream +{ + public: + virtual void push_token(const Token&) = 0; + virtual ~TokenStream(){}; +}; + +} // namespace Lexer +} // namespace ASM +} // namespace SpasmImpl + +#undef TOKENS + +#endif diff --git a/src/asm/tokenizer.cpp b/src/asm/tokenizer.cpp new file mode 100644 index 0000000..8694ccf --- /dev/null +++ b/src/asm/tokenizer.cpp @@ -0,0 +1,51 @@ +#include +#include +#include + +#include "lexer.hpp" +#include "token.hpp" +#include "tokenizer.hpp" + +namespace SpasmImpl +{ +namespace ASM +{ +namespace Lexer +{ +Tokenizer::Tokenizer(std::istream& istr) + : _lexer(new Lexer(istr, 1024)), end_input(false) +{ + _lexer->buffer_init(); +} + +void Tokenizer::push_token(const Token& token) +{ + _tokens.push(token); + if (token.type() == Token::endinput) + end_input = true; +} + +Token Tokenizer::next_token() +{ + Token t(Token::endinput); + if (!_tokens.empty()) + { + t = _tokens.front(); + _tokens.pop(); + } + else if (!end_input) + { + while (_tokens.empty()) + { + _lexer->read(); + _lexer->tokenize(*this); + } + t = _tokens.front(); + _tokens.pop(); + } + return t; +} + +} // namespace Lexer +} // namespace ASM +} // namespace SpasmImpl diff --git a/src/asm/tokenizer.hpp b/src/asm/tokenizer.hpp new file mode 100644 index 0000000..1155db7 --- /dev/null +++ b/src/asm/tokenizer.hpp @@ -0,0 +1,35 @@ +#ifndef TOKENIZER_HPP +#define TOKENIZER_HPP + +#include +#include +#include + +#include "lexer.hpp" +#include "token.hpp" + +namespace SpasmImpl +{ +namespace ASM +{ +namespace Lexer +{ +class Tokenizer : public TokenStream +{ + public: + Tokenizer(std::istream&); + + virtual void push_token(const Token&); + Token next_token(); + + private: + std::unique_ptr _lexer; + std::queue _tokens; + bool end_input; +}; // class Tokenizer +} // namespace Lexer + +} // namespace ASM +} // namespace SpasmImpl + +#endif diff --git a/src/dstack.cpp b/src/dstack.cpp new file mode 100644 index 0000000..93592ed --- /dev/null +++ b/src/dstack.cpp @@ -0,0 +1,172 @@ +#include "dstack.hpp" + +#include + +namespace SpasmImpl +{ +Dstack::Dstack() : bottom(NULL), tos(NULL), s_size(0) {} + +Dstack::Dstack(const Dstack& ds) : s_size(ds.s_size) +{ + copy_dstack(ds); +} + +Dstack& Dstack::operator=(const Dstack& ds) +{ + if (this != &ds) + { + if (bottom) + delete[] bottom; + s_size = ds.s_size; + copy_dstack(ds); + } + return *this; +} + +Dstack::~Dstack() +{ + if (bottom) + delete[] bottom; +} + +/** + * Makes the stack occupy new_size bytes + * \param new_size new size for the stack + */ +void Dstack::reserve(size_t new_size) +{ + size_t offset = tos - bottom; + byte* new_bottom = new byte[new_size]; + if (bottom) + { + std::copy(bottom, bottom + std::min(s_size, new_size), new_bottom); + delete[] bottom; + } + bottom = new_bottom; + tos = new_bottom + offset; + s_size = new_size; +} + +/*! +** Pushes x in the stack. +** If the stack is full its size is doubled. +** \param x data_t object to be pushed on the stack +*/ +void Dstack::push(data_t x) +{ + if (bottom + s_size < tos + sizeof(data_t)) + reserve((s_size ? s_size : sizeof(data_t)) * 2); + *((data_t*)tos) = x; + tos += sizeof(data_t); +} + +/*! +** Pushes the object of size x_size bytes pointed by x in the stack. +** If the stack is full its size is doubled (or more is x_size is greater +** than the size of the stack). +** \param x pointer to the element to be pushed on the stack +** \param x_size size of the element +*/ +void Dstack::push(byte* x, size_t x_size) +{ + if (bottom + s_size < tos + x_size) + reserve(s_size + ((s_size > x_size) ? s_size : x_size)); + std::copy(x, x + x_size, tos); + tos += x_size; +} + +/*! +** Pops an object of size x_size from the stack. +** The object is written to the place pointed by x. +** +** \param x pointer to the place for popping +** \param x_size size of the object to be popped +*/ +void Dstack::pop(void* x, size_t x_size) +{ + if (tos - x_size >= bottom) + { + std::copy(tos - x_size, tos, (byte*)x); + tos -= x_size; + } +} + +/*! +** \return a single data_t object, popping it from the stack. +*/ +data_t Dstack::pop() +{ + data_t x{}; + if (tos - sizeof(data_t) >= bottom) + { + tos -= sizeof(data_t); + x = *((data_t*)tos); + } + return x; +} + +/*! +** \return copy of the data_t object that is on top of the stack +*/ +data_t Dstack::top() const +{ + data_t x{}; + if (tos - sizeof(data_t) >= bottom) + { + x = *((data_t*)(tos - sizeof(data_t))); + } + return x; +} + +/*! +** \return the size of the stack in bytes +*/ +size_t Dstack::size() const +{ + return tos - bottom; +} + +/*! +** \return the space reserved for the stack in bytes +*/ +size_t Dstack::reserved() const +{ + return s_size; +} + +/*! +** Frees unused memory. Note that it is not always possible because memory +** management is done with new / delete +*/ + +void Dstack::strip_memory() +{ + reserve(size()); +} + +/*! +** \return true if the stack is empty +*/ +bool Dstack::empty() const +{ + return tos - bottom == 0; +} + +/*! +** Creates a copy of ds +** +** \param ds data stack to be copied +*/ +void Dstack::copy_dstack(const Dstack& ds) +{ + if (ds.bottom) + { + bottom = new byte[ds.s_size]; + tos = bottom + (ds.tos - ds.bottom); + std::copy(ds.bottom, ds.tos, bottom); + } + else + bottom = tos = NULL; +} + +} // namespace SpasmImpl diff --git a/src/dstack.hpp b/src/dstack.hpp new file mode 100644 index 0000000..850b66b --- /dev/null +++ b/src/dstack.hpp @@ -0,0 +1,46 @@ +#ifndef DSTACK_HPP +#define DSTACK_HPP + +#include "types.hpp" + +namespace SpasmImpl +{ +//! class representing the data stack + +/*! The class is quite simple stack. It is byte-orientatied - every push +** and pop is done in bytes with no taking care of any byte order! +*/ +class Dstack +{ + public: + Dstack(); + Dstack(const Dstack&); + Dstack& operator=(const Dstack&); + ~Dstack(); + void push(data_t); + void push(byte*, size_t); + void pop(void*, size_t); + data_t pop(); + data_t top() const; + + void reserve(size_t); + void strip_memory(); + size_t size() const; + size_t reserved() const; + bool empty() const; + + private: + void copy_dstack(const Dstack&); + + //! pointer to the bottom of the stack + byte* bottom; + + //! pointer to the top of the stack + byte* tos; + + //! size of the stack in bytes + size_t s_size; +}; +} // namespace SpasmImpl + +#endif // #ifndef DSTACK_HPP diff --git a/src/frames.cpp b/src/frames.cpp new file mode 100644 index 0000000..8b7c891 --- /dev/null +++ b/src/frames.cpp @@ -0,0 +1,130 @@ +#include + +#include "types.hpp" + +#include "frames.hpp" + +namespace SpasmImpl +{ +FrameStack::FrameStack() : base_ptr(NULL), frame_ptr(NULL), g_size(0), c_size(0) +{ +} + +FrameStack::FrameStack(const FrameStack& fs) + : g_size(fs.g_size), c_size(fs.c_size), fstack(fs.fstack) +{ + copy_fstack(fs); +} + +FrameStack::~FrameStack() +{ + delete_fstack(); +} + +FrameStack& FrameStack::operator=(const FrameStack& fs) +{ + if (this != &fs) + { + delete_fstack(); + copy_fstack(fs); + g_size = fs.g_size; + c_size = fs.c_size; + fstack = fs.fstack; + } + return *this; +} + +/*! +** Deletes the frame stack +*/ +void FrameStack::delete_fstack() +{ + if (base_ptr) + delete[] base_ptr; +} + +/*! +** Copies the frame stack fs +** +** \param fs - the frame stack to be copied +*/ +void FrameStack::copy_fstack(const FrameStack& fs) +{ + base_ptr = new data_t[fs.g_size]; + std::copy(fs.base_ptr, fs.frame_ptr + fs.c_size, base_ptr); + frame_ptr = base_ptr + (fs.frame_ptr - fs.base_ptr); +} + +/*! +** Returns a data_t object from the current frame +** +** \param index - index of the data_t object +** \return const reference to the object +*/ +const data_t& FrameStack::operator[](size_t index) const +{ + return frame_ptr[index]; +} + +/*! +** Returns a data_t object from the current frame +** +** \param index - index of the data_t object +** \return reference to the object +*/ +data_t& FrameStack::operator[](size_t index) +{ + return frame_ptr[index]; +} + +/*! +** Removes the current frame from the stack. +** It is called when a function does return. +*/ +void FrameStack::pop_frame() +{ + if (fstack.empty()) + { + frame_ptr = base_ptr; + c_size = 0; + } + else + { + data_t* new_frame_ptr = base_ptr + fstack.top(); + fstack.pop(); + c_size = frame_ptr - new_frame_ptr; + frame_ptr = new_frame_ptr; + } +} + +/*! +** Creates (pushes on the stack) new frame of fsize data_t objects +** +** \param fsize - size in data_t objects of the new frame +*/ +void FrameStack::new_frame(size_t fsize) +{ + if (frame_ptr + c_size + fsize > base_ptr + g_size) + { + size_t new_size = g_size + std::max(g_size, c_size + fsize); + data_t* new_base = new data_t[new_size]; + if (base_ptr) + { + std::copy(base_ptr, frame_ptr + c_size, new_base); + delete[] base_ptr; + } + frame_ptr = new_base + (frame_ptr - base_ptr); + base_ptr = new_base; + } + fstack.push(frame_ptr - base_ptr); + c_size = fsize; +} + +/*! +** \return true if the stack is empty +*/ +bool FrameStack::empty() const +{ + return frame_ptr == base_ptr && c_size == 0; +} +} // namespace SpasmImpl diff --git a/src/frames.hpp b/src/frames.hpp new file mode 100644 index 0000000..14d1d14 --- /dev/null +++ b/src/frames.hpp @@ -0,0 +1,51 @@ +#ifndef FRAMES_HPP +#define FRAMES_HPP + +#include + +#include "types.hpp" + +namespace SpasmImpl +{ +//! Class representing the stack frame for a function +/*! +** The class is implemented as a simple stack of frames while each frame +** is built up by a number of data_t objects +*/ +class FrameStack +{ + public: + FrameStack(); + FrameStack(const FrameStack&); + ~FrameStack(); + FrameStack& operator=(const FrameStack&); + + const data_t& operator[](size_t) const; + data_t& operator[](size_t); + void pop_frame(); + void new_frame(size_t); + bool empty() const; + + private: + //! pointer to the base of the stack + data_t* base_ptr; + + //! pointer to the beginning of the current frame + data_t* frame_ptr; + + //! size of the whole stack in data_t objects + size_t g_size; + + //! size of the current frame in data_t objects + size_t c_size; + + //! stack of the offsets between frames in the stack. + std::stack fstack; + + void copy_fstack(const FrameStack&); + void delete_fstack(); +}; + +} // namespace SpasmImpl + +#endif // #ifndef FRAMES_HPP diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 0000000..17bb322 --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,33 @@ +#include +#include + +#include +#include "spasm.hpp" + +int main(int argc, const char* argv[]) +{ + if (argc != 2) + return 1; + + std::ifstream input(argv[1], std::ios_base::in | std::ios_base::binary); + + size_t len; + + input.read((char*)&len, sizeof(len)); + + std::unique_ptr bytecode(new Spasm::byte[len]); + + input.read((char*)bytecode.get(), len); + + for (size_t i = 0; i < len; ++i) + std::cout << std::hex << (int)bytecode[i] << ' '; + std::cout << std::endl; + + Spasm::Spasm vm(len, bytecode.get()); + + vm.run(); + + std::cout << std::endl; + + return 0; +} diff --git a/src/program.spa b/src/program.spa new file mode 100644 index 0000000..d92456a --- /dev/null +++ b/src/program.spa @@ -0,0 +1,12 @@ +read +label next +dup +push 1 +< +gotrue bye +push 1 +- +dup +print +go next +label bye diff --git a/src/spasm.cpp b/src/spasm.cpp new file mode 100644 index 0000000..e67c975 --- /dev/null +++ b/src/spasm.cpp @@ -0,0 +1,348 @@ +#include +#include + +#include "spasm.hpp" + +namespace SpasmImpl +{ +PC_t Spasm::op_size = 21; +// Be sure the same number is on the previous and next lines +Operation Spasm::operations[] = {NULL, + &Spasm::push, + &Spasm::pop, + &Spasm::dup, + &Spasm::print, + &Spasm::read, + &Spasm::plus, + &Spasm::minus, + &Spasm::multiply, + &Spasm::divide, + &Spasm::modulus, + &Spasm::gotrue, + &Spasm::gofalse, + &Spasm::go, + &Spasm::call, + &Spasm::ret, + &Spasm::load, + &Spasm::store, + &Spasm::less, + &Spasm::lesseq}; + +Spasm::Spasm() + : pc(0), bc_size(0), bytecode(NULL), istr(&std::cin), ostr(&std::cout) +{ +} + +/*! +** Constructs new Spasm object +** +** \param _bc_size - size/length of the bytecode +** \param _bytecode - the bytecode of the program +** \param _istr - input stream for the machine +** \param _ostr - output stream for the machine +*/ +Spasm::Spasm(PC_t _bc_size, + const byte* _bytecode, + std::istream& _istr, + std::ostream& _ostr) + : pc(0), bc_size(_bc_size), istr(&_istr), ostr(&_ostr) +{ + bytecode = new byte[bc_size]; + std::copy(_bytecode, _bytecode + bc_size, bytecode); +} + +Spasm::Spasm(const Spasm& m) + : pc(m.pc), + bc_size(m.bc_size), + data_stack(m.data_stack), + return_stack(m.return_stack), + frame(m.frame), + istr(m.istr), + ostr(m.ostr) +{ + copybc(m); +} + +Spasm::~Spasm() +{ + deleteobj(); +} + +Spasm& Spasm::operator=(const Spasm& m) +{ + if (this != &m) + { + deleteobj(); + data_stack = m.data_stack; + return_stack = m.return_stack; + frame = m.frame; + istr = m.istr; + ostr = m.ostr; + copybc(m); + } + return *this; +} + +/*! +** Copies the bytecode of another machine m +** +** \param m - the machine from the bytecode is copied +*/ + +void Spasm::copybc(const Spasm& m) +{ + bytecode = new byte[bc_size]; + std::copy(m.bytecode, m.bytecode + bc_size, bytecode); +} + +/*! +** Deletes the machine +*/ +void Spasm::deleteobj() +{ + if (bytecode) + delete[] bytecode; +} + +/*! +** Returns the dstack, so that it can be examined after execution +** +** \return const reference to the data stack +*/ +const Dstack& Spasm::get_dstack() const +{ + return data_stack; +} + +/*! +** Starts the machine. The machine stops if it reaches an invalid opcode +** or opcode 0 or the pc reaches beyond the end of the bytecode. +*/ +void Spasm::run() +{ + while (pc < bc_size) + { + if (bytecode[pc] > 0 && bytecode[pc] < op_size) + (this->*operations[bytecode[pc]])(); + else + { + std::cerr << "opcode got to " << int(bytecode[pc]) << std::endl; + break; + } + ++pc; + } +} + +/*! +** Pushes the next data_t object on the data stack +*/ +void Spasm::push() +{ + ++pc; + data_stack.push(*reinterpret_cast(bytecode + pc)); + pc += sizeof(data_t) - 1; +} + +/*! +** Pops a data_t object from the data stack. +*/ +void Spasm::pop() +{ + data_stack.pop(); +} + +/*! +** Dups the data_t object on top of the data stack. +*/ +void Spasm::dup() +{ + data_stack.push(data_stack.top()); +} + +/*! +** Reads a data_t object from the input stream and pushes it on the data +** stack. +*/ +void Spasm::read() +{ + data_t x; + *istr >> x; + data_stack.push(x); +} + +/*! +** Pops a data_t object from the data stack and prints it on the output +** stream. +*/ +void Spasm::print() +{ + *ostr << data_stack.pop(); +} + +/*! +** Pops two data objects from the data stack and pushes their sum on the +** data stack. +*/ +void Spasm::plus() +{ + data_t x, y = data_stack.pop(); + x = data_stack.pop(); + data_stack.push(x + y); +} + +/*! +** Pops two data objects from the data stack and pushes their difference +** on the data stack. +*/ +void Spasm::minus() +{ + data_t x, y = data_stack.pop(); + x = data_stack.pop(); + data_stack.push(x - y); +} + +/*! +** Pops two data objects from the data stack and pushes their product +** on the data stack. +*/ +void Spasm::multiply() +{ + data_t x, y = data_stack.pop(); + x = data_stack.pop(); + data_stack.push(x * y); +} + +/*! +** Pops two data objects from the data stack and pushes their division +** on the data stack. +*/ +void Spasm::divide() +{ + data_t x, y = data_stack.pop(); + x = data_stack.pop(); + data_stack.push(x / y); +} + +/*! +** Pops two data objects from the data stack and pushes their modulus +** on the data stack. +*/ +void Spasm::modulus() +{ + data_t x, y = data_stack.pop(); + x = data_stack.pop(); + data_stack.push(x % y); +} + +/*! +** Conditional execution. +** If the data_t object on top of the data stack evaluates to true +** execution continues from the place pointed by number in the next bytes +*/ +void Spasm::gotrue() +{ + ++pc; + if (data_stack.pop()) + pc = *(reinterpret_cast(bytecode + pc)) - 1; + else + pc += sizeof(size_t) - 1; +} + +/*! +** Conditional execution. +** If the data_t object on top of the data stack evaluates to false +** execution continues from the place pointed by number in the next bytes +*/ +void Spasm::gofalse() +{ + ++pc; + if (!data_stack.pop()) + pc = *(reinterpret_cast(bytecode + pc)) - 1; + else + pc += sizeof(size_t) - 1; +} + +/*! +** Unconditional execution. +** Execution continues from the opcode pointed by the next bytes +*/ +void Spasm::go() +{ + ++pc; + pc = *(reinterpret_cast(bytecode + pc)) - 1; +} + +/*! +** Function call. A new frame with the specified size is created, the +** return address is saved in the return stack and the new pc is loaded. +*/ +void Spasm::call() +{ + size_t fs; // new frame size + return_stack.push(pc); // using the ++pc in run() + data_stack.pop(&fs, sizeof(fs)); + data_stack.pop(&pc, sizeof(pc)); + frame.new_frame(fs); + --pc; // the ++pc in run() +} + +/*! +** Function return. The frame of the current function is destroyed and the +** saved return address is loaded in the pc +*/ +void Spasm::ret() +{ + pc = return_stack.top(); + return_stack.pop(); + frame.pop_frame(); +} + +/*! +** Local variable with index top of the data stack is pushed on top of the +** data stack. +*/ +void Spasm::load() +{ + size_t offset; + + data_stack.pop(&offset, sizeof(offset)); + data_stack.push(frame[offset]); +} + +/*! +** Local variable is assigned value +*/ +void Spasm::store() +{ + data_t value = data_stack.pop(); + size_t offset; + + data_stack.pop(&offset, sizeof(offset)); + frame[offset] = value; +} + +/*! +** Compares the values on top of the stack. Pushes 1 if the value before +** the top of the stack is less than that on top of the stack. +*/ +void Spasm::less() +{ + data_t y = data_stack.pop(); + data_t x = data_stack.pop(); + + data_stack.push(x < y); +} + +/*! +** Compares the values on top of the stack. Pushes 1 if the value before +** the top of the stack is less than or equal to that on top of the stack. +*/ +void Spasm::lesseq() +{ + data_t y = data_stack.pop(); + data_t x = data_stack.pop(); + + data_stack.push(x <= y); +} + +} // namespace SpasmImpl diff --git a/src/spasm.hpp b/src/spasm.hpp new file mode 100644 index 0000000..7468bd8 --- /dev/null +++ b/src/spasm.hpp @@ -0,0 +1,13 @@ +#ifndef SPASM_HPP +#define SPASM_HPP + +#include "spasm_impl.hpp" + +namespace Spasm +{ +using SpasmImpl::byte; +using SpasmImpl::PC_t; +using SpasmImpl::Spasm; +} // namespace Spasm + +#endif // #ifndef SPASM_HPP diff --git a/src/spasm_impl.hpp b/src/spasm_impl.hpp new file mode 100644 index 0000000..78c5d08 --- /dev/null +++ b/src/spasm_impl.hpp @@ -0,0 +1,97 @@ +#ifndef SPASM_IMPL_HPP +#define SPASM_IMPL_HPP + +#include + +#include "dstack.hpp" +#include "frames.hpp" +#include "types.hpp" + +namespace SpasmImpl +{ +//! The Abstract Stack Machine +/*! +** The machine contains a data stack for operations and control flow and +** frame stack for function calls (including parameter passing) and local +** variables and return stack for the addresses of the returns. +*/ +class Spasm +{ + public: + Spasm(); + Spasm(PC_t, + const byte*, + std::istream& = std::cin, + std::ostream& = std::cout); + Spasm(const Spasm&); + ~Spasm(); + Spasm& operator=(const Spasm&); + + void run(); + + const Dstack& get_dstack() const; + + private: + //! Operations (opcodes) of the machine + static Operation operations[]; + + //! number of operations + static PC_t op_size; + + //! Program counter - points the current opcode + PC_t pc; + + //! size of the program bytecode + PC_t bc_size; + + //! bytecode of the program + byte* bytecode; + + //! Data stack for arithmetic operations and control flow + Dstack data_stack; + + //! Return stack for the addresses of the returns + Rstack_t return_stack; + + //! Stack for the frame of the functions + FrameStack frame; + + //! Input stream for read () operation + std::istream* istr; + + //! Output stream for print () opertion + std::ostream* ostr; + + void push(); + void pop(); + void dup(); + + void print(); + void read(); + + void plus(); + void minus(); + void multiply(); + void divide(); + void modulus(); + + void gotrue(); + void gofalse(); + void go(); + + void call(); + void ret(); + + void load(); + void store(); + + void less(); + void lesseq(); + + // private method for copying and deleting an object + void copybc(const Spasm&); + void deleteobj(); +}; + +} // namespace SpasmImpl +#endif // #ifndef SPASM_IMPL_HPP diff --git a/src/types.hpp b/src/types.hpp new file mode 100644 index 0000000..0d86cab --- /dev/null +++ b/src/types.hpp @@ -0,0 +1,17 @@ +#ifndef TYPES_HPP +#define TYPES_HPP + +#include +#include + +namespace SpasmImpl +{ +typedef unsigned char byte; +typedef size_t PC_t; +typedef int data_t; +typedef std::stack Rstack_t; + +class Spasm; +typedef void (Spasm::*Operation)(); +} // namespace SpasmImpl +#endif // ----- #ifndef TYPES_HPP -- cgit v1.3.1-26-gb76a