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:
11
projects/functions.j
Normal file
11
projects/functions.j
Normal file
@@ -0,0 +1,11 @@
|
||||
x = "Hello world!"
|
||||
y = 21
|
||||
println()
|
||||
println(x)
|
||||
print("y=")
|
||||
println(y)
|
||||
|
||||
dummy()
|
||||
|
||||
if y > 1:
|
||||
println("OK!")
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user