summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohnny Richard <johnny@johnnyrichard.com>2024-10-30 22:58:03 +0100
committerJohnny Richard <johnny@johnnyrichard.com>2025-12-14 09:53:52 +0100
commit10bb8a05088f1d3bb24f7167f609b5f6fb0ba026 (patch)
tree7a4b3f69a461301c45204ed856b61f92a7d42233
bootstrap projectHEADmaster
Signed-off-by: Johnny Richard <johnny@johnnyrichard.com>
-rw-r--r--.clang-format246
-rw-r--r--.editorconfig13
-rw-r--r--.gitignore20
-rw-r--r--AUTHORS1
-rw-r--r--CODE_OF_CONDUCT182
-rw-r--r--COPYING674
-rw-r--r--COPYING.LESSER165
-rw-r--r--INSTALL365
-rw-r--r--Makefile.am37
-rw-r--r--NEWS0
-rw-r--r--README4
-rwxr-xr-xautogen.sh3
-rw-r--r--configure.ac34
-rw-r--r--docs/info/obe.texi54
-rw-r--r--examples/main.ir26
-rw-r--r--include/.gitignore1
-rw-r--r--include/obe/arena.h77
-rw-r--r--include/obe/array.h60
-rw-r--r--include/obe/ir.h80
-rw-r--r--include/obe/lexer.h84
-rw-r--r--include/obe/parser.h40
-rw-r--r--include/obe/string.h42
-rw-r--r--include/obe/utils.h27
-rw-r--r--include/obe/x86_64/codegen.h31
-rwxr-xr-xscripts/docstr2man241
-rwxr-xr-xscripts/format43
-rw-r--r--src/arena.c121
-rw-r--r--src/array.c67
-rw-r--r--src/ir.c42
-rw-r--r--src/lexer.c222
-rw-r--r--src/obe.c142
-rw-r--r--src/parser.c224
-rw-r--r--src/string.c34
-rw-r--r--src/utils.c74
-rw-r--r--src/x86_64/codegen.c152
-rw-r--r--tests/Makefile.am12
-rw-r--r--tests/obe_arena_test.c121
-rw-r--r--tests/obe_array_test.c85
38 files changed, 3846 insertions, 0 deletions
diff --git a/.clang-format b/.clang-format
new file mode 100644
index 0000000..db97ccb
--- /dev/null
+++ b/.clang-format
@@ -0,0 +1,246 @@
+---
+Language: Cpp
+# BasedOnStyle: Mozilla
+AccessModifierOffset: -2
+AlignAfterOpenBracket: Align
+AlignArrayOfStructures: None
+AlignConsecutiveAssignments:
+ Enabled: false
+ AcrossEmptyLines: false
+ AcrossComments: false
+ AlignCompound: false
+ AlignFunctionPointers: false
+ PadOperators: true
+AlignConsecutiveBitFields:
+ Enabled: false
+ AcrossEmptyLines: false
+ AcrossComments: false
+ AlignCompound: false
+ AlignFunctionPointers: false
+ PadOperators: false
+AlignConsecutiveDeclarations:
+ Enabled: false
+ AcrossEmptyLines: false
+ AcrossComments: false
+ AlignCompound: false
+ AlignFunctionPointers: false
+ PadOperators: false
+AlignConsecutiveMacros:
+ Enabled: false
+ AcrossEmptyLines: false
+ AcrossComments: false
+ AlignCompound: false
+ AlignFunctionPointers: false
+ PadOperators: false
+AlignConsecutiveShortCaseStatements:
+ Enabled: false
+ AcrossEmptyLines: false
+ AcrossComments: false
+ AlignCaseColons: false
+AlignEscapedNewlines: Right
+AlignOperands: Align
+AlignTrailingComments:
+ Kind: Always
+ OverEmptyLines: 0
+AllowAllArgumentsOnNextLine: true
+AllowAllParametersOfDeclarationOnNextLine: false
+AllowBreakBeforeNoexceptSpecifier: Never
+AllowShortBlocksOnASingleLine: Never
+AllowShortCaseLabelsOnASingleLine: false
+AllowShortCompoundRequirementOnASingleLine: true
+AllowShortEnumsOnASingleLine: true
+AllowShortFunctionsOnASingleLine: Inline
+AllowShortIfStatementsOnASingleLine: Never
+AllowShortLambdasOnASingleLine: All
+AllowShortLoopsOnASingleLine: false
+AlwaysBreakAfterDefinitionReturnType: TopLevel
+AlwaysBreakAfterReturnType: TopLevel
+AlwaysBreakBeforeMultilineStrings: false
+AlwaysBreakTemplateDeclarations: Yes
+AttributeMacros:
+ - __capability
+BinPackArguments: false
+BinPackParameters: false
+BitFieldColonSpacing: Both
+BraceWrapping:
+ AfterCaseLabel: false
+ AfterClass: true
+ AfterControlStatement: Never
+ AfterEnum: true
+ AfterExternBlock: true
+ AfterFunction: true
+ AfterNamespace: false
+ AfterObjCDeclaration: false
+ AfterStruct: true
+ AfterUnion: true
+ BeforeCatch: false
+ BeforeElse: false
+ BeforeLambdaBody: false
+ BeforeWhile: false
+ IndentBraces: false
+ SplitEmptyFunction: true
+ SplitEmptyRecord: false
+ SplitEmptyNamespace: true
+BreakAdjacentStringLiterals: true
+BreakAfterAttributes: Leave
+BreakAfterJavaFieldAnnotations: false
+BreakArrays: true
+BreakBeforeBinaryOperators: None
+BreakBeforeConceptDeclarations: Always
+BreakBeforeBraces: Mozilla
+BreakBeforeInlineASMColon: OnlyMultiline
+BreakBeforeTernaryOperators: true
+BreakConstructorInitializers: BeforeComma
+BreakInheritanceList: BeforeComma
+BreakStringLiterals: true
+ColumnLimit: 80
+CommentPragmas: '^ IWYU pragma:'
+CompactNamespaces: false
+ConstructorInitializerIndentWidth: 2
+ContinuationIndentWidth: 2
+Cpp11BracedListStyle: false
+DerivePointerAlignment: false
+DisableFormat: false
+EmptyLineAfterAccessModifier: Never
+EmptyLineBeforeAccessModifier: LogicalBlock
+ExperimentalAutoDetectBinPacking: false
+FixNamespaceComments: false
+ForEachMacros:
+ - foreach
+ - Q_FOREACH
+ - BOOST_FOREACH
+IfMacros:
+ - KJ_IF_MAYBE
+IncludeBlocks: Preserve
+IncludeCategories:
+ - Regex: '^"(llvm|llvm-c|clang|clang-c)/'
+ Priority: 2
+ SortPriority: 0
+ CaseSensitive: false
+ - Regex: '^(<|"(gtest|gmock|isl|json)/)'
+ Priority: 3
+ SortPriority: 0
+ CaseSensitive: false
+ - Regex: '.*'
+ Priority: 1
+ SortPriority: 0
+ CaseSensitive: false
+IncludeIsMainRegex: '(Test)?$'
+IncludeIsMainSourceRegex: ''
+IndentAccessModifiers: false
+IndentCaseBlocks: false
+IndentCaseLabels: true
+IndentExternBlock: AfterExternBlock
+IndentGotoLabels: true
+IndentPPDirectives: None
+IndentRequiresClause: true
+IndentWidth: 4
+IndentWrappedFunctionNames: false
+InsertBraces: false
+InsertNewlineAtEOF: false
+InsertTrailingCommas: None
+IntegerLiteralSeparator:
+ Binary: 0
+ BinaryMinDigits: 0
+ Decimal: 0
+ DecimalMinDigits: 0
+ Hex: 0
+ HexMinDigits: 0
+JavaScriptQuotes: Leave
+JavaScriptWrapImports: true
+KeepEmptyLinesAtTheStartOfBlocks: true
+KeepEmptyLinesAtEOF: false
+LambdaBodyIndentation: Signature
+LineEnding: DeriveLF
+MacroBlockBegin: ''
+MacroBlockEnd: ''
+MaxEmptyLinesToKeep: 1
+NamespaceIndentation: None
+ObjCBinPackProtocolList: Auto
+ObjCBlockIndentWidth: 2
+ObjCBreakBeforeNestedBlockParam: true
+ObjCSpaceAfterProperty: true
+ObjCSpaceBeforeProtocolList: false
+PackConstructorInitializers: BinPack
+PenaltyBreakAssignment: 2
+PenaltyBreakBeforeFirstCallParameter: 19
+PenaltyBreakComment: 300
+PenaltyBreakFirstLessLess: 120
+PenaltyBreakOpenParenthesis: 0
+PenaltyBreakScopeResolution: 500
+PenaltyBreakString: 1000
+PenaltyBreakTemplateDeclaration: 10
+PenaltyExcessCharacter: 1000000
+PenaltyIndentedWhitespace: 0
+PenaltyReturnTypeOnItsOwnLine: 200
+PointerAlignment: Left
+PPIndentWidth: -1
+QualifierAlignment: Leave
+ReferenceAlignment: Pointer
+ReflowComments: true
+RemoveBracesLLVM: false
+RemoveParentheses: Leave
+RemoveSemicolon: false
+RequiresClausePosition: OwnLine
+RequiresExpressionIndentation: OuterScope
+SeparateDefinitionBlocks: Leave
+ShortNamespaceLines: 1
+SkipMacroDefinitionBody: false
+SortIncludes: CaseSensitive
+SortJavaStaticImport: Before
+SortUsingDeclarations: LexicographicNumeric
+SpaceAfterCStyleCast: false
+SpaceAfterLogicalNot: false
+SpaceAfterTemplateKeyword: false
+SpaceAroundPointerQualifiers: Default
+SpaceBeforeAssignmentOperators: true
+SpaceBeforeCaseColon: false
+SpaceBeforeCpp11BracedList: false
+SpaceBeforeCtorInitializerColon: true
+SpaceBeforeInheritanceColon: true
+SpaceBeforeJsonColon: false
+SpaceBeforeParens: ControlStatements
+SpaceBeforeParensOptions:
+ AfterControlStatements: true
+ AfterForeachMacros: true
+ AfterFunctionDefinitionName: false
+ AfterFunctionDeclarationName: false
+ AfterIfMacros: true
+ AfterOverloadedOperator: false
+ AfterPlacementOperator: true
+ AfterRequiresInClause: false
+ AfterRequiresInExpression: false
+ BeforeNonEmptyParentheses: false
+SpaceBeforeRangeBasedForLoopColon: true
+SpaceBeforeSquareBrackets: false
+SpaceInEmptyBlock: false
+SpacesBeforeTrailingComments: 1
+SpacesInAngles: Never
+SpacesInContainerLiterals: true
+SpacesInLineCommentPrefix:
+ Minimum: 1
+ Maximum: -1
+SpacesInParens: Never
+SpacesInParensOptions:
+ InCStyleCasts: false
+ InConditionalStatements: false
+ InEmptyParentheses: false
+ Other: false
+SpacesInSquareBrackets: false
+Standard: Latest
+StatementAttributeLikeMacros:
+ - Q_EMIT
+StatementMacros:
+ - Q_UNUSED
+ - QT_REQUIRE_VERSION
+TabWidth: 8
+UseTab: Never
+VerilogBreakBetweenInstancePorts: true
+WhitespaceSensitiveMacros:
+ - BOOST_PP_STRINGIZE
+ - CF_SWIFT_NAME
+ - NS_SWIFT_NAME
+ - PP_STRINGIZE
+ - STRINGIZE
+...
+
diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 0000000..9985e7a
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,13 @@
+root = true
+
+[*]
+end_of_line = lf
+insert_final_newline = true
+
+[*.{c,h}]
+charset = utf-8
+indent_style = space
+indent_size = 4
+
+[Makefile]
+indent_style = tab
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..a705701
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,20 @@
+obe
+*.o
+*.info
+*.swp
+.deps
+aclocal.m4
+autom4te.cache
+build
+compile
+config.guess
+config.h.in
+config.sub
+configure
+configure~
+depcomp
+install-sh
+test-driver
+texinfo.tex
+Makefile.in
+missing
diff --git a/AUTHORS b/AUTHORS
new file mode 100644
index 0000000..daeb816
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1 @@
+Johnny Richard <johnny@johnnyrichard.com> - original author, maintainer
diff --git a/CODE_OF_CONDUCT b/CODE_OF_CONDUCT
new file mode 100644
index 0000000..cd834c1
--- /dev/null
+++ b/CODE_OF_CONDUCT
@@ -0,0 +1,182 @@
+Contributor Covenant 3.0 Code of Conduct
+========================================
+
+OUR PLEDGE
+----------
+
+We pledge to make our community welcoming, safe, and equitable for all.
+
+We are committed to fostering an environment that respects and promotes the
+dignity, rights, and contributions of all individuals, regardless of
+characteristics including race, ethnicity, caste, color, age, physical
+characteristics, neurodiversity, disability, sex or gender, gender identity or
+expression, sexual orientation, language, philosophy or religion, national or
+social origin, socio-economic position, level of education, or other status.
+The same privileges of participation are extended to everyone who participates
+in good faith and in accordance with this Covenant.
+
+ENCOURAGED BEHAVIORS
+--------------------
+
+While acknowledging differences in social norms, we all strive to meet our
+community’s expectations for positive behavior. We also understand that our
+words and actions may be interpreted differently than we intend based on
+culture, background, or native language.
+
+With these considerations in mind, we agree to behave mindfully toward each
+other and act in ways that center our shared values, including:
+
+* Respecting the purpose of our community, our activities, and our ways of gathering.
+* Engaging kindly and honestly with others.
+* Respecting different viewpoints and experiences.
+* Taking responsibility for our actions and contributions.
+* Gracefully giving and accepting constructive feedback.
+* Committing to repairing harm when it occurs.
+* Behaving in other ways that promote and sustain the well-being of our community.
+
+RESTRICTED BEHAVIORS
+--------------------
+
+We agree to restrict the following behaviors in our community. Instances,
+threats, and promotion of these behaviors are violations of this Code of
+Conduct.
+
+* Harassment. Violating explicitly expressed boundaries or engaging in
+ unnecessary personal attention after any clear request to stop.
+* Character attacks. Making insulting, demeaning, or pejorative comments
+ directed at a community member or group of people.
+* Stereotyping or discrimination. Characterizing anyone’s personality or
+ behavior on the basis of immutable identities or traits.
+* Sexualization. Behaving in a way that would generally be considered
+ inappropriately intimate in the context or purpose of the community.
+* Violating confidentiality. Sharing or acting on someone’s personal or private
+ information without their permission.
+* Endangerment. Causing, encouraging, or threatening violence or other harm
+ toward any person or group.
+* Behaving in other ways that threaten the well-being of our community.
+
+OTHER RESTRICTIONS
+------------------
+
+* Misleading identity. Impersonating someone else for any reason, or pretending
+ to be someone else to evade enforcement actions.
+* Failing to credit sources. Not properly crediting the sources of content you
+ contribute.
+* Promotional materials. Sharing marketing or other commercial content in a way
+ that is outside the norms of the community.
+* Irresponsible communication. Failing to responsibly present content which
+ includes, links or describes any other restricted behaviors.
+
+REPORTING AN ISSUE
+------------------
+
+Tensions can occur between community members even when they are trying their
+best to collaborate. Not every conflict represents a code of conduct violation,
+and this Code of Conduct reinforces encouraged behaviors and norms that can
+help avoid conflicts and minimize harm.
+
+When an incident does occur, it is important to report it promptly. To report a
+possible violation, send a plain text email to public@johnnyrichard.com
+
+Community Moderators take reports of violations seriously and will make every
+effort to respond in a timely manner. They will investigate all reports of code
+of conduct violations, reviewing messages, logs, and recordings, or
+interviewing witnesses and other participants. Community Moderators will keep
+investigation and enforcement actions as transparent as possible while
+prioritizing safety and confidentiality. In order to honor these values,
+enforcement actions are carried out in private with the involved parties, but
+communicating to the whole community may be part of a mutually agreed upon
+resolution.
+
+ADDRESSING AND REPAIRING HARM
+-----------------------------
+
+If an investigation by the Community Moderators finds that this Code of Conduct
+has been violated, the following enforcement ladder may be used to determine
+how best to repair harm, based on the incident’s impact on the individuals
+involved and the community as a whole. Depending on the severity of a
+violation, lower rungs on the ladder may be skipped.
+
+* Warning
+
+ * Event: A violation involving a single incident or series of incidents.
+
+ * Consequence: A private, written warning from the Community Moderators.
+
+ * Repair: Examples of repair include a private written apology,
+ acknowledgement of responsibility, and seeking clarification on
+ expectations.
+
+* Temporarily Limited Activities
+
+ * Event: A repeated incidence of a violation that previously resulted in a
+ warning, or the first incidence of a more serious violation.
+
+ * Consequence: A private, written warning with a time-limited cooldown
+ period designed to underscore the seriousness of the situation and give
+ the community members involved time to process the incident. The cooldown
+ period may be limited to particular communication channels or
+ interactions with particular community members.
+
+ * Repair: Examples of repair may include making an apology, using the
+ cooldown period to reflect on actions and impact, and being thoughtful
+ about re-entering community spaces after the period is over.
+
+* Temporary Suspension
+
+ * Event: A pattern of repeated violation which the Community Moderators
+ have tried to address with warnings, or a single serious violation.
+
+ * Consequence: A private written warning with conditions for return from
+ suspension. In general, temporary suspensions give the person being
+ suspended time to reflect upon their behavior and possible corrective
+ actions.
+
+ * Repair: Examples of repair include respecting the spirit of the
+ suspension, meeting the specified conditions for return, and being
+ thoughtful about how to reintegrate with the community when the
+ suspension is lifted.
+
+* Permanent Ban
+
+ * Event: A pattern of repeated code of conduct violations that other steps
+ on the ladder have failed to resolve, or a violation so serious that the
+ Community Moderators determine there is no way to keep the community safe
+ with this person as a member.
+
+ * Consequence: Access to all community spaces, tools, and communication
+ channels is removed. In general, permanent bans should be rarely used,
+ should have strong reasoning behind them, and should only be resorted to
+ if working through other remedies has failed to change the behavior.
+
+ * Repair: There is no possible repair in cases of this severity.
+
+This enforcement ladder is intended as a guideline. It does not limit the
+ability of Community Managers to use their discretion and judgment, in keeping
+with the best interests of our community.
+
+SCOPE
+-----
+
+This Code of Conduct applies within all community spaces, and also applies when
+an individual is officially representing the community in public or other
+spaces. Examples of representing our community include using an official email
+address, posting via an official social media account, or acting as an
+appointed representative at an online or offline event.
+
+ATTRIBUTION
+-----------
+
+This Code of Conduct is adapted from the Contributor Covenant, version 3.0,
+permanently available at https://www.contributor-covenant.org/version/3/0/.
+
+Contributor Covenant is stewarded by the Organization for Ethical Source and
+licensed under CC BY-SA 4.0. To view a copy of this license, visit
+https://creativecommons.org/licenses/by-sa/4.0/
+
+For answers to common questions about Contributor Covenant, see the FAQ at
+https://www.contributor-covenant.org/faq. Translations are provided at
+https://www.contributor-covenant.org/translations. Additional enforcement and
+community guideline resources can be found at
+https://www.contributor-covenant.org/resources. The enforcement ladder was
+inspired by the work of Mozilla’s code of conduct team.
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..f288702
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,674 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+ The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works. By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users. We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors. You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+ To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights. Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received. You must make sure that they, too, receive
+or can get the source code. And you must show them these terms so they
+know their rights.
+
+ Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+ For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software. For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+ Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so. This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software. The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable. Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products. If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+ Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary. To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ TERMS AND CONDITIONS
+
+ 0. Definitions.
+
+ "This License" refers to version 3 of the GNU General Public License.
+
+ "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+ "The Program" refers to any copyrightable work licensed under this
+License. Each licensee is addressed as "you". "Licensees" and
+"recipients" may be individuals or organizations.
+
+ To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy. The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+ A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+ To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy. Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+ To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies. Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+ An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License. If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+ 1. Source Code.
+
+ The "source code" for a work means the preferred form of the work
+for making modifications to it. "Object code" means any non-source
+form of a work.
+
+ A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+ The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form. A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+ The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities. However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work. For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+ The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+ The Corresponding Source for a work in source code form is that
+same work.
+
+ 2. Basic Permissions.
+
+ All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met. This License explicitly affirms your unlimited
+permission to run the unmodified Program. The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work. This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+ You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force. You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright. Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+ Conveying under any other circumstances is permitted solely under
+the conditions stated below. Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+ No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+ When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+ 4. Conveying Verbatim Copies.
+
+ You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+ You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+ 5. Conveying Modified Source Versions.
+
+ You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+ a) The work must carry prominent notices stating that you modified
+ it, and giving a relevant date.
+
+ b) The work must carry prominent notices stating that it is
+ released under this License and any conditions added under section
+ 7. This requirement modifies the requirement in section 4 to
+ "keep intact all notices".
+
+ c) You must license the entire work, as a whole, under this
+ License to anyone who comes into possession of a copy. This
+ License will therefore apply, along with any applicable section 7
+ additional terms, to the whole of the work, and all its parts,
+ regardless of how they are packaged. This License gives no
+ permission to license the work in any other way, but it does not
+ invalidate such permission if you have separately received it.
+
+ d) If the work has interactive user interfaces, each must display
+ Appropriate Legal Notices; however, if the Program has interactive
+ interfaces that do not display Appropriate Legal Notices, your
+ work need not make them do so.
+
+ A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit. Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+ 6. Conveying Non-Source Forms.
+
+ You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+ a) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by the
+ Corresponding Source fixed on a durable physical medium
+ customarily used for software interchange.
+
+ b) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by a
+ written offer, valid for at least three years and valid for as
+ long as you offer spare parts or customer support for that product
+ model, to give anyone who possesses the object code either (1) a
+ copy of the Corresponding Source for all the software in the
+ product that is covered by this License, on a durable physical
+ medium customarily used for software interchange, for a price no
+ more than your reasonable cost of physically performing this
+ conveying of source, or (2) access to copy the
+ Corresponding Source from a network server at no charge.
+
+ c) Convey individual copies of the object code with a copy of the
+ written offer to provide the Corresponding Source. This
+ alternative is allowed only occasionally and noncommercially, and
+ only if you received the object code with such an offer, in accord
+ with subsection 6b.
+
+ d) Convey the object code by offering access from a designated
+ place (gratis or for a charge), and offer equivalent access to the
+ Corresponding Source in the same way through the same place at no
+ further charge. You need not require recipients to copy the
+ Corresponding Source along with the object code. If the place to
+ copy the object code is a network server, the Corresponding Source
+ may be on a different server (operated by you or a third party)
+ that supports equivalent copying facilities, provided you maintain
+ clear directions next to the object code saying where to find the
+ Corresponding Source. Regardless of what server hosts the
+ Corresponding Source, you remain obligated to ensure that it is
+ available for as long as needed to satisfy these requirements.
+
+ e) Convey the object code using peer-to-peer transmission, provided
+ you inform other peers where the object code and Corresponding
+ Source of the work are being offered to the general public at no
+ charge under subsection 6d.
+
+ A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+ A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling. In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage. For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product. A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+ "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source. The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+ If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information. But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+ The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed. Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+ Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+ 7. Additional Terms.
+
+ "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law. If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+ When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it. (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.) You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+ Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+ a) Disclaiming warranty or limiting liability differently from the
+ terms of sections 15 and 16 of this License; or
+
+ b) Requiring preservation of specified reasonable legal notices or
+ author attributions in that material or in the Appropriate Legal
+ Notices displayed by works containing it; or
+
+ c) Prohibiting misrepresentation of the origin of that material, or
+ requiring that modified versions of such material be marked in
+ reasonable ways as different from the original version; or
+
+ d) Limiting the use for publicity purposes of names of licensors or
+ authors of the material; or
+
+ e) Declining to grant rights under trademark law for use of some
+ trade names, trademarks, or service marks; or
+
+ f) Requiring indemnification of licensors and authors of that
+ material by anyone who conveys the material (or modified versions of
+ it) with contractual assumptions of liability to the recipient, for
+ any liability that these contractual assumptions directly impose on
+ those licensors and authors.
+
+ All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10. If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term. If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+ If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+ Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+ 8. Termination.
+
+ You may not propagate or modify a covered work except as expressly
+provided under this License. Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+ However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+ Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+ Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License. If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+ 9. Acceptance Not Required for Having Copies.
+
+ You are not required to accept this License in order to receive or
+run a copy of the Program. Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance. However,
+nothing other than this License grants you permission to propagate or
+modify any covered work. These actions infringe copyright if you do
+not accept this License. Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+ 10. Automatic Licensing of Downstream Recipients.
+
+ Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License. You are not responsible
+for enforcing compliance by third parties with this License.
+
+ An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations. If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+ You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License. For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+ 11. Patents.
+
+ A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based. The
+work thus licensed is called the contributor's "contributor version".
+
+ A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version. For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+ In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement). To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+ If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients. "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+ If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+ A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License. You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+ Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+ 12. No Surrender of Others' Freedom.
+
+ If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all. For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+ 13. Use with the GNU Affero General Public License.
+
+ Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work. The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+ 14. Revised Versions of this License.
+
+ The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation. If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+ If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+ Later license versions may give you additional or different
+permissions. However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+ 15. Disclaimer of Warranty.
+
+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. Limitation of Liability.
+
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+ 17. Interpretation of Sections 15 and 16.
+
+ If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+ If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+ <program> Copyright (C) <year> <name of author>
+ This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+ You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+<https://www.gnu.org/licenses/>.
+
+ The GNU General Public License does not permit incorporating your program
+into proprietary programs. If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License. But first, please read
+<https://www.gnu.org/licenses/why-not-lgpl.html>.
diff --git a/COPYING.LESSER b/COPYING.LESSER
new file mode 100644
index 0000000..0a04128
--- /dev/null
+++ b/COPYING.LESSER
@@ -0,0 +1,165 @@
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+
+ This version of the GNU Lesser General Public License incorporates
+the terms and conditions of version 3 of the GNU General Public
+License, supplemented by the additional permissions listed below.
+
+ 0. Additional Definitions.
+
+ As used herein, "this License" refers to version 3 of the GNU Lesser
+General Public License, and the "GNU GPL" refers to version 3 of the GNU
+General Public License.
+
+ "The Library" refers to a covered work governed by this License,
+other than an Application or a Combined Work as defined below.
+
+ An "Application" is any work that makes use of an interface provided
+by the Library, but which is not otherwise based on the Library.
+Defining a subclass of a class defined by the Library is deemed a mode
+of using an interface provided by the Library.
+
+ A "Combined Work" is a work produced by combining or linking an
+Application with the Library. The particular version of the Library
+with which the Combined Work was made is also called the "Linked
+Version".
+
+ The "Minimal Corresponding Source" for a Combined Work means the
+Corresponding Source for the Combined Work, excluding any source code
+for portions of the Combined Work that, considered in isolation, are
+based on the Application, and not on the Linked Version.
+
+ The "Corresponding Application Code" for a Combined Work means the
+object code and/or source code for the Application, including any data
+and utility programs needed for reproducing the Combined Work from the
+Application, but excluding the System Libraries of the Combined Work.
+
+ 1. Exception to Section 3 of the GNU GPL.
+
+ You may convey a covered work under sections 3 and 4 of this License
+without being bound by section 3 of the GNU GPL.
+
+ 2. Conveying Modified Versions.
+
+ If you modify a copy of the Library, and, in your modifications, a
+facility refers to a function or data to be supplied by an Application
+that uses the facility (other than as an argument passed when the
+facility is invoked), then you may convey a copy of the modified
+version:
+
+ a) under this License, provided that you make a good faith effort to
+ ensure that, in the event an Application does not supply the
+ function or data, the facility still operates, and performs
+ whatever part of its purpose remains meaningful, or
+
+ b) under the GNU GPL, with none of the additional permissions of
+ this License applicable to that copy.
+
+ 3. Object Code Incorporating Material from Library Header Files.
+
+ The object code form of an Application may incorporate material from
+a header file that is part of the Library. You may convey such object
+code under terms of your choice, provided that, if the incorporated
+material is not limited to numerical parameters, data structure
+layouts and accessors, or small macros, inline functions and templates
+(ten or fewer lines in length), you do both of the following:
+
+ a) Give prominent notice with each copy of the object code that the
+ Library is used in it and that the Library and its use are
+ covered by this License.
+
+ b) Accompany the object code with a copy of the GNU GPL and this license
+ document.
+
+ 4. Combined Works.
+
+ You may convey a Combined Work under terms of your choice that,
+taken together, effectively do not restrict modification of the
+portions of the Library contained in the Combined Work and reverse
+engineering for debugging such modifications, if you also do each of
+the following:
+
+ a) Give prominent notice with each copy of the Combined Work that
+ the Library is used in it and that the Library and its use are
+ covered by this License.
+
+ b) Accompany the Combined Work with a copy of the GNU GPL and this license
+ document.
+
+ c) For a Combined Work that displays copyright notices during
+ execution, include the copyright notice for the Library among
+ these notices, as well as a reference directing the user to the
+ copies of the GNU GPL and this license document.
+
+ d) Do one of the following:
+
+ 0) Convey the Minimal Corresponding Source under the terms of this
+ License, and the Corresponding Application Code in a form
+ suitable for, and under terms that permit, the user to
+ recombine or relink the Application with a modified version of
+ the Linked Version to produce a modified Combined Work, in the
+ manner specified by section 6 of the GNU GPL for conveying
+ Corresponding Source.
+
+ 1) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (a) uses at run time
+ a copy of the Library already present on the user's computer
+ system, and (b) will operate properly with a modified version
+ of the Library that is interface-compatible with the Linked
+ Version.
+
+ e) Provide Installation Information, but only if you would otherwise
+ be required to provide such information under section 6 of the
+ GNU GPL, and only to the extent that such information is
+ necessary to install and execute a modified version of the
+ Combined Work produced by recombining or relinking the
+ Application with a modified version of the Linked Version. (If
+ you use option 4d0, the Installation Information must accompany
+ the Minimal Corresponding Source and Corresponding Application
+ Code. If you use option 4d1, you must provide the Installation
+ Information in the manner specified by section 6 of the GNU GPL
+ for conveying Corresponding Source.)
+
+ 5. Combined Libraries.
+
+ You may place library facilities that are a work based on the
+Library side by side in a single library together with other library
+facilities that are not Applications and are not covered by this
+License, and convey such a combined library under terms of your
+choice, if you do both of the following:
+
+ a) Accompany the combined library with a copy of the same work based
+ on the Library, uncombined with any other library facilities,
+ conveyed under the terms of this License.
+
+ b) Give prominent notice with the combined library that part of it
+ is a work based on the Library, and explaining where to find the
+ accompanying uncombined form of the same work.
+
+ 6. Revised Versions of the GNU Lesser General Public License.
+
+ The Free Software Foundation may publish revised and/or new versions
+of the GNU Lesser General Public License from time to time. Such new
+versions will be similar in spirit to the present version, but may
+differ in detail to address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Library as you received it specifies that a certain numbered version
+of the GNU Lesser General Public License "or any later version"
+applies to it, you have the option of following the terms and
+conditions either of that published version or of any later version
+published by the Free Software Foundation. If the Library as you
+received it does not specify a version number of the GNU Lesser
+General Public License, you may choose any version of the GNU Lesser
+General Public License ever published by the Free Software Foundation.
+
+ If the Library as you received it specifies that a proxy can decide
+whether future versions of the GNU Lesser General Public License shall
+apply, that proxy's public statement of acceptance of any version is
+permanent authorization for you to choose that version for the
+Library.
diff --git a/INSTALL b/INSTALL
new file mode 100644
index 0000000..d3b6e4e
--- /dev/null
+++ b/INSTALL
@@ -0,0 +1,365 @@
+Installation Instructions
+*************************
+
+Basic Installation
+==================
+
+ The following shell commands:
+
+ test -f configure || ./bootstrap
+ ./configure
+ make
+ make install
+
+should configure, build, and install this package. The first line,
+which bootstraps, is intended for developers; when building from
+distribution tarballs it does nothing and can be skipped.
+
+ The following more-detailed instructions are generic; see the
+‘README’ file for instructions specific to this package. Some packages
+provide this ‘INSTALL’ file but do not implement all of the features
+documented below. The lack of an optional feature in a given package is
+not necessarily a bug. More recommendations for GNU packages can be
+found in the GNU Coding Standards.
+
+ Many packages have scripts meant for developers instead of ordinary
+builders, as they may use developer tools that are less commonly
+installed, or they may access the network, which has privacy
+implications. If the ‘bootstrap’ shell script exists, it attempts to
+build the ‘configure’ shell script and related files, possibly using
+developer tools or the network. Because the output of ‘bootstrap’ is
+system-independent, it is normally run by a package developer so that
+its output can be put into the distribution tarball and ordinary
+builders and users need not run ‘bootstrap’. Some packages have
+commands like ‘./autopull.sh’ and ‘./autogen.sh’ that you can run
+instead of ‘./bootstrap’, for more fine-grained control over
+bootstrapping.
+
+ The ‘configure’ shell script attempts to guess correct values for
+various system-dependent variables used during compilation. It uses
+those values to create a ‘Makefile’ in each directory of the package.
+It may also create one or more ‘.h’ files containing system-dependent
+definitions. Finally, it creates a shell script ‘config.status’ that
+you can run in the future to recreate the current configuration, and a
+file ‘config.log’ containing output useful for debugging ‘configure’.
+
+ It can also use an optional file (typically called ‘config.cache’ and
+enabled with ‘--cache-file=config.cache’ or simply ‘-C’) that saves the
+results of its tests to speed up reconfiguring. Caching is disabled by
+default to prevent problems with accidental use of stale cache files.
+
+ If you need to do unusual things to compile the package, please try
+to figure out how ‘configure’ could check whether to do them, and mail
+diffs or instructions to the address given in the ‘README’ so they can
+be considered for the next release. If you are using the cache, and at
+some point ‘config.cache’ contains results you don’t want to keep, you
+may remove or edit it.
+
+ The ‘autoconf’ program generates ‘configure’ from the file
+‘configure.ac’. Normally you should edit ‘configure.ac’ instead of
+editing ‘configure’ directly.
+
+ The simplest way to compile this package is:
+
+ 1. ‘cd’ to the directory containing the package’s source code.
+
+ 2. If this is a developer checkout and file ‘configure’ does not yet
+ exist, type ‘./bootstrap’ to create it. You may need special
+ developer tools and network access to bootstrap, and the network
+ access may have privacy implications.
+
+ 3. Type ‘./configure’ to configure the package for your system. This
+ might take a while. While running, ‘configure’ prints messages
+ telling which features it is checking for.
+
+ 4. Type ‘make’ to compile the package.
+
+ 5. Optionally, type ‘make check’ to run any self-tests that come with
+ the package, generally using the just-built uninstalled binaries.
+
+ 6. Type ‘make install’ to install the programs and any data files and
+ documentation. When installing into a prefix owned by root, it is
+ recommended that the package be configured and built as a regular
+ user, and only the ‘make install’ phase executed with root
+ privileges.
+
+ 7. Optionally, type ‘make installcheck’ to repeat any self-tests, but
+ this time using the binaries in their final installed location.
+ This target does not install anything. Running this target as a
+ regular user, particularly if the prior ‘make install’ required
+ root privileges, verifies that the installation completed
+ correctly.
+
+ 8. You can remove the program binaries and object files from the
+ source code directory by typing ‘make clean’. To also remove the
+ files that ‘configure’ created (so you can compile the package for
+ a different kind of computer), type ‘make distclean’. There is
+ also a ‘make maintainer-clean’ target, but that is intended mainly
+ for the package’s developers. If you use it, you may have to
+ bootstrap again.
+
+ 9. If the package follows the GNU Coding Standards, you can type ‘make
+ uninstall’ to remove the installed files.
+
+Compilers and Options
+=====================
+
+ Some systems require unusual options for compilation or linking that
+the ‘configure’ script does not know about. Run ‘./configure --help’
+for details on some of the pertinent environment variables.
+
+ You can give ‘configure’ initial values for configuration parameters
+by setting variables in the command line or in the environment. Here is
+an example:
+
+ ./configure CC=gcc CFLAGS=-g LIBS=-lposix
+
+ See “Defining Variables” for more details.
+
+Compiling For Multiple Architectures
+====================================
+
+ You can compile the package for more than one kind of computer at the
+same time, by placing the object files for each system in their own
+directory. To do this, you can use GNU ‘make’. ‘cd’ to the directory
+where you want the object files and executables to go and run the
+‘configure’ script. ‘configure’ automatically checks for the source
+code in the directory that ‘configure’ is in and in ‘..’. This is known
+as a “VPATH” build.
+
+ With a non-GNU ‘make’, it is safer to compile the package for one
+system at a time in the source code directory. After you have installed
+the package for one system, use ‘make distclean’ before reconfiguring
+for another system.
+
+ Some platforms, notably macOS, support “fat” or “universal” binaries,
+where a single binary can execute on different architectures. On these
+platforms you can configure and compile just once, with options specific
+to that platform.
+
+Installation Names
+==================
+
+ By default, ‘make install’ installs the package’s commands under
+‘/usr/local/bin’, include files under ‘/usr/local/include’, etc. You
+can specify an installation prefix other than ‘/usr/local’ by giving
+‘configure’ the option ‘--prefix=PREFIX’, where PREFIX must be an
+absolute file name.
+
+ You can specify separate installation prefixes for
+architecture-specific files and architecture-independent files. If you
+pass the option ‘--exec-prefix=PREFIX’ to ‘configure’, the package uses
+PREFIX as the prefix for installing programs and libraries.
+Documentation and other data files still use the regular prefix.
+
+ In addition, if you use an unusual directory layout you can give
+options like ‘--bindir=DIR’ to specify different values for particular
+kinds of files. Run ‘configure --help’ for a list of the directories
+you can set and what kinds of files go in them. In general, the default
+for these options is expressed in terms of ‘${prefix}’, so that
+specifying just ‘--prefix’ will affect all of the other directory
+specifications that were not explicitly provided.
+
+ The most portable way to affect installation locations is to pass the
+correct locations to ‘configure’; however, many packages provide one or
+both of the following shortcuts of passing variable assignments to the
+‘make install’ command line to change installation locations without
+having to reconfigure or recompile.
+
+ The first method involves providing an override variable for each
+affected directory. For example, ‘make install
+prefix=/alternate/directory’ will choose an alternate location for all
+directory configuration variables that were expressed in terms of
+‘${prefix}’. Any directories that were specified during ‘configure’,
+but not in terms of ‘${prefix}’, must each be overridden at install time
+for the entire installation to be relocated. The approach of makefile
+variable overrides for each directory variable is required by the GNU
+Coding Standards, and ideally causes no recompilation. However, some
+platforms have known limitations with the semantics of shared libraries
+that end up requiring recompilation when using this method, particularly
+noticeable in packages that use GNU Libtool.
+
+ The second method involves providing the ‘DESTDIR’ variable. For
+example, ‘make install DESTDIR=/alternate/directory’ will prepend
+‘/alternate/directory’ before all installation names. The approach of
+‘DESTDIR’ overrides is not required by the GNU Coding Standards, and
+does not work on platforms that have drive letters. On the other hand,
+it does better at avoiding recompilation issues, and works well even
+when some directory options were not specified in terms of ‘${prefix}’
+at ‘configure’ time.
+
+Optional Features
+=================
+
+ If the package supports it, you can cause programs to be installed
+with an extra prefix or suffix on their names by giving ‘configure’ the
+option ‘--program-prefix=PREFIX’ or ‘--program-suffix=SUFFIX’.
+
+ Some packages pay attention to ‘--enable-FEATURE’ and
+‘--disable-FEATURE’ options to ‘configure’, where FEATURE indicates an
+optional part of the package. They may also pay attention to
+‘--with-PACKAGE’ and ‘--without-PACKAGE’ options, where PACKAGE is
+something like ‘gnu-ld’. ‘./configure --help’ should mention the
+‘--enable-...’ and ‘--with-...’ options that the package recognizes.
+
+ Some packages offer the ability to configure how verbose the
+execution of ‘make’ will be. For these packages, running ‘./configure
+--enable-silent-rules’ sets the default to minimal output, which can be
+overridden with ‘make V=1’; while running ‘./configure
+--disable-silent-rules’ sets the default to verbose, which can be
+overridden with ‘make V=0’.
+
+Specifying a System Type
+========================
+
+ By default ‘configure’ builds for the current system. To create
+binaries that can run on a different system type, specify a
+‘--host=TYPE’ option along with compiler variables that specify how to
+generate object code for TYPE. For example, to create binaries intended
+to run on a 64-bit ARM processor:
+
+ ./configure --host=aarch64-linux-gnu \
+ CC=aarch64-linux-gnu-gcc \
+ CXX=aarch64-linux-gnu-g++
+
+If done on a machine that can execute these binaries (e.g., via
+‘qemu-aarch64’, ‘$QEMU_LD_PREFIX’, and Linux’s ‘binfmt_misc’
+capability), the build behaves like a native build. Otherwise it is a
+cross-build: ‘configure’ will make cross-compilation guesses instead of
+running test programs, and ‘make check’ will not work.
+
+ A system type can either be a short name like ‘mingw64’, or a
+canonical name like ‘x86_64-pc-linux-gnu’. Canonical names have the
+form CPU-COMPANY-SYSTEM where SYSTEM is either OS or KERNEL-OS. To
+canonicalize and validate a system type, you can run the command
+‘config.sub’, which is often squirreled away in a subdirectory like
+‘build-aux’. For example:
+
+ $ build-aux/config.sub arm64-linux
+ aarch64-unknown-linux-gnu
+ $ build-aux/config.sub riscv-lnx
+ Invalid configuration 'riscv-lnx': OS 'lnx' not recognized
+
+You can look at the ‘config.sub’ file to see which types are recognized.
+If the file is absent, this package does not need the system type.
+
+ If ‘configure’ fails with the diagnostic “cannot guess build type”.
+‘config.sub’ did not recognize your system’s type. In this case, first
+fetch the newest versions of these files from the GNU config package
+(https://savannah.gnu.org/projects/config). If that fixes things,
+please report it to the maintainers of the package containing
+‘configure’. Otherwise, you can try the configure option ‘--build=TYPE’
+where TYPE comes close to your system type; also, please report the
+problem to <config-patches@gnu.org>.
+
+ For more details about configuring system types, see the Autoconf
+documentation.
+
+Sharing Defaults
+================
+
+ If you want to set default values for ‘configure’ scripts to share,
+you can create a site shell script called ‘config.site’ that gives
+default values for variables like ‘CC’, ‘cache_file’, and ‘prefix’.
+‘configure’ looks for ‘PREFIX/share/config.site’ if it exists, then
+‘PREFIX/etc/config.site’ if it exists. Or, you can set the
+‘CONFIG_SITE’ environment variable to the location of the site script.
+A warning: not all ‘configure’ scripts look for a site script.
+
+Defining Variables
+==================
+
+ Variables not defined in a site shell script can be set in the
+environment passed to ‘configure’. However, some packages may run
+configure again during the build, and the customized values of these
+variables may be lost. In order to avoid this problem, you should set
+them in the ‘configure’ command line, using ‘VAR=value’. For example:
+
+ ./configure CC=/usr/local2/bin/gcc
+
+causes the specified ‘gcc’ to be used as the C compiler (unless it is
+overridden in the site shell script).
+
+Unfortunately, this technique does not work for ‘CONFIG_SHELL’ due to an
+Autoconf limitation. Until the limitation is lifted, you can use this
+workaround:
+
+ CONFIG_SHELL=/bin/bash ./configure CONFIG_SHELL=/bin/bash
+
+‘configure’ Invocation
+======================
+
+ ‘configure’ recognizes the following options to control how it
+operates.
+
+‘--help’
+‘-h’
+ Print a summary of all of the options to ‘configure’, and exit.
+
+‘--help=short’
+‘--help=recursive’
+ Print a summary of the options unique to this package’s
+ ‘configure’, and exit. The ‘short’ variant lists options used only
+ in the top level, while the ‘recursive’ variant lists options also
+ present in any nested packages.
+
+‘--version’
+‘-V’
+ Print the version of Autoconf used to generate the ‘configure’
+ script, and exit.
+
+‘--cache-file=FILE’
+ Enable the cache: use and save the results of the tests in FILE,
+ traditionally ‘config.cache’. FILE defaults to ‘/dev/null’ to
+ disable caching.
+
+‘--config-cache’
+‘-C’
+ Alias for ‘--cache-file=config.cache’.
+
+‘--srcdir=DIR’
+ Look for the package’s source code in directory DIR. Usually
+ ‘configure’ can determine that directory automatically.
+
+‘--prefix=DIR’
+ Use DIR as the installation prefix. See “Installation Names” for
+ more details, including other options available for fine-tuning the
+ installation locations.
+
+‘--host=TYPE’
+ Build binaries for system TYPE. See “Specifying a System Type”.
+
+‘--enable-FEATURE’
+‘--disable-FEATURE’
+ Enable or disable the optional FEATURE. See “Optional Features”.
+
+‘--with-PACKAGE’
+‘--without-PACKAGE’
+ Use or omit PACKAGE when building. See “Optional Features”.
+
+‘--quiet’
+‘--silent’
+‘-q’
+ Do not print messages saying which checks are being made. To
+ suppress all normal output, redirect it to ‘/dev/null’ (any error
+ messages will still be shown).
+
+‘--no-create’
+‘-n’
+ Run the configure checks, but stop before creating any output
+ files.
+
+‘configure’ also recognizes several environment variables, and accepts
+some other, less widely useful, options. Run ‘configure --help’ for
+more details.
+
+Copyright notice
+================
+
+ Copyright © 1994–1996, 1999–2002, 2004–2017, 2020–2024 Free Software
+Foundation, Inc.
+
+ Copying and distribution of this file, with or without modification,
+are permitted in any medium without royalty provided the copyright
+notice and this notice are preserved. This file is offered as-is,
+without warranty of any kind.
diff --git a/Makefile.am b/Makefile.am
new file mode 100644
index 0000000..a65100e
--- /dev/null
+++ b/Makefile.am
@@ -0,0 +1,37 @@
+AM_CPPFLAGS = -I$(top_srcdir)/include
+
+# binaries settings.
+bin_PROGRAMS = obe
+obe_SOURCES = src/obe.c \
+ src/ir.c \
+ src/arena.c \
+ src/array.c \
+ src/utils.c \
+ src/lexer.c \
+ src/parser.c \
+ src/string.c \
+ src/x86_64/codegen.c
+
+info_TEXINFOS = docs/info/obe.texi
+man1_MANS = obe.1
+
+dist_man_MANS = obe.1
+dist_doc_DATA = README
+
+EXTRA_DIST = \
+ include/obe/arena.h \
+ include/obe/array.h \
+ include/obe/ir.h \
+ include/obe/lexer.h \
+ include/obe/parser.h \
+ include/obe/string_view.h \
+ include/obe/utils.h \
+ include/obe/x86_64/codegen.h
+
+CLEANFILES = obe.1
+
+obe.1: $(srcdir)/src/obe.c
+ @-printf " HELP2MAN %s\n" '$@'
+ @-$(HELP2MAN) --output=$@ --name='olang backend' $(builddir)/obe
+
+SUBDIRS = tests
diff --git a/NEWS b/NEWS
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/NEWS
diff --git a/README b/README
new file mode 100644
index 0000000..d78cf99
--- /dev/null
+++ b/README
@@ -0,0 +1,4 @@
+O backend
+=========
+
+The O compiler backend
diff --git a/autogen.sh b/autogen.sh
new file mode 100755
index 0000000..22632ed
--- /dev/null
+++ b/autogen.sh
@@ -0,0 +1,3 @@
+#!/bin/sh
+
+autoreconf -vi
diff --git a/configure.ac b/configure.ac
new file mode 100644
index 0000000..85f2aa8
--- /dev/null
+++ b/configure.ac
@@ -0,0 +1,34 @@
+AC_PREREQ([2.72])
+
+AC_INIT([obe], [0.0.0], [johnny@johnnyrichard.com])
+AM_INIT_AUTOMAKE([-Wall -Werror foreign subdir-objects])
+
+AM_SILENT_RULES([yes])
+
+AC_CONFIG_SRCDIR([src/obe.c])
+AC_CONFIG_HEADERS([config.h])
+
+# Checks for programs.
+AC_PROG_CC
+AC_PATH_PROG(HELP2MAN, help2man, false // no help2man //)
+
+# Checks for libraries.
+PKG_CHECK_MODULES([CHECK], [check >= 0.9.6], [], AC_MSG_ERROR(['check' is required, but not found]))
+
+# Checks for header files.
+AC_CHECK_HEADERS([stdint.h])
+
+# Checks for typedefs, structures, and compiler characteristics.
+AC_CHECK_HEADER_STDBOOL
+AC_C_INLINE
+AC_TYPE_SIZE_T
+AC_TYPE_UINT32_T
+AC_TYPE_UINT8_T
+
+# Checks for library functions.
+AC_FUNC_MALLOC
+AC_CHECK_FUNCS([strerror])
+
+AC_CONFIG_FILES([Makefile
+ tests/Makefile])
+AC_OUTPUT
diff --git a/docs/info/obe.texi b/docs/info/obe.texi
new file mode 100644
index 0000000..558fb80
--- /dev/null
+++ b/docs/info/obe.texi
@@ -0,0 +1,54 @@
+\input texinfo
+
+@setfilename obe.info
+@settitle Obe: compier backend
+
+@copying
+Copyright @copyright{} 2024 olang project.
+
+This is free software; see the source for copying conditions. There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+@end copying
+
+@titlepage
+@title Obe manual
+@page
+@vskip 0pt plus 1filll
+@insertcopying
+@end titlepage
+
+@contents
+
+@node Top
+@top Obe: compiler backend
+
+This manual is for OBE.
+
+@menu
+* First Chapter:: The first chapter.
+@end menu
+
+@node First Chapter
+@chapter First Chapter
+
+Here is a numbered list.
+
+@enumerate
+@item
+This is the first item.
+
+@item
+This is the second item.
+@end enumerate
+
+@node First Section
+@section First Section
+
+First section of first chapter.
+
+@node Second Section
+@section Second Section
+
+Second section of first chapter.
+
+@bye
diff --git a/examples/main.ir b/examples/main.ir
new file mode 100644
index 0000000..e1ef195
--- /dev/null
+++ b/examples/main.ir
@@ -0,0 +1,26 @@
+@main {
+ v0: u8 = 8;
+ value: u8 = v0;
+ v1: u8 = 1;
+ result: u8 = v1;
+ v3: u8 = value;
+ i: u8 = v3;
+.for.cond:
+ v4: u8 = i;
+ v6: bool = v4 > v5;
+ br v6 .for.body .for.end;
+.for.body:
+ v7: u8 = result;
+ v8: u8 = i;
+ v9: u8 = v7 * v8;
+ result: u8 = v9;
+ v10: u8 = i;
+ v11: u8 = 1;
+ v12: u8 = v10 - v11;
+ i: u8 = v12;
+ jmp .for.cond;
+.for.end:
+ v13: u8 = result;
+ pru8 v13;
+ v14: u8 = 0;
+}
diff --git a/include/.gitignore b/include/.gitignore
new file mode 100644
index 0000000..eabc82f
--- /dev/null
+++ b/include/.gitignore
@@ -0,0 +1 @@
+!obe
diff --git a/include/obe/arena.h b/include/obe/arena.h
new file mode 100644
index 0000000..5b3490a
--- /dev/null
+++ b/include/obe/arena.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2025 Johnny Richard <johnny@johnnyrichard.com>
+ *
+ * SPDX-License-Identifier: LGPL-3.0-or-later
+ *
+ * This file is part of obe.
+ *
+ * obe is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free
+ * Software Foundation, either version 3 of the License, or (at your option)
+ * any later version.
+ *
+ * obe is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with obe. If not, see <https://www.gnu.org/licenses/>.
+ */
+#ifndef OBE_ARENA_H
+#define OBE_ARENA_H
+
+#include <stddef.h>
+#include <stdint.h>
+
+#define OBE_ARENA_ALIGMENT_BYTES (16)
+#define OBE_ARENA_ALIGMENT_MASK (OBE_ARENA_ALIGMENT_BYTES - 1)
+#define OBE_ARENA_REGION_DEFAULT_CAPACITY (8 * 1024)
+#define OBE_ARENA_PADDING(bytes) \
+ ((uint8_t)((OBE_ARENA_ALIGMENT_BYTES - bytes) & OBE_ARENA_ALIGMENT_MASK))
+
+typedef struct obe_arena_region obe_arena_region_t;
+
+struct obe_arena_region
+{
+ obe_arena_region_t* next;
+ size_t offset;
+ size_t capacity;
+ uint8_t* data;
+};
+
+typedef struct obe_arena
+{
+ obe_arena_region_t* begin;
+ obe_arena_region_t* end;
+} obe_arena_t;
+
+/* arena */
+
+void*
+obe_arena_alloc(obe_arena_t* arena, size_t size);
+
+void*
+obe_arena_realloc(obe_arena_t* arena,
+ void* old_ptr,
+ size_t old_size,
+ size_t new_size);
+
+void
+obe_arena_release(obe_arena_t* arena);
+
+void
+obe_arena_free(obe_arena_t* arena);
+
+/* region */
+
+obe_arena_region_t*
+obe_arena_region_new(size_t capacity);
+
+void
+obe_arena_region_free(obe_arena_region_t* r);
+
+char*
+obe_arena_strdup(obe_arena_t* arena, char* s);
+
+#endif /* OBE_ARENA_H */
diff --git a/include/obe/array.h b/include/obe/array.h
new file mode 100644
index 0000000..4ef9204
--- /dev/null
+++ b/include/obe/array.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2025 Johnny Richard <johnny@johnnyrichard.com>
+ *
+ * SPDX-License-Identifier: LGPL-3.0-or-later
+ *
+ * This file is part of obe.
+ *
+ * obe is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free
+ * Software Foundation, either version 3 of the License, or (at your option)
+ * any later version.
+ *
+ * obe is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with obe. If not, see <https://www.gnu.org/licenses/>.
+ */
+#ifndef OBE_ARRAY_H
+#define OBE_ARRAY_H
+#include <obe/arena.h>
+#include <stddef.h>
+
+#define OBE_ARRAY_INITIAL_CAPACITY 4
+
+#define obe_array(arena, T) (T*)obe_array_new((arena), sizeof(T))
+
+#define obe_array_append(arr, item) \
+ do { \
+ obe_array_header_t* h = obe_array_get_header(arr); \
+ if (h->capacity < h->length + 1) { \
+ arr = obe_array_grow(arr); \
+ h = obe_array_get_header(arr); \
+ } \
+ arr[h->length++] = item; \
+ } while (0)
+
+typedef struct obe_array_header
+{
+ obe_arena_t* arena;
+ size_t capacity;
+ size_t item_size;
+ size_t length;
+} obe_array_header_t;
+
+void*
+obe_array_new(obe_arena_t* arena, size_t item_size);
+
+obe_array_header_t*
+obe_array_get_header(void* arr);
+
+void*
+obe_array_grow(void* arr);
+
+size_t
+obe_array_length(void* arr);
+
+#endif /* OBE_ARRAY_H */
diff --git a/include/obe/ir.h b/include/obe/ir.h
new file mode 100644
index 0000000..ae6f797
--- /dev/null
+++ b/include/obe/ir.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2025 Johnny Richard <johnny@johnnyrichard.com>
+ *
+ * SPDX-License-Identifier: LGPL-3.0-or-later
+ *
+ * This file is part of obe.
+ *
+ * obe is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free
+ * Software Foundation, either version 3 of the License, or (at your option)
+ * any later version.
+ *
+ * obe is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with obe. If not, see <https://www.gnu.org/licenses/>.
+ */
+#ifndef OBE_IR_H
+#define OBE_IR_H
+
+#include <obe/arena.h>
+#include <obe/string.h>
+
+typedef enum obe_ir_inst_kind
+{
+ OBE_IR_INST_CONST,
+ OBE_IR_INST_PRINT,
+ OBE_IR_INST_RETURN,
+ OBE_IR_INST_BR,
+ OBE_IR_INST_JMP,
+ OBE_IR_INST_LABEL,
+} obe_ir_inst_kind_t;
+
+typedef enum obe_ir_type
+{
+ OBE_IR_TYPE_INT
+} obe_ir_type_t;
+
+typedef enum obe_ir_operand_kind
+{
+ OBE_IR_OPERAND_LITERAL,
+ OBE_IR_OPERAND_IDENT
+} obe_ir_operand_kind_t;
+
+typedef struct obe_ir_operand
+{
+ obe_ir_operand_kind_t kind;
+ char *value;
+} obe_ir_operand_t;
+
+typedef struct obe_ir_inst
+{
+ obe_ir_inst_kind_t kind;
+ obe_ir_type_t type;
+ char* dest;
+ obe_ir_operand_t operand1;
+ obe_ir_operand_t operand2;
+} obe_ir_inst_t;
+
+typedef struct obe_ir_function
+{
+ obe_string_t name;
+ obe_ir_inst_t* instrs;
+} obe_ir_function_t;
+
+typedef struct obe_ir_translation_unit
+{
+ obe_ir_function_t* funcs;
+} obe_ir_translation_unit_t;
+
+obe_ir_translation_unit_t*
+obe_ir_translation_unit_new(obe_arena_t* arena);
+
+obe_ir_function_t*
+obe_ir_function_new(obe_arena_t* arena, obe_string_t name);
+
+#endif /* OBE_IR_H */
diff --git a/include/obe/lexer.h b/include/obe/lexer.h
new file mode 100644
index 0000000..9761aa7
--- /dev/null
+++ b/include/obe/lexer.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2025 Johnny Richard <johnny@johnnyrichard.com>
+ *
+ * SPDX-License-Identifier: LGPL-3.0-or-later
+ *
+ * This file is part of obe.
+ *
+ * obe is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free
+ * Software Foundation, either version 3 of the License, or (at your option)
+ * any later version.
+ *
+ * obe is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with obe. If not, see <https://www.gnu.org/licenses/>.
+ */
+#ifndef OBE_LEXER_H
+#define OBE_LEXER_H
+
+#include <obe/string.h>
+#include <stddef.h>
+
+typedef enum obe_token_kind
+{
+ TOKEN_KW_RETURN,
+ TOKEN_KW_FN,
+ TOKEN_KW_BR,
+ TOKEN_IDENT,
+ TOKEN_LABEL,
+ TOKEN_NUMBER,
+ TOKEN_INT,
+ TOKEN_EQ,
+ TOKEN_COLON,
+ TOKEN_SEMICOLON,
+ TOKEN_LBRACE,
+ TOKEN_RBRACE,
+ TOKEN_EOF,
+ TOKEN_UNKOWN
+} obe_token_kind_t;
+
+typedef struct obe_lexer_loc
+{
+ size_t offset;
+ size_t lineoffset;
+ size_t lineno;
+} obe_lexer_loc_t;
+
+typedef struct obe_token
+{
+ obe_token_kind_t kind;
+ obe_string_t value;
+ obe_lexer_loc_t loc;
+} obe_token_t;
+
+typedef struct obe_lexer
+{
+ char* filename;
+ obe_string_t source;
+ obe_lexer_loc_t loc;
+} obe_lexer_t;
+
+void
+obe_lexer_init(obe_lexer_t* lexer, char* filename);
+
+bool
+obe_lexer_is_eof(obe_lexer_t* lexer);
+
+char
+obe_lexer_current_char(obe_lexer_t* lexer);
+
+char
+obe_lexer_next_char(obe_lexer_t* lexer);
+
+void
+obe_lexer_next_token(obe_lexer_t* lexer, obe_token_t* token);
+
+char*
+obe_token_to_cstr(obe_token_kind_t kind);
+
+#endif /* OBE_LEXER_H */
diff --git a/include/obe/parser.h b/include/obe/parser.h
new file mode 100644
index 0000000..026af5c
--- /dev/null
+++ b/include/obe/parser.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2025 Johnny Richard <johnny@johnnyrichard.com>
+ *
+ * SPDX-License-Identifier: LGPL-3.0-or-later
+ *
+ * This file is part of obe.
+ *
+ * obe is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free
+ * Software Foundation, either version 3 of the License, or (at your option)
+ * any later version.
+ *
+ * obe is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with obe. If not, see <https://www.gnu.org/licenses/>.
+ */
+#ifndef OBE_PARSER_H
+#define OBE_PARSER_H
+
+#include <obe/arena.h>
+#include <obe/ir.h>
+#include <obe/lexer.h>
+
+typedef struct obe_parser
+{
+ obe_arena_t* arena;
+ obe_lexer_t* lexer;
+} obe_parser_t;
+
+void
+obe_parser_init(obe_parser_t* parser, obe_lexer_t* lexer, obe_arena_t* arena);
+
+obe_ir_translation_unit_t*
+obe_parser_parse(obe_parser_t* parser);
+
+#endif /* OBE_PARSER_H */
diff --git a/include/obe/string.h b/include/obe/string.h
new file mode 100644
index 0000000..6194cb2
--- /dev/null
+++ b/include/obe/string.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2025 Johnny Richard <johnny@johnnyrichard.com>
+ *
+ * SPDX-License-Identifier: LGPL-3.0-or-later
+ *
+ * This file is part of obe.
+ *
+ * obe is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free
+ * Software Foundation, either version 3 of the License, or (at your option)
+ * any later version.
+ *
+ * obe is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with obe. If not, see <https://www.gnu.org/licenses/>.
+ */
+#ifndef OBE_STRING_H
+#define OBE_STRING_H
+
+#define PRIs "%.*s"
+#define PRIsARG(s) (int)(s).length, (s).chars
+
+#include <stdbool.h>
+#include <stddef.h>
+
+typedef struct obe_string
+{
+ char* chars;
+ size_t length;
+} obe_string_t;
+
+obe_string_t
+obe_string_from_cstr(char* cstr);
+
+bool
+obe_string_eq(obe_string_t s1, obe_string_t s2);
+
+#endif /* OBE_STRING_H */
diff --git a/include/obe/utils.h b/include/obe/utils.h
new file mode 100644
index 0000000..ef4c1c5
--- /dev/null
+++ b/include/obe/utils.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2025 Johnny Richard <johnny@johnnyrichard.com>
+ *
+ * SPDX-License-Identifier: LGPL-3.0-or-later
+ *
+ * This file is part of obe.
+ *
+ * obe is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free
+ * Software Foundation, either version 3 of the License, or (at your option)
+ * any later version.
+ *
+ * obe is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with obe. If not, see <https://www.gnu.org/licenses/>.
+ */
+#ifndef OBE_UTILS_H
+#define OBE_UTILS_H
+
+char*
+read_file_contents(char* file_path);
+
+#endif /* OBE_UTILS_H */
diff --git a/include/obe/x86_64/codegen.h b/include/obe/x86_64/codegen.h
new file mode 100644
index 0000000..01ad3ff
--- /dev/null
+++ b/include/obe/x86_64/codegen.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2025 Johnny Richard <johnny@johnnyrichard.com>
+ *
+ * SPDX-License-Identifier: LGPL-3.0-or-later
+ *
+ * This file is part of obe.
+ *
+ * obe is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free
+ * Software Foundation, either version 3 of the License, or (at your option)
+ * any later version.
+ *
+ * obe is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with obe. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef OBE_X86_64_CODEGEN_H
+#define OBE_X86_64_CODEGEN_H
+
+#include <obe/ir.h>
+#include <stdio.h>
+
+void
+obe_x86_64_codegen_emit(obe_ir_translation_unit_t* tu, FILE *out);
+
+#endif /* OBE_X86_64_CODEGEN_H */
diff --git a/scripts/docstr2man b/scripts/docstr2man
new file mode 100755
index 0000000..c58c3bd
--- /dev/null
+++ b/scripts/docstr2man
@@ -0,0 +1,241 @@
+#!/bin/python3
+
+# Copyright (C) 2024 olang mantainers
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+import sys
+import re
+from enum import Enum
+
+
+class Field:
+ def __init__(self, kind, name, type, description):
+ self.kind = kind
+ self.name = name
+ self.type = type
+ self.description = description
+
+
+NODE_KIND = Enum('NODE_KIND', ['FUNCTION', 'TYPEDEF_STRUCT', 'TYPEDEF_UNION', 'MACRO'])
+
+class DocString:
+ def __init__(self, comment_lines, code_node):
+ self.comment_lines = comment_lines
+ self.code_node = code_node
+
+ def get_name(self):
+ return self.code_node.get_name()
+
+ def get_title(self):
+ return self.comment_lines[0]
+
+ def get_description(self):
+ description = ""
+ for line in self.comment_lines[2:]:
+ if line.startswith('@'):
+ break
+ elif len(description) > 0 and description[-1] != '\n':
+ description += ' '
+ description += line + '\n'
+ return description.strip()
+
+ def get_fields(self):
+ name = ""
+ description = ""
+
+ fields_map = {}
+
+ for line in self.comment_lines[2:]:
+ if line.startswith('@'):
+ if name:
+ fields_map[name] = description
+ name = line[1:].split(':')[0]
+ description = ":".join(line.split(':')[1:])
+ elif name:
+ description += ' ' + line
+
+ if name:
+ fields_map[name] = description
+
+ for field in self.code_node.get_fields():
+ if field.name in fields_map:
+ field.description = fields_map.get(field.name)
+ yield field
+
+
+class MacroNode:
+ def __init__(self, lines):
+ self.lines = lines
+ self.kind = NODE_KIND.MACRO
+
+ def get_name(self):
+ return self.lines[0].split(' ')[1]
+
+ def get_fields(self):
+ return []
+
+
+class TypedefNode:
+ def __init__(self, lines, kind):
+ self.lines = lines
+ self.kind = kind
+
+ def get_name(self):
+ return self.lines[-1].split(' ')[1].replace(';', '')
+
+ def get_fields(self):
+ description = None
+ for line in self.lines[2:-1]:
+ line = line.strip()
+
+ if line.startswith('/*'):
+ description = line.replace('/* ', '').replace('*/', '')
+ continue
+
+ # FIXME: handle anonymous struct/inline
+ field_name = line.split(' ')[-1].replace(';', '')
+ field_type = ' '.join(line.split(' ')[:-1])
+
+ yield Field('field', field_name, field_type, description)
+ description = None
+ return []
+
+
+class FunctionNode:
+ def __init__(self, lines):
+ self.lines = lines
+ self.kind = NODE_KIND.FUNCTION
+
+ def get_ret_type(self):
+ return self.lines[0]
+
+ def get_name(self):
+ return self.lines[1].split('(')[0]
+
+ def get_fields(self):
+ all_lines = "".join(self.lines)
+ args = all_lines.split('(')[1].split(')')[0].strip()
+
+ for arg in re.finditer("(((?P<arg_type>((struct|union|enum) *)*([\\w]+ *\\**)) *(?P<arg_name>[\\w]+))[, ]*)", args):
+ yield Field('arg', arg.group('arg_name'), arg.group('arg_type').strip(), None)
+
+ yield Field('return', 'return', self.get_ret_type(), None)
+
+
+
+def get_code_node(lines):
+ assert(len(lines) > 0)
+ if lines[0].startswith("#define"):
+ return MacroNode(lines)
+ if lines[0].startswith("typedef union"):
+ return TypedefNode(lines, NODE_KIND.TYPEDEF_UNION)
+ if lines[0].startswith("typedef struct"):
+ return TypedefNode(lines, NODE_KIND.TYPEDEF_STRUCT)
+ if lines[0].startswith("typedef enum"):
+ return TypedefNode(lines, NODE_KIND.TYPEDEF_STRUCT)
+ return FunctionNode(lines)
+
+
+def extract_comment(lines, index):
+ if not lines[index].startswith("/**"):
+ return None, index
+
+ comment_lines = []
+
+ for line in lines[index + 1:]:
+ if line.strip().startswith("*/"):
+ break
+
+ comment_lines.append(line.strip()[2:])
+ index += 1
+
+ return comment_lines, index
+
+
+def extract_code(lines, index):
+ """
+ This is highly tied to olang's code style and require the curly brackets
+ to be open into a new line.
+ """
+ code_lines = []
+ is_block = False
+
+ for line in lines[index + 1:]:
+ code_lines.append(line)
+ if is_block:
+ if len(line) == 0:
+ continue
+
+ if line[0] == '}':
+ break;
+
+ if len(line) == 0:
+ break
+
+ if line[0] == '{':
+ is_block = True
+ index += 1
+
+ return code_lines, index
+
+
+def extract_docstring(file):
+ lines = file.split('\n')
+
+ index = 0
+
+ while index < len(lines):
+ comment_lines, index = extract_comment(lines, index)
+ if comment_lines:
+ index += 1
+ code_lines, index = extract_code(lines, index)
+ yield DocString(comment_lines, get_code_node(code_lines))
+ index += 1
+
+
+def generate_docs(file_name):
+ with open(file_name) as file:
+ for docstring in extract_docstring(file.read()):
+ node = docstring.code_node
+ if node.kind == NODE_KIND.FUNCTION:
+ print(f".TH {docstring.get_name()} 3 {docstring.get_name()} 1988-12-31 \"Olang Hacker's manual\"")
+ print(f".SH NAME")
+ print(f"{docstring.get_name()} \\- {docstring.get_title()}")
+
+ print(f".SH SYNOPSIS")
+
+ print(f".nf")
+ print(f".B #include <{sys.argv[1].replace('include/', '')}>")
+ print(f".P")
+
+ fields = list(node.get_fields())[:-1]
+ paren = f"{node.get_ret_type()} {docstring.get_name()}("
+ paren_len = len(paren)
+ post = ","
+ for index, field in enumerate(fields):
+ if index == len(fields) - 1:
+ post = ");"
+
+ print(f".BI \"{paren}{field.type} \" {field.name} {post}")
+
+ paren = " " * paren_len
+
+ print(f".fi")
+ print(f".SH DESCRIPTION")
+ print(f"{docstring.get_description()}")
+
+
+if __name__ == "__main__":
+ generate_docs(sys.argv[1])
diff --git a/scripts/format b/scripts/format
new file mode 100755
index 0000000..42f7e99
--- /dev/null
+++ b/scripts/format
@@ -0,0 +1,43 @@
+#!/bin/sh
+#
+# Copyright (C) 2024 Johnny Richard <johnny@johnnyrichard.com>
+#
+# SPDX-License-Identifier: LGPL-3.0-or-later
+#
+# This file is part of obe.
+#
+# obe is free software: you can redistribute it and/or modify it under the
+# terms of the GNU Lesser General Public License as published by the Free
+# Software Foundation, either version 3 of the License, or (at your option) any
+# later version.
+#
+# obe is distributed in the hope that it will be useful, but WITHOUT ANY
+# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+# A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+# details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with obe. If not, see <https://www.gnu.org/licenses/>.
+
+opt_fix=0
+
+while getopts 'f' opt
+do
+ case "$opt" in
+ f)
+ opt_fix=1
+ ;;
+ esac
+done
+
+shift $((OPTIND - 1))
+
+
+if test "$opt_fix" -eq 1
+then
+ clang_format_flags="-i"
+else
+ clang_format_flags="--dry-run -Werror"
+fi
+
+find . -type f -name '*.c' -o -name '*.h' | xargs -L1 clang-format $clang_format_flags
diff --git a/src/arena.c b/src/arena.c
new file mode 100644
index 0000000..8822fdd
--- /dev/null
+++ b/src/arena.c
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2025 Johnny Richard <johnny@johnnyrichard.com>
+ *
+ * SPDX-License-Identifier: LGPL-3.0-or-later
+ *
+ * This file is part of obe.
+ *
+ * obe is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free
+ * Software Foundation, either version 3 of the License, or (at your option)
+ * any later version.
+ *
+ * obe is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with obe. If not, see <https://www.gnu.org/licenses/>.
+ */
+#include <assert.h>
+#include <obe/arena.h>
+#include <stdlib.h>
+#include <string.h>
+
+void*
+obe_arena_alloc(obe_arena_t* arena, size_t size)
+{
+ if (arena->end == NULL) {
+ assert(arena->begin == NULL);
+ size_t capacity = OBE_ARENA_REGION_DEFAULT_CAPACITY;
+ if (capacity < OBE_ARENA_PADDING(size))
+ capacity = size + OBE_ARENA_PADDING(size);
+ arena->end = obe_arena_region_new(capacity);
+ arena->begin = arena->end;
+ }
+
+ while (arena->end->offset + size > arena->end->capacity &&
+ arena->end->next != NULL) {
+ arena->end = arena->end->next;
+ }
+
+ if (arena->end->offset + size > arena->end->capacity) {
+ assert(arena->end->next == NULL);
+ size_t capacity = OBE_ARENA_REGION_DEFAULT_CAPACITY;
+ if (capacity < size)
+ capacity = size + OBE_ARENA_PADDING(size);
+ arena->end->next = obe_arena_region_new(capacity);
+ arena->end = arena->end->next;
+ }
+
+ void* ptr = arena->end->data + arena->end->offset;
+ arena->end->offset += size + OBE_ARENA_PADDING(size);
+ return ptr;
+}
+
+void*
+obe_arena_realloc(obe_arena_t* arena,
+ void* old_ptr,
+ size_t old_size,
+ size_t new_size)
+{
+ if (new_size <= old_size)
+ return old_ptr;
+ void* new_ptr = obe_arena_alloc(arena, new_size);
+ return memcpy(new_ptr, old_ptr, old_size);
+}
+
+void
+obe_arena_release(obe_arena_t* arena)
+{
+ for (obe_arena_region_t* r = arena->begin; r != NULL; r = r->next) {
+ r->offset = 0;
+ }
+ arena->end = arena->begin;
+}
+
+void
+obe_arena_free(obe_arena_t* arena)
+{
+ obe_arena_region_t* r = arena->begin;
+ while (r) {
+ obe_arena_region_t* r_tmp = r;
+ r = r->next;
+ obe_arena_region_free(r_tmp);
+ }
+ arena->begin = NULL;
+ arena->end = NULL;
+}
+
+obe_arena_region_t*
+obe_arena_region_new(size_t capacity)
+{
+ size_t size = sizeof(obe_arena_region_t) + sizeof(uint8_t) * capacity;
+ obe_arena_region_t* r = (obe_arena_region_t*)malloc(size);
+ assert(r);
+ r->next = NULL;
+ r->offset = 0;
+ r->capacity = capacity;
+ r->data = (uint8_t*)(r + 1);
+ return r;
+}
+
+void
+obe_arena_region_free(obe_arena_region_t* r)
+{
+ free(r);
+}
+
+char*
+obe_arena_strdup(obe_arena_t* arena, char* s)
+{
+ size_t slen = strlen(s);
+ char* d = obe_arena_alloc(arena, sizeof(char) * (slen + 1));
+ assert(d);
+
+ for (size_t i = 0; i <= slen; ++i)
+ d[i] = s[i];
+
+ return d;
+}
diff --git a/src/array.c b/src/array.c
new file mode 100644
index 0000000..dde3eba
--- /dev/null
+++ b/src/array.c
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2025 Johnny Richard <johnny@johnnyrichard.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+#include <assert.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+#include <obe/arena.h>
+#include <obe/array.h>
+
+void*
+obe_array_new(obe_arena_t* arena, size_t item_size)
+{
+ obe_array_header_t* h = obe_arena_alloc(
+ arena,
+ (item_size * OBE_ARRAY_INITIAL_CAPACITY) + sizeof(obe_array_header_t));
+ if (h == NULL) {
+ return NULL;
+ }
+ h->arena = arena;
+ h->length = 0;
+ h->item_size = item_size;
+ h->capacity = OBE_ARRAY_INITIAL_CAPACITY;
+
+ return ((uint8_t *)h) + sizeof(obe_array_header_t);
+}
+
+obe_array_header_t*
+obe_array_get_header(void* arr)
+{
+ return (obe_array_header_t*)(((uint8_t *)arr) - sizeof(obe_array_header_t));
+}
+
+void*
+obe_array_grow(void* arr)
+{
+ obe_array_header_t* h = obe_array_get_header(arr);
+
+ size_t old_size = sizeof(obe_array_header_t) + (h->capacity * h->item_size);
+ h->capacity *= 2;
+ size_t new_size = sizeof(obe_array_header_t) + (h->capacity * h->item_size);
+
+ h = obe_arena_realloc(h->arena, h, old_size, new_size);
+
+ return ((uint8_t *)h) + sizeof(obe_array_header_t);
+}
+
+size_t
+obe_array_length(void* arr)
+{
+ assert(arr);
+ obe_array_header_t* header = obe_array_get_header(arr);
+ return header->length;
+}
diff --git a/src/ir.c b/src/ir.c
new file mode 100644
index 0000000..2c0b0c9
--- /dev/null
+++ b/src/ir.c
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2025 Johnny Richard <johnny@johnnyrichard.com>
+ *
+ * SPDX-License-Identifier: LGPL-3.0-or-later
+ *
+ * This file is part of obe.
+ *
+ * obe is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free
+ * Software Foundation, either version 3 of the License, or (at your option)
+ * any later version.
+ *
+ * obe is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with obe. If not, see <https://www.gnu.org/licenses/>.
+ */
+#include <assert.h>
+#include <obe/arena.h>
+#include <obe/ir.h>
+#include <obe/array.h>
+
+obe_ir_translation_unit_t*
+obe_ir_translation_unit_new(obe_arena_t* arena)
+{
+ obe_ir_translation_unit_t* tu = obe_arena_alloc(arena, sizeof(obe_ir_translation_unit_t));
+ assert(tu);
+ tu->funcs = obe_array(arena, obe_ir_function_t);
+ return tu;
+}
+
+obe_ir_function_t*
+obe_ir_function_new(obe_arena_t* arena, obe_string_t name)
+{
+ obe_ir_function_t* func = obe_arena_alloc(arena, sizeof(obe_ir_function_t));
+ assert(func);
+ func->name = name;
+ return func;
+}
diff --git a/src/lexer.c b/src/lexer.c
new file mode 100644
index 0000000..3ad8751
--- /dev/null
+++ b/src/lexer.c
@@ -0,0 +1,222 @@
+/*
+ * Copyright (C) 2025 Johnny Richard <johnny@johnnyrichard.com>
+ *
+ * SPDX-License-Identifier: LGPL-3.0-or-later
+ *
+ * This file is part of obe.
+ *
+ * obe is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free
+ * Software Foundation, either version 3 of the License, or (at your option)
+ * any later version.
+ *
+ * obe is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with obe. If not, see <https://www.gnu.org/licenses/>.
+ */
+#include <assert.h>
+#include <ctype.h>
+#include <obe/lexer.h>
+#include <obe/string.h>
+#include <obe/utils.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+void
+obe_lexer_init(obe_lexer_t* lexer, char* filename)
+{
+ assert(lexer);
+
+ char* program = read_file_contents(filename);
+ if (program == NULL) {
+ fprintf(stderr, "Unable to read file contents <%s>\n", filename);
+ exit(EXIT_FAILURE);
+ }
+
+ lexer->filename = filename;
+ lexer->loc = (obe_lexer_loc_t){ 0 };
+ lexer->source = obe_string_from_cstr(program);
+}
+
+bool
+obe_lexer_is_eof(obe_lexer_t* lexer)
+{
+ return !(lexer->loc.offset < lexer->source.length);
+}
+
+char
+obe_lexer_current_char(obe_lexer_t* lexer)
+{
+ return lexer->source.chars[lexer->loc.offset];
+}
+
+char
+obe_lexer_next_char(obe_lexer_t* lexer)
+{
+ assert(lexer->loc.offset < lexer->source.length);
+
+ char previous_char = obe_lexer_current_char(lexer);
+ if (previous_char == '\n') {
+ lexer->loc.lineno++;
+ lexer->loc.lineoffset = ++lexer->loc.offset;
+ } else {
+ lexer->loc.offset++;
+ }
+ return obe_lexer_current_char(lexer);
+}
+
+void
+obe_lexer_next_token(obe_lexer_t* lexer, obe_token_t* token)
+{
+ if (obe_lexer_is_eof(lexer)) {
+ *token = (obe_token_t){ .kind = TOKEN_EOF };
+ return;
+ }
+
+ char c = obe_lexer_current_char(lexer);
+ if (isspace(c) && !obe_lexer_is_eof(lexer)) {
+ while (isspace(c) && !obe_lexer_is_eof(lexer)) {
+ c = obe_lexer_next_char(lexer);
+ }
+ }
+
+ if (obe_lexer_is_eof(lexer)) {
+ *token = (obe_token_t){ .kind = TOKEN_EOF };
+ return;
+ }
+
+ if (isalpha(c) || c == '_') {
+ obe_lexer_loc_t start_loc = lexer->loc;
+ while ((isalnum(c) || c == '_') && !obe_lexer_is_eof(lexer)) {
+ c = obe_lexer_next_char(lexer);
+ }
+ obe_string_t token_value = {
+ .chars = lexer->source.chars + start_loc.offset,
+ .length = lexer->loc.offset - start_loc.offset
+ };
+ token->value = token_value;
+ token->loc = start_loc;
+ if (obe_string_eq(token_value, obe_string_from_cstr("fn"))) {
+ token->kind = TOKEN_KW_FN;
+ return;
+ }
+ if (obe_string_eq(token_value, obe_string_from_cstr("br"))) {
+ token->kind = TOKEN_KW_BR;
+ return;
+ }
+ if (obe_string_eq(token_value,
+ obe_string_from_cstr("return"))) {
+ token->kind = TOKEN_KW_RETURN;
+ return;
+ }
+ if (obe_string_eq(token_value, obe_string_from_cstr("int"))) {
+ token->kind = TOKEN_INT;
+ return;
+ }
+ token->kind = TOKEN_IDENT;
+ return;
+ }
+
+ if (c == '.') {
+ obe_lexer_loc_t start_loc = lexer->loc;
+ do {
+ c = obe_lexer_next_char(lexer);
+ } while ((isalnum(c) || c == '_') && !obe_lexer_is_eof(lexer));
+
+ obe_string_t token_value = {
+ .chars = lexer->source.chars + start_loc.offset,
+ .length = lexer->loc.offset - start_loc.offset
+ };
+
+ token->value = token_value;
+ token->loc = start_loc;
+ token->kind = TOKEN_LABEL;
+ return;
+ }
+
+ if (isdigit(c)) {
+ obe_lexer_loc_t start_loc = lexer->loc;
+ while (isdigit(c) && !obe_lexer_is_eof(lexer)) {
+ c = obe_lexer_next_char(lexer);
+ }
+ obe_string_t token_value = {
+ .chars = lexer->source.chars + start_loc.offset,
+ .length = lexer->loc.offset - start_loc.offset
+ };
+ token->kind = TOKEN_NUMBER;
+ token->value = token_value;
+ token->loc = start_loc;
+ return;
+ }
+
+ if (c == ';') {
+ token->kind = TOKEN_SEMICOLON;
+ token->loc = lexer->loc;
+ token->value = (obe_string_t){ .chars = lexer->source.chars + lexer->loc.offset, .length = 1 };
+ obe_lexer_next_char(lexer);
+ return;
+ }
+
+ if (c == ':') {
+ token->kind = TOKEN_COLON;
+ token->value = (obe_string_t){ .chars = lexer->source.chars + lexer->loc.offset , .length = 1} ;
+ token->loc = lexer->loc;
+ obe_lexer_next_char(lexer);
+ return;
+ }
+
+ if (c == '=') {
+ token->kind = TOKEN_EQ;
+ token->value = (obe_string_t){ .chars = lexer->source.chars + lexer->loc.offset, .length = 1 };
+ token->loc = lexer->loc;
+ obe_lexer_next_char(lexer);
+ return;
+ }
+
+ if (c == '{') {
+ token->kind = TOKEN_LBRACE;
+ token->value = (obe_string_t){ .chars = lexer->source.chars + lexer->loc.offset, .length = 1 };
+ token->loc = lexer->loc;
+ obe_lexer_next_char(lexer);
+ return;
+ }
+
+ if (c == '}') {
+ token->kind = TOKEN_RBRACE;
+ token->value = (obe_string_t){ .chars = lexer->source.chars + lexer->loc.offset, .length = 1 };
+ token->loc = lexer->loc;
+ obe_lexer_next_char(lexer);
+ return;
+ }
+
+ token->kind = TOKEN_UNKOWN;
+ token->value = (obe_string_t){ .chars = lexer->source.chars + lexer->loc.offset, .length = 1 };
+ token->loc = lexer->loc;
+ obe_lexer_next_char(lexer);
+ return;
+}
+
+static char* token_to_cstr_table[] = { [TOKEN_KW_RETURN] = "return",
+ [TOKEN_KW_FN] = "fn",
+ [TOKEN_KW_BR] = "br",
+ [TOKEN_IDENT] = "<ident>",
+ [TOKEN_LABEL] = "<label>",
+ [TOKEN_NUMBER] = "<number>",
+ [TOKEN_INT] = "int",
+ [TOKEN_EQ] = "=",
+ [TOKEN_COLON] = ":",
+ [TOKEN_SEMICOLON] = ";",
+ [TOKEN_LBRACE] = "{",
+ [TOKEN_RBRACE] = "}",
+ [TOKEN_EOF] = "<eof>",
+ [TOKEN_UNKOWN] = "<?unkown?>" };
+
+char*
+obe_token_to_cstr(obe_token_kind_t kind)
+{
+ return token_to_cstr_table[kind];
+}
diff --git a/src/obe.c b/src/obe.c
new file mode 100644
index 0000000..38af876
--- /dev/null
+++ b/src/obe.c
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2024 Johnny Richard <johnny@johnnyrichard.com>
+ *
+ * SPDX-License-Identifier: LGPL-3.0-or-later
+ *
+ * This file is part of obe.
+ *
+ * obe is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free
+ * Software Foundation, either version 3 of the License, or (at your option)
+ * any later version.
+ *
+ * obe is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with obe. If not, see <https://www.gnu.org/licenses/>.
+ */
+#include <config.h>
+#include <obe/parser.h>
+#include <obe/x86_64/codegen.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+typedef struct obe_cli_args
+{
+ int argc;
+ char** argv;
+} obe_cli_args_t;
+
+typedef struct obe_cli_opts
+{
+ uint32_t options;
+ char* ir_file;
+ char* program_path;
+} obe_cli_opts_t;
+
+typedef enum
+{
+ OBE_CLI_OPT_HELP = 1,
+ OBE_CLI_OPT_VERSION = 1 << 1,
+ OBE_CLI_OPT_OUTPUT = 1 << 2,
+} cli_opt_t;
+
+obe_cli_opts_t
+obe_cli_parse_args(int argc, char** argv);
+
+static char*
+obe_cli_args_shift(obe_cli_args_t* args)
+{
+ if (args->argc == 0)
+ return NULL;
+ --(args->argc);
+ return *(args->argv)++;
+}
+
+void
+obe_cli_print_usage(FILE* stream)
+{
+ fprintf(stream,
+ "Usage: " PACKAGE_NAME " [OPTIONS] file...\n"
+ "\n"
+ "Options:\n"
+ " -h, --help display the help and exit\n"
+ " -v, --version output version information and exit\n"
+ " -o, --output output gas assembly\n"
+ "\n"
+ "Report bugs to " PACKAGE_BUGREPORT "\n");
+}
+
+void
+obe_cli_print_version(void)
+{
+ printf(PACKAGE_STRING
+ "\n"
+ "\n"
+ "Copyright (C) 2025 Olang project.\n"
+ "This is free software; see the source for copying conditions. "
+ "There is NO\n"
+ "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR "
+ "PURPOSE.\n"
+ "\n"
+ "Written by Johnny Richard <johnny@johnnyrichard.com>\n");
+}
+
+int
+main(int argc, char** argv)
+{
+ obe_cli_opts_t opts = { 0 };
+ obe_cli_args_t args = { .argc = argc, .argv = argv };
+
+ opts.program_path = obe_cli_args_shift(&args);
+
+ char* arg = obe_cli_args_shift(&args);
+ while (arg != NULL) {
+ if (strcmp(arg, "-h") == 0 || strcmp(arg, "--help") == 0) {
+ opts.options |= OBE_CLI_OPT_HELP;
+ } else if (strcmp(arg, "-v") == 0 || strcmp(arg, "--version") == 0) {
+ opts.options |= OBE_CLI_OPT_VERSION;
+ } else if (strcmp(arg, "-o") == 0 || strcmp(arg, "--output") == 0) {
+ opts.options |= OBE_CLI_OPT_OUTPUT;
+ } else {
+ opts.ir_file = arg;
+ }
+ arg = obe_cli_args_shift(&args);
+ }
+
+ if (opts.ir_file != NULL) {
+ obe_arena_t arena = { 0 };
+
+ obe_lexer_t lexer = { 0 };
+ obe_lexer_init(&lexer, opts.ir_file);
+
+ obe_parser_t parser = { 0 };
+ obe_parser_init(&parser, &lexer, &arena);
+ obe_ir_translation_unit_t* tu = obe_parser_parse(&parser);
+
+ obe_x86_64_codegen_emit(tu, stdout);
+ return EXIT_SUCCESS;
+ }
+
+ if (opts.options & OBE_CLI_OPT_HELP) {
+ obe_cli_print_usage(stdout);
+ return EXIT_SUCCESS;
+ }
+
+ if (opts.options & OBE_CLI_OPT_VERSION) {
+ obe_cli_print_version();
+ return EXIT_SUCCESS;
+ }
+
+ if (opts.options & OBE_CLI_OPT_OUTPUT) {
+ return EXIT_SUCCESS;
+ }
+
+ obe_cli_print_usage(stderr);
+ return EXIT_FAILURE;
+}
diff --git a/src/parser.c b/src/parser.c
new file mode 100644
index 0000000..d95e6f9
--- /dev/null
+++ b/src/parser.c
@@ -0,0 +1,224 @@
+/*
+ * Copyright (C) 2025 Johnny Richard <johnny@johnnyrichard.com>
+ *
+ * SPDX-License-Identifier: LGPL-3.0-or-later
+ *
+ * This file is part of obe.
+ *
+ * obe is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free
+ * Software Foundation, either version 3 of the License, or (at your option)
+ * any later version.
+ *
+ * obe is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with obe. If not, see <https://www.gnu.org/licenses/>.
+ */
+#include <assert.h>
+#include <obe/array.h>
+#include <obe/lexer.h>
+#include <obe/parser.h>
+#include <stdbool.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+static obe_ir_function_t obe_parser_parse_function(obe_parser_t* parser);
+
+inline static bool expected_next_token(obe_lexer_t *lexer, obe_token_t *token,
+ obe_token_kind_t expected_kind);
+
+static bool expected_token(obe_lexer_t *lexer, obe_token_t *token,
+ obe_token_kind_t expected_kind);
+
+void
+obe_parser_init(obe_parser_t* parser, obe_lexer_t* lexer, obe_arena_t* arena)
+{
+ assert(parser && lexer && arena);
+ parser->lexer = lexer;
+ parser->arena = arena;
+}
+
+void
+obe_parser_next_expected_token(obe_parser_t* parser,
+ obe_token_t* token,
+ obe_token_kind_t kind)
+{
+ obe_lexer_next_token(parser->lexer, token);
+ if (token->kind != kind) {
+ fprintf(stderr,
+ "%s:%zu:%zu: syntax error: expected token <%s> but got <%s>.\n",
+ parser->lexer->filename,
+ token->loc.lineno + 1,
+ token->loc.offset - token->loc.lineoffset + 1,
+ obe_token_to_cstr(kind),
+ obe_token_to_cstr(token->kind));
+ exit(EXIT_FAILURE);
+ }
+}
+
+obe_ir_translation_unit_t*
+obe_parser_parse(obe_parser_t* parser)
+{
+ obe_ir_translation_unit_t* tu = obe_ir_translation_unit_new(parser->arena);
+
+ // FIXME: Add support to parse multiple functions
+ obe_array_append(tu->funcs, obe_parser_parse_function(parser));
+
+ return tu;
+}
+
+static obe_ir_function_t
+obe_parser_parse_function(obe_parser_t* parser)
+{
+ obe_token_t token;
+
+ expected_next_token(parser->lexer, &token, TOKEN_KW_FN);
+ expected_next_token(parser->lexer, &token, TOKEN_IDENT);
+
+ obe_ir_function_t func = { .name = token.value, .instrs = obe_array(parser->arena, obe_ir_inst_t) };
+
+ expected_next_token(parser->lexer, &token, TOKEN_LBRACE);
+
+ obe_lexer_next_token(parser->lexer, &token);
+ while (token.kind != TOKEN_EOF && token.kind != TOKEN_RBRACE) {
+ switch (token.kind) {
+ case TOKEN_KW_RETURN:
+ {
+ expected_next_token(parser->lexer, &token, TOKEN_IDENT);
+
+ char value[token.value.length + 1];
+ memcpy(value, token.value.chars, token.value.length);
+ value[token.value.length] = 0;
+
+ obe_ir_inst_t inst = {
+ .kind = OBE_IR_INST_RETURN,
+ .operand1 = (obe_ir_operand_t) {
+ .kind = OBE_IR_OPERAND_IDENT,
+ .value = obe_arena_strdup(parser->arena, value)
+ }
+ };
+
+ obe_array_append(func.instrs, inst);
+
+ expected_next_token(parser->lexer, &token, TOKEN_SEMICOLON);
+ } break;
+ case TOKEN_KW_BR:
+ {
+ expected_next_token(parser->lexer, &token, TOKEN_IDENT);
+
+ char op1[token.value.length + 1];
+ memcpy(op1, token.value.chars, token.value.length);
+ op1[token.value.length] = 0;
+
+ expected_next_token(parser->lexer, &token, TOKEN_LABEL);
+
+ char dest[token.value.length + 1];
+ memcpy(dest, token.value.chars, token.value.length);
+ dest[token.value.length] = 0;
+
+ expected_next_token(parser->lexer, &token, TOKEN_SEMICOLON);
+
+ obe_ir_inst_t inst = {
+ .kind = OBE_IR_INST_BR,
+ .dest = obe_arena_strdup(parser->arena, dest),
+ .operand1 = (obe_ir_operand_t) {
+ .kind = OBE_IR_OPERAND_IDENT,
+ .value = obe_arena_strdup(parser->arena, op1)
+ }
+ };
+
+ obe_array_append(func.instrs, inst);
+ } break;
+ case TOKEN_LABEL:
+ {
+ char label[token.value.length + 1];
+ memcpy(label, token.value.chars, token.value.length);
+ label[token.value.length] = 0;
+
+ expected_next_token(parser->lexer, &token, TOKEN_COLON);
+
+ obe_ir_inst_t inst = {
+ .kind = OBE_IR_INST_LABEL,
+ .dest = obe_arena_strdup(parser->arena, label)
+ };
+
+ obe_array_append(func.instrs, inst);
+ } break;
+ case TOKEN_IDENT:
+ {
+ obe_string_t val = token.value;
+
+ char dest[token.value.length + 1];
+ memcpy(dest, token.value.chars, token.value.length);
+ dest[token.value.length] = 0;
+
+ expected_next_token(parser->lexer, &token, TOKEN_COLON);
+ expected_next_token(parser->lexer, &token, TOKEN_INT);
+ expected_next_token(parser->lexer, &token, TOKEN_EQ);
+ expected_next_token(parser->lexer, &token, TOKEN_NUMBER);
+
+
+ char number[token.value.length + 1];
+ memcpy(number, token.value.chars, token.value.length);
+ number[token.value.length] = 0;
+
+ obe_ir_inst_t inst = {
+ .kind = OBE_IR_INST_CONST,
+ .type = OBE_IR_TYPE_INT,
+ .dest = obe_arena_strdup(parser->arena, dest),
+ .operand1 = (obe_ir_operand_t) {
+ .kind = OBE_IR_OPERAND_LITERAL,
+ .value = obe_arena_strdup(parser->arena, number)
+ }
+ };
+
+ obe_array_append(func.instrs, inst);
+
+ expected_next_token(parser->lexer, &token, TOKEN_SEMICOLON);
+ } break;
+ default:
+ {
+ printf("%s:%ld:%ld: token <" PRIs ">\n",
+ parser->lexer->filename,
+ token.loc.lineno + 1,
+ token.loc.offset - token.loc.lineoffset + 1,
+ PRIsARG(token.value));
+ }
+ }
+ obe_lexer_next_token(parser->lexer, &token);
+ }
+
+ expected_token(parser->lexer, &token, TOKEN_RBRACE);
+
+ return func;
+}
+
+static bool
+expected_token(obe_lexer_t *lexer, obe_token_t *token, obe_token_kind_t expected_kind)
+{
+ if (token->kind != expected_kind) {
+ fprintf(stderr,
+ "%s:%lu:%lu: syntax error: got '" PRIs "' token but expect '%s'\n",
+ lexer->filename,
+ token->loc.lineno + 1,
+ token->loc.offset - lexer->loc.lineoffset + 1,
+ PRIsARG(token->value),
+ obe_token_to_cstr(expected_kind));
+ exit(EXIT_FAILURE);
+ }
+ return true;
+}
+
+inline static bool
+expected_next_token(obe_lexer_t *lexer,
+ obe_token_t *token,
+ obe_token_kind_t expected_kind)
+{
+ obe_lexer_next_token(lexer, token);
+ return expected_token(lexer, token, expected_kind);
+}
diff --git a/src/string.c b/src/string.c
new file mode 100644
index 0000000..b6638bd
--- /dev/null
+++ b/src/string.c
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2025 Johnny Richard <johnny@johnnyrichard.com>
+ *
+ * SPDX-License-Identifier: LGPL-3.0-or-later
+ *
+ * This file is part of obe.
+ *
+ * obe is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free
+ * Software Foundation, either version 3 of the License, or (at your option)
+ * any later version.
+ *
+ * obe is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with obe. If not, see <https://www.gnu.org/licenses/>.
+ */
+#include <obe/string.h>
+#include <string.h>
+
+obe_string_t
+obe_string_from_cstr(char* cstr)
+{
+ return (obe_string_t){ .chars = cstr, .length = strlen(cstr) };
+}
+
+bool
+obe_string_eq(obe_string_t s1, obe_string_t s2)
+{
+ return s1.length == s2.length && memcmp(s1.chars, s2.chars, s1.length) == 0;
+}
diff --git a/src/utils.c b/src/utils.c
new file mode 100644
index 0000000..345d5a4
--- /dev/null
+++ b/src/utils.c
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2025 Johnny Richard <johnny@johnnyrichard.com>
+ *
+ * SPDX-License-Identifier: LGPL-3.0-or-later
+ *
+ * This file is part of obe.
+ *
+ * obe is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free
+ * Software Foundation, either version 3 of the License, or (at your option)
+ * any later version.
+ *
+ * obe is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with obe. If not, see <https://www.gnu.org/licenses/>.
+ */
+#include <obe/utils.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+char*
+read_file_contents(char* file_path)
+{
+ FILE* file;
+ int file_size;
+
+ file = fopen(file_path, "r");
+
+ if (file == NULL) {
+ perror("fopen");
+ return NULL;
+ }
+
+ if (fseek(file, 0, SEEK_END) == -1) {
+ perror("fseek SEEK_END");
+ fclose(file);
+ return NULL;
+ }
+
+ if ((file_size = ftell(file)) == -1) {
+ perror("ftell");
+ fclose(file);
+ return NULL;
+ }
+
+ if (fseek(file, 0, SEEK_SET) == -1) {
+ perror("fseek 0 SEEK_SET");
+ fclose(file);
+ return NULL;
+ }
+
+ char* file_content = (char*)calloc(file_size + 1, sizeof(char));
+ if (file_content == NULL) {
+ fprintf(stderr, "Could not allocate mem for file_content\n");
+ fclose(file);
+ return NULL;
+ }
+
+ size_t ret = fread(file_content, sizeof(char), file_size, file);
+ if (ret == 0 && ferror(file) != 0) {
+ perror("fread");
+ free(file_content);
+ fclose(file);
+ return NULL;
+ }
+
+ fclose(file);
+
+ return file_content;
+}
diff --git a/src/x86_64/codegen.c b/src/x86_64/codegen.c
new file mode 100644
index 0000000..6cafda0
--- /dev/null
+++ b/src/x86_64/codegen.c
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2025 Johnny Richard <johnny@johnnyrichard.com>
+ *
+ * SPDX-License-Identifier: LGPL-3.0-or-later
+ *
+ * This file is part of obe.
+ *
+ * obe is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free
+ * Software Foundation, either version 3 of the License, or (at your option)
+ * any later version.
+ *
+ * obe is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with obe. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <obe/arena.h>
+#include <obe/array.h>
+#include <obe/ir.h>
+#include <obe/x86_64/codegen.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+static void
+obe_x86_64_codegen_emit_function(obe_ir_function_t *fn, FILE *out)
+{
+ fprintf(out, PRIs ":\n", PRIsARG(fn->name));
+ fprintf(out, "\tpush %%rbp\n");
+ fprintf(out, "\tmov %%rsp, %%rbp\n");
+
+ size_t insts_length = obe_array_length(fn->instrs);
+ for (size_t i = 0; i < insts_length; ++i) {
+ obe_ir_inst_t inst = fn->instrs[i];
+ switch (inst.kind) {
+ case OBE_IR_INST_RETURN:
+ {
+ if (inst.operand1.kind == OBE_IR_OPERAND_LITERAL) {
+ fprintf(out, "\tmov $%s, %%rax\n", inst.operand1.value);
+ } else {
+ fprintf(stderr, "Operation kind not supported\n");
+ exit(EXIT_FAILURE);
+ }
+ } break;
+ default:
+ {
+ fprintf(stderr, "Instruction not supported\n");
+ exit(EXIT_FAILURE);
+ }
+ }
+ }
+
+ fprintf(out, "\tleave\n");
+ fprintf(out, "\tret\n");
+}
+
+void
+_obe_x86_64_codegen_emit(obe_ir_translation_unit_t* tu, FILE *out)
+{
+ // FIXME: Add syntax to configure globl
+ fprintf(out, ".globl main\n");
+
+ fprintf(out, ".text\n");
+ size_t funcs_length = obe_array_length(tu->funcs);
+ for (size_t i = 0; i < funcs_length; ++i) {
+ obe_ir_function_t fn = tu->funcs[i];
+ obe_x86_64_codegen_emit_function(&fn, out);
+ }
+}
+
+typedef struct obe_basic_block obe_basic_block_t;
+typedef struct obe_cfg obe_cfg_t;
+typedef struct obe_int_graph obe_int_graph_t;
+
+struct obe_basic_block {
+ obe_string_t id;
+ obe_ir_inst_t *instrs;
+ struct obe_basic_block *pred;
+ struct obe_basic_block *succ;
+};
+
+struct obe_cfg {
+ obe_basic_block_t *init_block;
+ obe_basic_block_t *curr_block;
+};
+
+
+typedef struct obe_int_edge {
+ size_t v1;
+ size_t v2;
+} obe_int_edge_t;
+
+struct obe_int_graph {
+ obe_int_edge_t *edges;
+};
+
+obe_int_graph_t
+create_interference_graph(obe_cfg_t *cfg, obe_arena_t *arena)
+{
+ obe_int_graph_t graph = {0};
+ graph.edges = obe_array(arena, obe_int_edge_t);
+
+ return graph;
+}
+
+void
+obe_x86_64_codegen_emit(obe_ir_translation_unit_t* tu, FILE *out)
+{
+ // FIXME: Create a valid CFG
+ obe_arena_t arena = {0};
+ obe_cfg_t cfg = {0};
+if (cfg.init_block == NULL) {
+ cfg.init_block = obe_arena_alloc(&arena, sizeof(obe_basic_block_t));
+ cfg.curr_block = cfg.init_block;
+ cfg.curr_block->instrs = obe_array(&arena, obe_ir_inst_t);
+ }
+
+ size_t funcs_length = obe_array_length(tu->funcs);
+ for (size_t i = 0; i < funcs_length; ++i) {
+ obe_ir_function_t fn = tu->funcs[i];
+
+ size_t instrs_length = obe_array_length(fn.instrs);
+ for (size_t j = 0; j < instrs_length; ++j) {
+ obe_ir_inst_t inst = fn.instrs[j];
+ switch (inst.kind) {
+ default:
+ {
+ obe_array_append(cfg.curr_block->instrs, inst);
+ }
+ }
+ }
+ }
+
+ // TODO: Register Allocation
+ // liveness analysis (create interference graph)
+ size_t instrs_length = obe_array_length(cfg.init_block->instrs);
+ for (size_t i = 0; i < instrs_length; ++i) {
+ obe_ir_inst_t inst = cfg.init_block->instrs[i];
+ // asm("int3");
+ printf("inst = %d\n", inst.kind);
+ }
+ // TODO: create_interference_graph(&cfg, &arena);
+
+
+ // TODO: Emit assembly code
+
+ obe_arena_free(&arena);
+}
diff --git a/tests/Makefile.am b/tests/Makefile.am
new file mode 100644
index 0000000..23baae3
--- /dev/null
+++ b/tests/Makefile.am
@@ -0,0 +1,12 @@
+AM_CPPFLAGS = -I$(top_srcdir)/include
+
+TESTS = arena_test array_test
+check_PROGRAMS = arena_test array_test
+
+arena_test_SOURCES = obe_arena_test.c $(top_srcdir)/src/arena.c
+arena_test_CFLAGS = @CHECK_CFLAGS@
+arena_test_LDADD = @CHECK_LIBS@
+
+array_test_SOURCES = obe_array_test.c $(top_srcdir)/src/arena.c $(top_srcdir)/src/array.c
+array_test_CFLAGS = @CHECK_CFLAGS@
+array_test_LDADD = @CHECK_LIBS@
diff --git a/tests/obe_arena_test.c b/tests/obe_arena_test.c
new file mode 100644
index 0000000..2ff97bf
--- /dev/null
+++ b/tests/obe_arena_test.c
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2025 Johnny Richard <johnny@johnnyrichard.com>
+ *
+ * SPDX-License-Identifier: LGPL-3.0-or-later
+ *
+ * This file is part of obe.
+ *
+ * obe is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free
+ * Software Foundation, either version 3 of the License, or (at your option)
+ * any later version.
+ *
+ * obe is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with obe. If not, see <https://www.gnu.org/licenses/>.
+ */
+#include <check.h>
+#include <obe/arena.h>
+#include <stdlib.h>
+
+START_TEST(obe_arena_alloc_test)
+{
+ obe_arena_t arena = { 0 };
+ int* ptr = obe_arena_alloc(&arena, sizeof(int));
+ ck_assert_ptr_nonnull(ptr);
+
+ *ptr = 10;
+ ck_assert_int_eq(*ptr, 10);
+
+ obe_arena_free(&arena);
+}
+END_TEST
+
+START_TEST(obe_arena_realloc_test)
+{
+ obe_arena_t arena = { 0 };
+ int* ptr = obe_arena_alloc(&arena, sizeof(int));
+ ck_assert_ptr_nonnull(ptr);
+
+ *ptr = 42;
+
+ int* old_ptr = ptr;
+ int* new_ptr = obe_arena_realloc(&arena, ptr, sizeof(int), sizeof(int) * 2);
+
+ ck_assert_int_eq(new_ptr[0], 42);
+ ck_assert_ptr_ne(new_ptr, old_ptr);
+
+ obe_arena_free(&arena);
+}
+END_TEST
+
+START_TEST(obe_arena_new_region_test)
+{
+ obe_arena_t arena = { 0 };
+ void* ptr = obe_arena_alloc(&arena, OBE_ARENA_REGION_DEFAULT_CAPACITY);
+ ck_assert_ptr_nonnull(ptr);
+ ck_assert_ptr_nonnull(arena.begin);
+ ck_assert_ptr_eq(arena.begin, arena.end);
+ ck_assert_ptr_null(arena.end->next);
+
+ ptr = obe_arena_alloc(&arena, sizeof(char));
+ ck_assert_ptr_nonnull(ptr);
+ ck_assert_ptr_ne(arena.begin, arena.end);
+ ck_assert_ptr_eq(arena.end->data, ptr);
+ ck_assert_ptr_null(arena.end->next);
+
+ obe_arena_free(&arena);
+}
+END_TEST
+
+START_TEST(obe_arena_strdup_test)
+{
+ obe_arena_t arena = { 0 };
+ char* s = "long string";
+ char* dup = obe_arena_strdup(&arena, s);
+
+ ck_assert_str_eq(dup, s);
+
+ obe_arena_free(&arena);
+}
+END_TEST
+
+Suite*
+arena_suite(void)
+{
+ Suite* s;
+ TCase* alloc_case;
+
+ s = suite_create("Arena");
+
+ /* Allocation test case */
+ alloc_case = tcase_create("Allocation");
+
+ tcase_add_test(alloc_case, obe_arena_alloc_test);
+ tcase_add_test(alloc_case, obe_arena_realloc_test);
+ tcase_add_test(alloc_case, obe_arena_new_region_test);
+ tcase_add_test(alloc_case, obe_arena_strdup_test);
+ suite_add_tcase(s, alloc_case);
+
+ return s;
+}
+
+int
+main(void)
+{
+ int number_failed;
+ Suite* s;
+ SRunner* sr;
+
+ s = arena_suite();
+ sr = srunner_create(s);
+
+ srunner_run_all(sr, CK_NORMAL);
+ number_failed = srunner_ntests_failed(sr);
+ srunner_free(sr);
+ return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
+}
diff --git a/tests/obe_array_test.c b/tests/obe_array_test.c
new file mode 100644
index 0000000..5439eec
--- /dev/null
+++ b/tests/obe_array_test.c
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2025 Johnny Richard <johnny@johnnyrichard.com>
+ *
+ * SPDX-License-Identifier: LGPL-3.0-or-later
+ *
+ * This file is part of obe.
+ *
+ * obe is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free
+ * Software Foundation, either version 3 of the License, or (at your option)
+ * any later version.
+ *
+ * obe is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with obe. If not, see <https://www.gnu.org/licenses/>.
+ */
+#include <check.h>
+#include <obe/arena.h>
+#include <obe/array.h>
+#include <stdlib.h>
+
+static obe_arena_t arena = { 0 };
+
+void
+setup(void)
+{
+}
+
+void
+teardown(void)
+{
+ obe_arena_release(&arena);
+}
+
+START_TEST(obe_array_append)
+{
+ int* arr = obe_array(&arena, int);
+
+ obe_array_append(arr, 1);
+ obe_array_append(arr, 2);
+ obe_array_append(arr, 3);
+ obe_array_append(arr, 4);
+ obe_array_append(arr, 5);
+
+ ck_assert_int_eq(obe_array_length(arr), 5);
+}
+END_TEST
+
+Suite*
+array_suite(void)
+{
+ Suite* s;
+ TCase* tc_append;
+
+ s = suite_create("Array");
+
+ tc_append = tcase_create("tc_append");
+
+ tcase_add_checked_fixture(tc_append, setup, teardown);
+
+ tcase_add_test(tc_append, obe_array_append);
+ suite_add_tcase(s, tc_append);
+
+ return s;
+}
+
+int
+main(void)
+{
+ int number_failed;
+ Suite* s;
+ SRunner* sr;
+
+ s = array_suite();
+ sr = srunner_create(s);
+
+ srunner_run_all(sr, CK_NORMAL);
+ number_failed = srunner_ntests_failed(sr);
+ srunner_free(sr);
+ return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
+}