DEV Community

Cover image for Como 'hackear' a linguagem de programação Ter/Terlang
Marcos Oliveira
Marcos Oliveira

Posted on

1

Como 'hackear' a linguagem de programação Ter/Terlang

Incorporar suas próprias funções diretamente via código-fonte com C++


Quando eu criei a linguagem de programação Ter/Terlang uma das coisas que eu queria que ela tivesse era justamente: a facilidade de poder hackear a linguagem e incorporar funções embutidas pelo programador.

Ou seja, você pode criar suas próprias funções nativas. Isso vai ser interessante quando eu começar a incorporar bibliotecas, principalmente de GameDev, como: SFML, SDL, Raylib e entre outras para ser utilizada pela Ter/Terlang.

Nesse exemplo vamos criar a função nativa: helloworld(), ou seja, ao imprimir essa função, deve exibir a mensagem: Hello, World!.

No momento se você criar um arquivo helloworld.ter e tentar fazer isso:

output(helloworld())
Enter fullscreen mode Exit fullscreen mode

Após rodar: ter helloworld.ter, a saída será um erro:

[line 1] Error: Undefined variable: 'helloworld'.
Enter fullscreen mode Exit fullscreen mode

Então, vamos modificar o código-fonte para que isso funcione!


Procedimento

Basta seguirmos 3 passos básicos para esse feito.

01. Antes de mais nada você precisa clonar

E entrar no projeto:

git clone https://github.com/terroo/terlang
cd terlang
Enter fullscreen mode Exit fullscreen mode

02. Agora vamos editar o arquivo: ./src/Builtin.hpp

E adicionar ao final do arquivo o código abaixo:

class HelloWorld : public Callable {
    public:
        int arity() override;
        std::any call(Interpreter &interpreter, std::vector<std::any> arguments) override;
        std::string toString() override;
}; 
Enter fullscreen mode Exit fullscreen mode

Todas as funções precisam herdar Callable de forma pública. As funções-membro: arity(), call() e toString() são o modelo para todas as funções que serão embutidas e precisam ser públicas.

03. Depois precisamos criar a execução para as funções-membro da classe HelloWorld que adicionamos.

Edite o arquivo ./src/Builtin.cpp e insira ao final do arquivo o conteúdo abaixo:

// ------ HelloWorld -----------
int HelloWorld::arity(){
    return 0;
}

std::any HelloWorld::call(Interpreter &interpreter, std::vector<std::any> arguments){
    if(arguments.size() > (size_t)arity() && interpreter.global != nullptr){
        builtinError("helloworld");
    }

    std::string hello = "Hello, World!";

    return std::any_cast<std::string>(hello);
}

std::string HelloWorld::toString(){
    return "<function builtin>";
}
Enter fullscreen mode Exit fullscreen mode
  • A função-membro arity() precisa retornar a quantidade de argumentos que ela recebe, como a função helloworld() não recebe nenhum argumento, retornamos zero, se fosse, por exemplo, uma função de nome add(x, y) recebe 2 argumentos, logo, precisaríamos retornar return 2;

  • A função-membro call() precisa sempre haver esse if inicial para verificar a quantidade de argumentos. Todos os retornos precisam ser transformados em std::any com std::any_cast, como queremos que retorne uma string então convertemos para std::string que será a frase que será exibida.

  • E por final toString() sempre deve possuir esse conteúdo para mapearmos o tipo de erro e saber que a falha na verdade é nesse tipo de função.

04. Adicionar helloworld ao mapa da Terlang

Agora vamos editar o arquivo: ./src/BuiltinFactory.cpp e adicionar AO FINAL DOS MAPAS builtinFactory e builtinNames o contexto. Com a sintaxe abaixo informe o nome da classe da sua função embutida, nesse caso: HelloWorld:

Lembre que na linha acima dela, precisa ADICIONAR UMA VÍRGULA: , ao final da linha para mostrar que possuímos um novo elemento.

{typeid(std::shared_ptr<HelloWorld>), [](){ return std::make_shared<HelloWorld>(); }}
Enter fullscreen mode Exit fullscreen mode

E fazer o mesmo em builtinNames, o primeiro elemento desse mapa é o nome que você deseja chamar no seu arquivo .ter, nesse caso chamamos ela de "helloworld" mesmo:

{"helloworld", typeid(std::shared_ptr<HelloWorld>)}
Enter fullscreen mode Exit fullscreen mode

Tudo certo agora basta compilar e testar:

# rm -rf build/ se já tiver construído uma vez, pois o CMake pode usar o cache
cmake -B build .
cmake --build build
Enter fullscreen mode Exit fullscreen mode

Crie o arquivo de teste: helloworld.ter:

auto hello = helloworld()
output(hello)
Enter fullscreen mode Exit fullscreen mode

Nesse caso, fizemos diferente do arquivo acima, armazenamos o retorno de helloworld() na variável hello, mas você também pode imprimir diretamente caso queira: output(helloworld())

E rode:

./build/ter helloworld.ter
Enter fullscreen mode Exit fullscreen mode

A saída será: Hello, World!

Se quiser que fique disponível para seu sistema é só instalar: sudo cmake --install build/.


Bem simples, né?! Esse procedimento está disponível na Wiki.

Para mais informações acesse o repositório: https://github.com/terroo/terlang/.

Aprenda a criar sua própria linguagem de programação com nosso Curso:

https://terminalroot.com.br/mylang

Hostinger image

Get n8n VPS hosting 3x cheaper than a cloud solution

Get fast, easy, secure n8n VPS hosting from $4.99/mo at Hostinger. Automate any workflow using a pre-installed n8n application and no-code customization.

Start now

Top comments (0)

Sentry image

See why 4M developers consider Sentry, “not bad.”

Fixing code doesn’t have to be the worst part of your day. Learn how Sentry can help.

Learn more

👋 Kindness is contagious

Found this post helpful? A ❤️ or a friendly comment is always appreciated!

Okay