Replace print/println keywords with generic function call mechanism

- Add NODE_CALL with name, args, and arg_count to parser
- Add TOK_COMMA token and tokenize (, ), , in lexer
- Remove TOK_PRINT/TOK_PRINTLN keywords; print/println are now regular
  identifiers resolved as built-in functions in the evaluator
- Add NODE_CALL debug output in ast_print
This commit is contained in:
Jose Luis Montañes Ojados
2026-02-16 18:14:39 +01:00
parent dd67537598
commit a36e52a9c3
4 changed files with 97 additions and 37 deletions

11
projects/functions.j Normal file
View File

@@ -0,0 +1,11 @@
x = "Hello world!"
y = 21
println()
println(x)
print("y=")
println(y)
dummy()
if y > 1:
println("OK!")

View File

@@ -15,8 +15,6 @@ typedef enum {
// Identificadores y keywords
TOK_ID, // x, foo, mi_var
TOK_PRINT, // print
TOK_PRINTLN, // println
TOK_IF, // if
TOK_WHILE, // while
@@ -35,6 +33,7 @@ typedef enum {
TOK_LPAREN, // (
TOK_RPAREN, // )
TOK_COLON, // :
TOK_COMMA, // ,
TOK_NEWLINE, // \n (significativo, como en Python)
TOK_INDENT, // aumento de indentacion
TOK_DEDENT, // reduccion de indentacion
@@ -118,6 +117,15 @@ Token *tokenize(const char *source, int *token_count) {
} else if (c == ':') {
tokens[count++] = make_token(TOK_COLON, ":");
pos++;
} else if (c == ',') {
tokens[count++] = make_token(TOK_COMMA, ",");
pos++;
} else if (c == '(') {
tokens[count++] = make_token(TOK_LPAREN, "(");
pos++;
} else if (c == ')') {
tokens[count++] = make_token(TOK_RPAREN, ")");
pos++;
} else if (c == '"') {
// Leer todo hasta el proximo '"'
pos++; // consumir '"'
@@ -138,16 +146,13 @@ Token *tokenize(const char *source, int *token_count) {
while (isalnum(source[pos]))
pos++;
char *word = substr(source, start, pos);
// tokens[count++] = make_token(TOK_ID, word);
// Comprobar si es una keyword reservada
if (strcmp(word, "print") == 0) {
tokens[count++] = make_token(TOK_PRINT, word);
if (strcmp(word, "if") == 0) {
tokens[count++] = make_token(TOK_IF, word);
} else if (strcmp(word, "while") == 0) {
tokens[count++] = make_token(TOK_WHILE, word);
} else if (strcmp(word, "if") == 0) {
tokens[count++] = make_token(TOK_IF, word);
} else if (strcmp(word, "println") == 0) {
tokens[count++] = make_token(TOK_PRINTLN, word);
} else {
tokens[count++] = make_token(TOK_ID, word);
}

View File

@@ -17,6 +17,7 @@ typedef enum {
NODE_IF, // if cond: bloque
NODE_WHILE, // while cond: bloque
NODE_BLOCK, // secuencia de statements
NODE_CALL,
} NodeType;
typedef struct ASTNode {
@@ -48,6 +49,11 @@ typedef struct ASTNode {
struct ASTNode *cond;
struct ASTNode *body;
} if_statement; // NODE_IF
struct {
char *name;
struct ASTNode **args;
int arg_count;
} call;
} data;
} ASTNode;
@@ -71,10 +77,13 @@ ASTNode *parse_term(Token *tokens) {
pos++;
return node;
} else if (tokens[pos].type == TOK_ID) {
printf("Parsing token: %s\n", tokens[pos].value);
ASTNode *node = make_node(NODE_VAR);
node->data.string_val = tokens[pos].value;
pos++;
return node;
} else if (tokens[pos].type == TOK_MINUS) {
pos++; // consumir '-'
ASTNode *term = parse_term(tokens);
@@ -85,7 +94,9 @@ ASTNode *parse_term(Token *tokens) {
neg->data.binop.right = term;
return neg;
}
printf("ERROR: esperaba INT o ID, encontre tipo %d\n", tokens[pos].type);
printf("ERROR: esperaba INT o ID, encontre tipo %d value: %s\n",
tokens[pos].type, tokens[pos].value);
exit(1);
}
@@ -110,6 +121,32 @@ ASTNode *parse_expr(Token *tokens) {
ASTNode *parse_statement(Token *tokens) {
if (tokens[pos].type == TOK_ID) {
if (tokens[pos + 1].type == TOK_LPAREN) {
// Es una funcion
char *name = tokens[pos].value;
pos++; // consumir ID
pos++; // consumir "("
// Parsear argumentos
ASTNode **args =
(ASTNode **)malloc(sizeof(ASTNode *) * 16); // Max 16 parametros
int arg_count = 0;
if (tokens[pos].type != TOK_RPAREN) {
args[arg_count++] = parse_expr(tokens);
while (tokens[pos].type == TOK_COMMA) {
pos++; // Consumir ","
args[arg_count++] = parse_expr(tokens);
}
}
pos++; // consumir ")"
ASTNode *node = make_node(NODE_CALL);
node->data.call.name = name;
node->data.call.args = args;
node->data.call.arg_count = arg_count;
return node;
}
char *name = tokens[pos].value;
pos++; // consumir ID
pos++; // consumir "="
@@ -120,23 +157,6 @@ ASTNode *parse_statement(Token *tokens) {
node->data.assign.value = value;
return node;
}
if (tokens[pos].type == TOK_PRINT) {
pos++; // consumir "print"
ASTNode *expr = parse_expr(tokens);
ASTNode *node = make_node(NODE_PRINT);
node->data.print.expr = expr;
return node;
}
if (tokens[pos].type == TOK_PRINTLN) {
pos++; // consumir "println"
ASTNode *expr = parse_expr(tokens);
ASTNode *node = make_node(NODE_PRINTLN);
node->data.print.expr = expr;
return node;
}
if (tokens[pos].type == TOK_WHILE) {
pos++; // consumir while
@@ -257,16 +277,6 @@ void ast_print(ASTNode *node, const char *prefix, int is_last) {
ast_print(node->data.binop.right, new_prefix, 1);
break;
case NODE_PRINT:
printf("NODE_PRINT\n");
ast_print(node->data.print.expr, new_prefix, 1);
break;
case NODE_PRINTLN:
printf("NODE_PRINTLN\n");
ast_print(node->data.print.expr, new_prefix, 1);
break;
case NODE_BLOCK:
printf("NODE_BLOCK\n");
for (int i = 0; i < node->data.block.count; i++) {
@@ -281,6 +291,14 @@ void ast_print(ASTNode *node, const char *prefix, int is_last) {
ast_print(node->data.while_loop.body, new_prefix, 1);
break;
case NODE_CALL:
printf("NODE_CALL(\"%s\")\n", node->data.call.name);
for (int i = 0; i < node->data.call.arg_count; i++) {
ast_print(node->data.call.args[i], new_prefix,
i == node->data.call.arg_count - 1);
}
break;
default:
printf("UNKNOWN\n");
break;

View File

@@ -83,7 +83,8 @@ size_t eval(ASTNode *node, Environment *env, void *allocator, int debug,
l->data.string_val.length);
// Copy right text
memcpy(tempBuff + l->data.string_val.length, JLANG_RESOLVE(allocator, r->data.string_val.chars),
memcpy(tempBuff + l->data.string_val.length,
JLANG_RESOLVE(allocator, r->data.string_val.chars),
r->data.string_val.length);
tempBuff[n] = '\0';
@@ -145,6 +146,31 @@ size_t eval(ASTNode *node, Environment *env, void *allocator, int debug,
}
break;
}
case NODE_CALL: {
if (strcmp(node->data.call.name, "print") == 0) {
if (node->data.call.arg_count > 0) {
size_t val = eval(node->data.call.args[0], env, allocator, debug, gc);
obj_print(allocator, val, "");
return val;
}
printf("");
return 0;
}
if (strcmp(node->data.call.name, "println") == 0) {
if (node->data.call.arg_count > 0) {
size_t val = eval(node->data.call.args[0], env, allocator, debug, gc);
obj_print(allocator, val, "");
printf("\n");
return val;
}
printf("\n");
return 0;
}
printf("ERROR: funcion '%s' no definida\n", node->data.call.name);
exit(1);
}
default:
break;
}