alecAbstraction Layer for Escape Codes |
git clone git://git.dimitrijedobrota.com/alec.git |
Log | Files | Refs | README | LICENSE | HACKING | CONTRIBUTING | CODE_OF_CONDUCT | BUILDING | |
commit | c2e90999f4d46bb7fb5daaf8456036b76a5c36dc |
parent | 52dc5de05fbb271b2d50973f71c58114e2d363ce |
author | Dimitrije Dobrota <mail@dimitrijedobrota.com> |
date | Fri, 31 Jan 2025 15:52:43 +0100 |
Consistency improvements * Improve naming consistency with .clang-tidy * Generator delimeter now puts everything in a comment * More consistent lexing and parsing * Generation split into muiltiple functions * More verbose argument naming * Reflect changes in README * Format rules and examples
Diffstat:M | .clang-tidy | | | ++++---- |
M | CMakeLists.txt | | | +- |
M | README.md | | | +++++++++++++++++++++++++++++++++++++++++----------------------------------------- |
M | example/alec_compile.cpp | | | ++++++++++++++++++++++--------------- |
M | example/alec_runtime.cpp | | | +++++++++++++++++++--------------- |
M | source/alec.rules.hpp | | | +++++++++++++++++++++++++++++++++++++++++++++------------------------------------- |
M | source/generator.cpp | | | +++++++++++++++++++++++++++++++++++++++++++++++++++------------------------------- |
M | source/generator.h | | | +++--- |
M | source/lexer.l | | | ++++++++++-------- |
M | source/parser.y | | | ++++++------ |
10 files changed, 345 insertions(+), 271 deletions(-)
diff --git a/.clang-tidy b/.clang-tidy
@@ -140,19 +140,19 @@ CheckOptions:
- key: 'readability-identifier-naming.StructCase'
value: 'lower_case'
- key: 'readability-identifier-naming.TemplateParameterCase'
value: 'CamelCase'
value: 'lower_case'
- key: 'readability-identifier-naming.TemplateTemplateParameterCase'
value: 'CamelCase'
value: 'lower_case'
- key: 'readability-identifier-naming.TypeAliasCase'
value: 'lower_case'
- key: 'readability-identifier-naming.TypedefCase'
value: 'lower_case'
- key: 'readability-identifier-naming.TypeTemplateParameterCase'
value: 'CamelCase'
value: 'lower_case'
- key: 'readability-identifier-naming.UnionCase'
value: 'lower_case'
- key: 'readability-identifier-naming.ValueTemplateParameterCase'
value: 'CamelCase'
value: 'lower_case'
- key: 'readability-identifier-naming.VariableCase'
value: 'lower_case'
- key: 'readability-identifier-naming.VirtualMethodCase'
diff --git a/CMakeLists.txt b/CMakeLists.txt
@@ -4,7 +4,7 @@ include(cmake/prelude.cmake)
project(
alec
VERSION 0.1.10
VERSION 0.1.11
DESCRIPTION "Abstraction Layer for Escape Codes"
HOMEPAGE_URL "git://git.dimitrijedobrota.com/alec.git"
LANGUAGES CXX
diff --git a/README.md b/README.md
@@ -42,40 +42,40 @@ and don't need to be called.
#### Available functions with short explanation
| Name | parameters | Description |
|-------------------|---------------------|-------------------------------------------------|
| cursor_up | int n | Move cursor n lines up |
| cursor_down | int n | Move cursor n lines down |
| cursor_frwd | int n | Move cursor n lines left |
| cursor_back | int n | Move cursor n lines right |
| cursor_line_next | int n | Move cursor to beginning of line n lines down |
| cursor_line_prev | int n | Move cursor to beginning of line n lines up |
| cursor_column | int n | Set cursor to specific position on current line |
| cursor_position | int n, int m | Set cursor to specific position on screen |
| erase_display | Motion m | Erase in display mode |
| erase_line | Motion m | Erase in line mode |
| scroll_up | int n | Scroll whole page up by n |
| scroll_down | int n | Scroll whole page down by n |
| foreground | Color color | Set foreground to color |
| background | Color color | Set background to color |
| foreground | int idx | Set foreground to idx in 256 color pallet |
| background | int idx | Set background to idx in 256 color pallet |
| foreground | int R, int G, int B | Set foreground to RGB value |
| background | int R, int G, int B | Set background to RGB value |
| decor_set | Decor decor | Turn specific decoration on |
| decor_reset | Decor decor | Turn specific decoration of |
| cursor_save | | Saves cursor position |
| cursor_restore | | Restore cursor position |
| screen_mode_set | int n | Changes screen width or type to mode n |
| screen_mode_reset | int n | Reset screen width or type to mode n |
| screen_save | | Save screen |
| screen_restore | | Restore screen |
| cursor_show | | Show cursor |
| cursor_hide | | Hide cursor |
| abuf_show | | Enable alternate screen buffer |
| abuf_hide | | Disable alternate screen buffer |
| paste_enable | | Turn on bracketed paste mode |
| paste_disable | | Turn off bracketed paste mode |
| Name | parameters | Description |
|-------------------|---------------------|---------------------------------------------------|
| cursor_up | int cnt | Move cursor `cnt` lines up |
| cursor_down | int cnt | Move cursor `cnt` lines down |
| cursor_frwd | int cnt | Move cursor `cnt` lines left |
| cursor_back | int cnt | Move cursor `cnt` lines right |
| cursor_line_next | int cnt | Move cursor to beginning of line `cnt` lines down |
| cursor_line_prev | int cnt | Move cursor to beginning of line `cnt` lines up |
| cursor_column | int col | Set cursor to specific position on current line |
| cursor_position | int col, int row | Set cursor to specific position on screen |
| erase_display | Motion mtn | Erase in display mode |
| erase_line | Motion mtn | Erase in line mode |
| scroll_up | int cnt | Scroll whole page up by `cnt` |
| scroll_down | int cnt | Scroll whole page down by `cnt` |
| foreground | Color color | Set foreground to `color` |
| background | Color color | Set background to `color` |
| foreground | int idx | Set foreground to `idx` in 256 color pallet |
| background | int idx | Set background to `idx` in 256 color pallet |
| foreground | int R, int G, int B | Set foreground to `RGB` value |
| background | int R, int G, int B | Set background to `RGB` value |
| decor_set | Decor decor | Turn specific decoration on |
| decor_reset | Decor decor | Turn specific decoration of |
| cursor_save | | Saves cursor position |
| cursor_restore | | Restore cursor position |
| screen_mode_set | int mode | Changes screen width or type to `mode` |
| screen_mode_reset | int mode | Reset screen width or type to `mode` |
| screen_save | | Save screen |
| screen_restore | | Restore screen |
| cursor_show | | Show cursor |
| cursor_hide | | Hide cursor |
| abuf_show | | Enable alternate screen buffer |
| abuf_hide | | Disable alternate screen buffer |
| paste_enable | | Turn on bracketed paste mode |
| paste_disable | | Turn off bracketed paste mode |
#### Enumeration
@@ -130,7 +130,7 @@ and don't need to be called.
Configuration file `alec.rules.hpp` is used to customize the output of
`alec.hpp` file. Similarly to Flex and Bison, configuration files needs to have
3 sections separated by `%%`: prologue, grammar and epilogue. Prologue and
3 sections separated by `/*%%*/`: prologue, grammar and epilogue. Prologue and
epilogue are copied as-is to the output file whilst the grammar section
contains rules for generating template and function code.
@@ -168,7 +168,7 @@ concept limit_pos_v = n >= 0;
// function constraint
static inline bool limit_pos(int n) { return n >= 0; };
%%
/*%%*//*
// comment that goes into output
decor_reset
@@ -177,16 +177,16 @@ static inline bool limit_pos(int n) { return n >= 0; };
(int)decor + 20, 'm'
screen_mode_set
int n
int mode
limit_pos
'=', n, 'h'
'=', mode, 'h'
paste_enable
|
|
"?2004h"
%%
*//*%%*/
// ending of a header file
```
@@ -209,6 +209,6 @@ This project is licensed under the MIT License - see the [`LICENSE`](LICENSE.md)
## References
* [ANSI Escape Sequences gist](https://gist.github.com/fnky/458719343aabd01cfb17a3a4f7296797)
* [Wikipedia article](https://en.wikipedia.org/wiki/ANSI_escape_code)
* [`ANSI Escape Sequences gist`](https://gist.github.com/fnky/458719343aabd01cfb17a3a4f7296797)
* [`Wikipedia article`](https://en.wikipedia.org/wiki/ANSI_escape_code)
diff --git a/example/alec_compile.cpp b/example/alec_compile.cpp
@@ -1,29 +1,36 @@
#include "alec/alec.hpp"
#include <cstdio>
#include <iostream>
using namespace alec; // NOLINT
#include "alec/alec.hpp"
using namespace alec; // NOLINT
using enum Color;
using enum Decor;
int main() {
std::cout << abuf_enable_v << cursor_hide_v;
int main()
{
std::cout << abuf_enable_v << cursor_hide_v;
std::cout << cursor_position_v<1, 1> << foreground_v<91> << "HELLO!\n";
std::cout << cursor_position_v<1, 1> << foreground_v<91> << "HELLO!\n";
std::cout << cursor_down_v<3>;
std::cout << foreground_v<30> << background_v<196, 53, 64> << "WORLD!\n";
std::cout << cursor_down_v<3>;
std::cout << foreground_v<30> << background_v<196, 53, 64> << "WORLD!\n";
std::cout << background_v<DEFAULT> << "testing 1...\n"
<< foreground_v<DEFAULT>;
std::cout << background_v<DEFAULT> << "testing 1...\n" << foreground_v<DEFAULT>;
std::cout << decor_set_v<INVERSE> << "testing 2...\n" << decor_reset_v<INVERSE>;
std::cout << decor_set_v<INVERSE> << "testing 2...\n"
<< decor_reset_v<INVERSE>;
std::cout << cursor_up_v<5> << "Hello there!" << cursor_save_v;
std::cout << cursor_down_v<10> << "General Kenobi!";
std::cout << cursor_position_v<10, 40> << "no pain no gain" << cursor_restore_v << cursor_show_v;
std::cout << cursor_up_v<5> << "Hello there!" << cursor_save_v;
std::cout << cursor_down_v<10> << "General Kenobi!";
std::cout << cursor_position_v<10, 40> << "no pain no gain"
<< cursor_restore_v << cursor_show_v;
(void) getchar();
(void)std::getchar();
std::cout << abuf_disable_v;
std::cout << abuf_disable_v;
return 0;
return 0;
}
diff --git a/example/alec_runtime.cpp b/example/alec_runtime.cpp
@@ -1,29 +1,33 @@
#include "alec/alec.hpp"
#include <cstdio>
#include <iostream>
using namespace alec; // NOLINT
#include "alec/alec.hpp"
using namespace alec; // NOLINT
using enum Color;
using enum Decor;
int main() {
std::cout << abuf_enable() << cursor_hide();
int main()
{
std::cout << abuf_enable() << cursor_hide();
std::cout << cursor_position(1, 1) << foreground(91) << "HELLO!\n";
std::cout << cursor_position(1, 1) << foreground(91) << "HELLO!\n";
std::cout << cursor_down(3);
std::cout << foreground(30) << background(96, 53, 64) << "WORLD!\n";
std::cout << cursor_down(3);
std::cout << foreground(30) << background(96, 53, 64) << "WORLD!\n";
std::cout << background(DEFAULT) << "testing 1...\n" << foreground(DEFAULT);
std::cout << decor_set(INVERSE) << "testing 2...\n" << decor_reset(INVERSE);
std::cout << background(DEFAULT) << "testing 1...\n" << foreground(DEFAULT);
std::cout << decor_set(INVERSE) << "testing 2...\n" << decor_reset(INVERSE);
std::cout << cursor_up(5) << "Hello there!" << cursor_save();
std::cout << cursor_down(10) << "General Kenobi!";
std::cout << cursor_position(10, 40) << "no pain no gain" << cursor_restore() << cursor_show();
std::cout << cursor_up(5) << "Hello there!" << cursor_save();
std::cout << cursor_down(10) << "General Kenobi!";
std::cout << cursor_position(10, 40) << "no pain no gain" << cursor_restore()
<< cursor_show();
(void) getchar();
(void)std::getchar();
std::cout << abuf_disable();
std::cout << abuf_disable();
return 0;
return 0;
}
diff --git a/source/alec.rules.hpp b/source/alec.rules.hpp
@@ -3,207 +3,240 @@
#include <algorithm>
#include <array>
#include <cassert>
#include <cstdint>
#include <cinttypes>
#include <string>
#include <type_traits>
namespace alec
{
namespace alec {
enum Ctrl {
BELL = 0x07,
BS = 0x08,
HT = 0x09,
LF = 0x0A,
VT = 0x0B,
FF = 0x0C,
CR = 0x0D,
ESC = 0x1B,
DEL = 0x7F,
enum Ctrl : std::uint8_t
{
BELL = 0x07,
BS = 0x08,
HT = 0x09,
LF = 0x0A,
VT = 0x0B,
FF = 0x0C,
CR = 0x0D,
ESC = 0x1B,
DEL = 0x7F,
};
enum class Color {
BLACK = 0,
RED = 1,
GREEN = 2,
YELLOW = 3,
BLUE = 4,
MAGENTA = 5,
CYAN = 6,
WHITE = 7,
DEFAULT = 9,
enum class Color : std::uint8_t
{
BLACK = 0,
RED = 1,
GREEN = 2,
YELLOW = 3,
BLUE = 4,
MAGENTA = 5,
CYAN = 6,
WHITE = 7,
DEFAULT = 9,
};
enum class Decor {
RESET = 0,
BOLD = 1,
DIM = 2,
ITALIC = 3,
UNDERLINE = 4,
BLINK = 5,
INVERSE = 7,
HIDE = 8,
STRIKE = 9,
enum class Decor : std::uint8_t
{
RESET = 0,
BOLD = 1,
DIM = 2,
ITALIC = 3,
UNDERLINE = 4,
BLINK = 5,
INVERSE = 7,
HIDE = 8,
STRIKE = 9,
};
enum class Motion {
END = 0,
BEGIN = 1,
WHOLE = 2,
enum class Motion : std::uint8_t
{
END = 0,
BEGIN = 1,
WHOLE = 2,
};
namespace details {
namespace details
{
template<std::size_t N>
template<std::size_t n>
struct string_literal
{
constexpr string_literal(const char (&str)[N]) : m_value(std::to_array(str)) {}
constexpr string_literal(const char (&str)[n]) // NOLINT
: m_value(std::to_array(str))
{
} // NOLINT
constexpr std::size_t size() const { return N; }
constexpr std::size_t size() const { return n; }
constexpr const char* data() const { return m_value.data(); }
std::array<char, N> m_value;
std::array<char, n> m_value;
};
namespace helper {
template <std::size_t N> static constexpr std::size_t size(string_literal<N> /*val*/) { return N; }
static constexpr std::size_t size(char /*val*/) { return 1; }
static constexpr std::size_t size(int val) {
std::size_t len = 1;
while ((val /= 10) != 0) {
len++;
}
return len;
}
template <std::size_t N> static constexpr char *append(char *ptr, string_literal<N> val) {
std::copy_n(val.data(), N, ptr);
return ptr + N;
}
static constexpr char *append(char *ptr, char val) {
*ptr++ = val;
return ptr;
}
static constexpr char *append(char *ptr, int val) {
char *tmp = ptr += size(val);
do {
*--tmp = '0' + static_cast<char>(val % 10);
} while ((val /= 10) != 0);
return ptr;
}
static constexpr std::string make(auto... args) {
std::string res((helper::size(args) + ... + 2), 0);
res[0] = Ctrl::ESC, res[1] = '[';
auto ptr = res.data() + 2;
((ptr = helper::append(ptr, args)), ...);
return res;
}
template <auto... Args> struct escape_t {
static constexpr const auto value = []() {
std::array<char, (helper::size(Args) + ... + 3)> arr = {Ctrl::ESC, '[', 0};
auto ptr = arr.data() + 2;
((ptr = helper::append(ptr, Args)), ...);
return arr;
}();
static constexpr auto data = value.data();
};
} // namespace helper
template <auto... Args> static constexpr auto escape = helper::escape_t<Args...>().data;
template <details::string_literal... Strs> static constexpr auto escape_literal = escape<Strs...>;
} // namespace details
namespace helper
{
template<std::size_t n>
static constexpr std::size_t size(string_literal<n> /*val*/)
{
return n;
}
static constexpr std::size_t size(char /*val*/)
{
return 1;
}
static constexpr std::size_t size(int val)
{
std::size_t len = 1;
while ((val /= 10) != 0) {
len++;
}
return len;
}
template<std::size_t n>
static constexpr char* append(char* ptr, string_literal<n> val)
{
std::copy_n(val.data(), n, ptr);
return ptr + n; // NOLINT
}
static constexpr char* append(char* ptr, char val)
{
*ptr++ = val; // NOLINT
return ptr;
}
static constexpr char* append(char* ptr, int val)
{
char* tmp = ptr += size(val); // NOLINT
do { // NOLINT
*--tmp = '0' + static_cast<char>(val % 10); // NOLINT
} while ((val /= 10) != 0);
return ptr;
}
static constexpr std::string make(auto... args)
{
std::string res((helper::size(args) + ... + 2), 0);
res[0] = Ctrl::ESC, res[1] = '[';
auto* ptr = res.data() + 2; // NOLINT
((ptr = helper::append(ptr, args)), ...);
return res;
}
template<auto... args>
struct escape_t
{
static constexpr const auto value = []()
{
std::array<char, (helper::size(args) + ... + 3)> arr = {Ctrl::ESC, '[', 0};
auto* ptr = arr.data() + 2;
((ptr = helper::append(ptr, args)), ...);
return arr;
}();
static constexpr auto data = value.data();
};
} // namespace helper
template<auto... args>
static constexpr auto escape = alec::details::helper::escape_t<args...>::data;
template<details::string_literal... strs>
static constexpr auto escape_literal = escape<strs...>;
} // namespace details
// Tamplate parameter constraints
template <int N>
concept limit_256_v = N >= 0 && N < 256;
template<int n>
concept limit_256_v = n >= 0 && n < 256;
template <int N>
concept limit_pos_v = N >= 0;
template<int n>
concept limit_pos_v = n >= 0;
static constexpr bool limit_pos(int n) { return n >= 0; }
static constexpr bool limit_256(int n) { return n >= 0 && n < 256; }
static constexpr bool limit_pos(int n)
{
return n >= 0;
}
static constexpr bool limit_256(int n)
{
return n >= 0 && n < 256;
}
%%
/*%%*//*
// NOLINTBEGIN (*cast*)
// Move cursor up/down/frwd/back
cursor_up
int n
int cnt
limit_pos
n, 'A'
cnt, 'A'
cursor_down
int n
int cnt
limit_pos
n, 'B'
cnt, 'B'
cursor_frwd
int n
int cnt
limit_pos
n, 'C'
cnt, 'C'
cursor_back
int n
int cnt
limit_pos
n, 'D'
cnt, 'D'
// Move cursor to the next/prev line
cursor_line_next
int n
int cnt
limit_pos
n, 'E'
cnt, 'E'
cursor_line_prev
int n
int cnt
limit_pos
n, 'F'
cnt, 'F'
// Set cursor to specific column
cursor_column
int n
int col
limit_pos
n, 'G'
col, 'G'
// Erase functions
erase_display
Motion m
Motion mtn
|
static_cast<int>(m), 'J'
int(mtn), 'J'
erase_line
Motion m
Motion mtn
|
static_cast<int>(m), 'K'
int(mtn), 'K'
// Scroll up/down
scroll_up
int n
int cnt
limit_pos
n, 'S'
cnt, 'S'
scroll_down
int n
int cnt
limit_pos
n, 'T'
cnt, 'T'
// Set cursor to a specific position
cursor_position
int n, int m
int row, int col
limit_pos
n, ';', m, 'H'
row, ';', col, 'H'
// color
@@ -212,12 +245,12 @@ static constexpr bool limit_256(int n) { return n >= 0 && n < 256; }
foreground
Color color
|
static_cast<int>(color) + 30, 'm'
int(color) + 30, 'm'
background
Color color
|
static_cast<int>(color) + 40, 'm'
int(color) + 40, 'm'
// 256-color palette
@@ -248,12 +281,12 @@ static constexpr bool limit_256(int n) { return n >= 0 && n < 256; }
decor_set
Decor decor
|
static_cast<int>(decor), 'm'
int(decor), 'm'
decor_reset
Decor decor
|
static_cast<int>(decor) + 20, 'm'
int(decor) + 20, 'm'
// Save/restore cursor position;
@@ -270,14 +303,14 @@ static constexpr bool limit_256(int n) { return n >= 0 && n < 256; }
// Set screen modes
screen_mode_set
int n
int mode
limit_pos
'=', n, 'h'
'=', mode, 'h'
screen_mode_reset
int n
int mode
limit_pos
'=', n, 'l'
'=', mode, 'l'
// Private screen modes supported by most terminals
@@ -329,8 +362,9 @@ static constexpr bool limit_256(int n) { return n >= 0 && n < 256; }
|
"?2004l"
%%
// NOLINTEND (*cast*)
*//*%%*/
// Keyboard string TODO
} // namespace alec
} // namespace alec
diff --git a/source/generator.cpp b/source/generator.cpp
@@ -19,6 +19,9 @@ extern std::vector<std::string> prologue; // NOLINT
} // namespace alec
namespace
{
template<typename T>
std::string join(const std::vector<T>& vec, const std::string& delim)
{
@@ -35,52 +38,43 @@ std::string join(const std::vector<T>& vec, const std::string& delim)
return res;
}
int main(const int argc, char* argv[])
auto generate_dupes()
{
using namespace alec; // NOLINT
const bool debug = argc > 1 && std::strcmp(argv[1], "--debug") == 0;
std::ifstream ifile;
if (argc != 1) {
ifile.open(argv[!debug ? 1 : 2]);
}
driver drv = argc == 1 ? driver(std::cin, debug) : driver(ifile, debug);
parser parser(drv, debug);
const int res = parser();
// print prologue section
for (const auto line : prologue) {
std::cout << line;
}
std::set<std::string> seen, dupes;
for (const auto& record : records) {
std::set<std::string> dupes;
std::set<std::string> seen;
for (const auto& record : alec::records) {
const auto [_, inserted] = seen.insert(record.name);
if (!inserted) {
dupes.insert(record.name);
}
}
return dupes;
}
void generate_variables()
{
std::cout << "\n/* Template compile-time variables */\n";
std::cout << "\n/* Template compile-time variables */\n\n";
std::cout << "\n/* Forward-declare templates */\n";
const auto dupes = generate_dupes();
for (const auto& dup : dupes) {
std::cout << std::format(
"template <auto... val> static const char *{}_v;\n", dup);
"template <auto... val> static const char * const {}_v = \"\";\n", dup);
}
for (const auto& record : records) {
std::cout << "\n/* Template specialization */\n\n";
for (const auto& record : alec::records) {
if (record.recipe.empty()) {
// comment
std::cout << std::format("{}\n\n", record.name);
std::cout << std::format("{}\n", record.name);
continue;
}
std::vector<std::string> params(record.args.size());
std::transform(record.args.begin(),
record.args.end(),
params.begin(),
[](const std::string& str)
{ return str.substr(str.find(' ') + 1); });
std::vector<std::string> params;
params.reserve(record.args.size());
for (const auto& arg : record.args) {
params.emplace_back(arg.substr(arg.find(' ') + 1));
}
if (!record.args.empty()) {
std::cout << std::format("template <{}>\n", join(record.args, ", "));
@@ -110,29 +104,32 @@ int main(const int argc, char* argv[])
join(record.recipe, ", "));
}
}
}
void generate_functions()
{
std::cout << "\n/* Run-time functions */\n\n";
for (const auto& record : records) {
for (const auto& record : alec::records) {
if (record.recipe.empty()) {
// comment
std::cout << std::format("{}\n\n", record.name);
std::cout << std::format("{}\n", record.name);
continue;
}
std::vector<std::string> params(record.args.size());
std::transform(record.args.begin(),
record.args.end(),
params.begin(),
[](const std::string& str)
{ return str.substr(str.find(' ') + 1); });
std::vector<std::string> params;
params.reserve(record.args.size());
for (const auto& arg : record.args) {
params.emplace_back(arg.substr(arg.find(' ') + 1));
}
std::cout << std::format("static constexpr auto {}({}) {{\n",
std::cout << std::format("static constexpr auto {}({})\n{{\n",
record.name,
join(record.args, ", "));
if (!record.rules.empty()) {
for (const auto& param : params) {
std::vector<std::string> constraints;
constraints.reserve(record.rules.size());
for (const auto& rule : record.rules) {
constraints.emplace_back(std::format("{}({})", rule, param));
}
@@ -149,9 +146,39 @@ int main(const int argc, char* argv[])
std::cout << "\n}\n\n";
}
}
} // namespace
int main(const int argc, char* argv[])
{
const bool debug = argc > 1 && std::strcmp(argv[1], "--debug") == 0;
std::ifstream ifile;
if (argc != 1) {
ifile.open(argv[!debug ? 1 : 2]);
}
using namespace alec; // NOLINT
driver drv = argc == 1 ? driver(std::cin, debug) : driver(ifile, debug);
parser parser(drv, debug);
const int res = parser();
if (res != 0) {
std::cerr << "Parser error";
return -1;
}
// print prologue section
for (const auto& line : prologue) {
std::cout << line;
}
generate_variables();
generate_functions();
// print epilogue section
for (const auto line : epilogue) {
for (const auto& line : epilogue) {
std::cout << line;
}
}
diff --git a/source/generator.h b/source/generator.h
@@ -9,9 +9,9 @@ namespace alec
struct record
{
std::string name;
std::vector<char*> args;
std::vector<char*> rules;
std::vector<char*> recipe;
std::vector<std::string> args;
std::vector<std::string> rules;
std::vector<std::string> recipe;
bool operator<(const record& rhs) const { return name < rhs.name; }
};
diff --git a/source/lexer.l b/source/lexer.l
@@ -21,7 +21,7 @@
#define END_MODE() do { \
if(yy_flex_debug) std::cerr<<"Returning to mode: "<<mode_st.top()<<std::endl; \
BEGIN(mode_st.top()); \
BEGIN(mode_st.top()); \
mode_st.pop(); \
} while(0);
%}
@@ -32,6 +32,8 @@
LINE_END (\n|\r|\r\n)
SWITCH_BEGIN "/\*%%\*//\*"{LINE_END}
SWITCH_END "\*//\*%%\*/"{LINE_END}
%x GEN LAST
@@ -42,9 +44,9 @@ LINE_END (\n|\r|\r\n)
%}
"%%"{LINE_END} { BEGIN_MODE(GEN); return Token::SWITCH; }
.*{LINE_END} {
yylval->emplace<char *>(strdup(yytext));
{SWITCH_BEGIN} { BEGIN_MODE(GEN); return Token::SWITCH; }
.*{LINE_END} {
yylval->emplace<std::string>(yytext);
return Token::PROLOGUE;
}
@@ -53,7 +55,7 @@ LINE_END (\n|\r|\r\n)
<GEN>^[\t ]*\|*[\t ]*{LINE_END} { return Token::EMPTY; }
<GEN>^[\t ]*"//".* {
yylval->emplace<char *>(strdup(yytext));
yylval->emplace<std::string>(yytext);
return Token::COMMENT;
}
@@ -63,17 +65,17 @@ LINE_END (\n|\r|\r\n)
char *p = yytext + strlen(yytext) - 1;
while(isspace(*p)) *p-- = '\0';
while(*yytext && isspace(*yytext)) yytext++;
yylval->emplace<char *>(strdup(yytext));
yylval->emplace<std::string>(yytext);
return Token::LITERAL;
}
<GEN>"%%"{LINE_END} {
<GEN>{SWITCH_END} {
BEGIN_MODE(LAST);
return Token::SWITCH;
}
<LAST>.*{LINE_END} {
yylval->emplace<char *>(strdup(yytext));
yylval->emplace<std::string>(yytext);
return Token::EPILOGUE;
}
diff --git a/source/parser.y b/source/parser.y
@@ -53,8 +53,8 @@
%token EOL COMMA SWITCH EMPTY
%type <record> record
%type <std::vector<char*>> list items
%type <char *> name
%type <std::vector<std::string>> list items
%type <std::string> name
%start document
@@ -63,16 +63,16 @@
document: prologue grammar epilogue
prologue: %empty
| prologue PROLOGUE { prologue.push_back($2); }
| prologue PROLOGUE { prologue.emplace_back($2); }
;
epilogue: SWITCH
| epilogue EPILOGUE { epilogue.push_back($2); }
| epilogue EPILOGUE { epilogue.emplace_back($2); }
;
grammar: SWITCH
| grammar EOL
| grammar record { records.push_back(std::move($2)); }
| grammar record { records.emplace_back($2); }
;
record: name list list list { $$ = record($1, $2, $3, $4); }
@@ -87,7 +87,7 @@ list: EMPTY { $$ = {}; }
;
items: LITERAL { $$ = { $1 }; }
| items COMMA LITERAL { $1.push_back($3); $$ = $1; }
| items COMMA LITERAL { $1.emplace_back($3); $$ = $1; }
;
%%