This project consists of the development of an interpreter for a programming language specialized in vector handling and operations. The development is divided into 6 incremental stages, starting from basic arithmetic operations to advanced functionalities.
- Dynamic Handling: Vectors can have any dimension thanks to an implementation based on linked lists.
- Dimension Validation: The interpreter automatically verifies that operand dimensions are compatible for each operation.
- Memory Management: Implementation of automatic memory cleanup after each evaluation to prevent leaks.
- Stage 1: Basic vector arithmetic and memory management.
- Stage 2: Variables, symbol table, and predefined functions.
- Stage 3: Stack Machine Architecture and Code Generation.
- Stage 4: Control Structures (if, else, while) and Logical Operators.
- Stage 5: Determinate iteration loops (
for). - Stage 6: Functions, procedures, and recursion.
In this initial phase, the interpreter functions as an interactive calculator that processes mathematical expressions directly from standard input.
- Parser: Developed with Bison using a recursive grammar.
- Lexer: Integrated lexical analyzer for recognition of integers and operation tokens.
- Data Structures: Implemented in C using
VectorandComponentstructures for dynamic storage.
| Operation | Syntax | Description |
|---|---|---|
| Addition | exp + exp |
Component-wise addition of two vectors. |
| Subtraction | exp - exp |
Component-wise subtraction of two vectors. |
| Scalar Product | n * exp |
Multiplication of a scalar by a vector. |
| Dot Product | exp * exp |
Calculation of inner product (returns a scalar). |
| Cross Product | exp x exp |
Vector product (exclusive to dimension 3). |
| Norm | | exp | |
Calculation of the Euclidean magnitude of the vector. |
>>> [1, 2, 3] + [4, 5, 6]
[5, 7, 9]
>>> [1, 0, 0] x [0, 1, 0]
[0, 0, 1]
>>> |[3, 4]|
5
>>> 5 * [1, 1]
[5, 5]
vectores.y: Bison grammar definition and lexical analyzer logic (yylex).vectores.c: Implementation of vector logic (creation, insertion, operations, and memory release).vectores.h: Definitions ofVectorandComponentstructures, and function prototypes.Makefile: Automated compilation scripts.
In this stage, the interpreter adds the ability to store results in memory and use built-in functions for vector analysis.
- Symbol Table: A linked list (
Symbol) was implemented to manage variable and function identifiers. - Data Persistence: Allows assigning vectors or operation results to variable names.
- Built-in Functions: Support for predefined function calls loaded during system initialization.
- Advanced Lexical Analysis: The lexer now recognizes alphanumeric identifiers and differentiates them from reserved words or functions.
| Feature | Syntax | Description |
|---|---|---|
| Assignment | A = [1, 2, 3] |
Stores a vector in variable A. |
| Variable Usage | A + [4, 5, 6] |
Retrieves the stored value to perform operations. |
| Norm Function | norma(A) |
Predefined function that returns the magnitude of a vector. |
| Dimension Function | dimension(A) |
Returns the number of components in a vector. |
>>> A = [1, 2, 3]
>>> B = [4, 5, 6]
>>> C = A x B
>>> C
[-3, 6, -3]
>>> norma(C)
7
>>> dimension(A)
3
vectores.y: Updated grammar with support for assignments and functions.simbolo.c: Symbol table management (variable search and installation).inicializacion.c: Registration of predefined mathematical functions in the system.vectores.c: Vector operations engine and memory logic.vectores.h: Global definitions of structures and prototypes.
In this stage, the interpreter stops executing operations directly during syntactic analysis. Now, the parser acts as a code generator that translates expressions into an instruction sequence for a Stack Virtual Machine.
- Execution Engine (VM): A data stack (
Datum) was implemented that can store scalars, vectors, or pointers to symbols. - Code Generation: The parser uses the
code()function to write instructions and operands to a global array calledprogram. - Machine Instructions:
Instructiontypes were defined as function pointers, enabling an efficient execution cycle based on a program counter (PC). - Phase Separation: The main loop now initializes code generation, calls
yyparse()to fill the program memory, and finally invokesexecute().
| Component | Description |
|---|---|
Stack (pila) |
Stores operands of type Datum (Scalars, Vectors, Components, or Symbols). |
Program (programa) |
An array of function pointers (Instruction) representing the script's bytecode. |
| Machine Operations | Functions like maquina_suma, maquina_resta, and maquina_norma that operate directly on the stack. |
For the expression A = [1, 2] + [3, 4], the generator produces:
insert_variable(A)maquina_crear_vector([1, 2])maquina_crear_vector([3, 4])maquina_sumaassignSTOP.
vectores.y: Updated parser to generate machine code instead of executing immediate results.maquina.c: Implementation of the stack, program array, and execution cycleexecute().vectores.h: Definitions of theDatumunion andInstructiontype.simbolo.c: Symbol table management for variables and predefined functions.inicializacion.c: Loading of mathematical functions (norm, dimension) into the symbol table.vectores.c: Low-level logic for manipulating the vector structure and its components.
In this stage, the interpreter evolves to support complete imperative programming, allowing decision-making and iterative execution of code blocks.
- Relational and Logical Operators: Comparisons for scalars and vectors were incorporated, as well as boolean algebra (
&&,||,!). - Control Statements: Implementation of
si(if),sino(else), andmientras(while) through jumps in the program counter. - Code Blocks: Support for multiple statements grouped between braces
{ ... }. - Extended Lexical Analysis: The lexer now recognizes compound operators like
>=,<=,==,!=and reserved words.
| Category | Syntax | Description |
|---|---|---|
| Conditional | si (condition) { ... } sino { ... } |
Branched execution based on a condition. |
| Iteration | mientras (condition) { ... } |
Repetitive loop based on a scalar condition. |
| Logic | &&, ||, ! |
AND, OR, and NOT operators for scalars. |
| Comparison | ==, !=, <, >, <=, >= |
Magnitude comparison or vector equality. |
| Output | imprimir expression |
Displays the value of a vector or scalar in console. |
>>> A = [1, 2, 3]
>>> B = [1, 2, 3]
>>> si (A == B) {
... imprimir([1, 1, 1])
... }
[1, 1, 1]
>>> i = 5
>>> mientras (i > 0) {
... imprimir([i, i])
... i = i - 1
... }
[5, 5]
[4, 4]
[3, 3]
[2, 2]
[1, 1]
vectores.y: Complete grammar with rules for control structures and logical operator precedence.maquina.c: Execution engine that manages the stack and jump functions si() and mientras().inicializacion.c: Registration of reserved words (si, sino, mientras, imprimir).vectores.c: Implementation of comparison logic such as son_iguales().simbolo.c: Symbol table for variable and constant management.vectores.h: Definitions of the Datum union and prototypes of new machine instructions.
In this stage, the para (for) structure is introduced, offering compact syntax to initialize, evaluate, and update control variables in a single line, facilitating traversal of vector elements.
paraLoop Logic: The virtual machine can now manage four distinct code blocks for a single statement: initialization, stop condition, increment/decrement step, and loop body.- Pointer Management in VM: A
para()function was implemented in the execution engine that saves the program counter to correctly alternate between condition evaluation and step execution. - Expanded Grammar: The parser (
vectores.y) includes new precedence rules and semicolon handling to separate the three sections of theparaloop.
| Structure | Description |
|---|---|
para (initialization; condition; step) { body } |
Executes initialization once, repeats the body while the condition is true, and executes the step after each iteration. |
>>> A = [0, 0]
>>> para (i = 1; i <= 3; i = i + 1) {
... A = A + [i, i]
... imprimir(A)
... }
[1, 1]
[3, 3]
[6, 6]
vectores.y: Grammar with support for the PARA token and loop construction rules.maquina.c: Implementation of the machine instruction para() that controls execution flow.inicializacion.c: Registration of the reserved word para in the symbol table.vectores.c: Low-level operations for vectors (addition, subtraction, cross product, norm).simbolo.c: Dynamic management of the symbol table for variables and functions.Makefile: Compilation script to generate the final binary.
The final stage introduces code abstraction through user-defined functions and procedures, allowing the creation of custom vector operation libraries.
- Stack Frames: A frame stack (
Marco) was implemented to manage the context of each call, storing the return point and arguments. - Dynamic Definition: Use of reserved words
funcionandprocedimiento(or their aliasesfuncandproc) to register new code blocks in the symbol table. - Argument Passing: Access to parameters through the syntax
$n(e.g.,$1,$2), managed dynamically during execution. - Return Statements: Implementation of
retornarto return values from functions or exit procedures prematurely.
| Type | Syntax | Description |
|---|---|---|
| Function | func name() { ... retornar exp } |
Subroutine that must return a value mandatorily. |
| Procedure | proc name() { ... } |
Code execution subroutine without a return value. |
| Arguments | $1, $2, ... $n |
Local variables representing the passed parameters. |
# Definition of a function to calculate double a vector
>>> func doble() {
... retornar $1 * 2
... }
# Using the function
>>> unVector = [1, 2]
>>> otroVector = doble(unVector)
>>> imprimir(otroVector)
[2, 4]
# Procedure with iteration
>>> proc saludo() {
... para (i = 0; i < 3; i = i + 1) {
... imprimir("Hola", i)
... }
... }
>>> saludo()
Hola 0
Hola 1
Hola 2
maquina.c: Implementation of the execution cycle, data stack management, and function frame stack.simbolo.c: Symbol table management for variables, predefined functions, and user-defined functions.inicializacion.c: Registration of reserved words (si, para, func, retornar) and constants.vectores.c: Core engine for vector mathematical operations (addition, cross product, norm).vectores.h: Global definitions of Vector, Datum, Instruction, and Marco structures.
The project uses a Makefile to automate the binary build and parser file generation.
- GCC: C compiler.
- Bison: Syntactic analyzer generator (LALR).
- Make: Compilation automation tool.
- Math Library: The project requires linking to the standard math library (
-lm) for norm calculations.
-
Compile the project: By executing the following command, the
vectores.yfile will be processed with Bison and the C modules will be compiled.make
-
Run the interpreter: Once the binary is generated, you can start the command-line interface:
./vectores
-
Clean generated files: To remove object files, the executable, and source code generated by Bison:
make clean