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
|
// Identificadores y keywords
|
||||||
TOK_ID, // x, foo, mi_var
|
TOK_ID, // x, foo, mi_var
|
||||||
TOK_PRINT, // print
|
|
||||||
TOK_PRINTLN, // println
|
|
||||||
TOK_IF, // if
|
TOK_IF, // if
|
||||||
TOK_WHILE, // while
|
TOK_WHILE, // while
|
||||||
|
|
||||||
@@ -35,6 +33,7 @@ typedef enum {
|
|||||||
TOK_LPAREN, // (
|
TOK_LPAREN, // (
|
||||||
TOK_RPAREN, // )
|
TOK_RPAREN, // )
|
||||||
TOK_COLON, // :
|
TOK_COLON, // :
|
||||||
|
TOK_COMMA, // ,
|
||||||
TOK_NEWLINE, // \n (significativo, como en Python)
|
TOK_NEWLINE, // \n (significativo, como en Python)
|
||||||
TOK_INDENT, // aumento de indentacion
|
TOK_INDENT, // aumento de indentacion
|
||||||
TOK_DEDENT, // reduccion de indentacion
|
TOK_DEDENT, // reduccion de indentacion
|
||||||
@@ -118,6 +117,15 @@ Token *tokenize(const char *source, int *token_count) {
|
|||||||
} else if (c == ':') {
|
} else if (c == ':') {
|
||||||
tokens[count++] = make_token(TOK_COLON, ":");
|
tokens[count++] = make_token(TOK_COLON, ":");
|
||||||
pos++;
|
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 == '"') {
|
} else if (c == '"') {
|
||||||
// Leer todo hasta el proximo '"'
|
// Leer todo hasta el proximo '"'
|
||||||
pos++; // consumir '"'
|
pos++; // consumir '"'
|
||||||
@@ -138,16 +146,13 @@ Token *tokenize(const char *source, int *token_count) {
|
|||||||
while (isalnum(source[pos]))
|
while (isalnum(source[pos]))
|
||||||
pos++;
|
pos++;
|
||||||
char *word = substr(source, start, pos);
|
char *word = substr(source, start, pos);
|
||||||
|
// tokens[count++] = make_token(TOK_ID, word);
|
||||||
|
|
||||||
// Comprobar si es una keyword reservada
|
// Comprobar si es una keyword reservada
|
||||||
if (strcmp(word, "print") == 0) {
|
if (strcmp(word, "if") == 0) {
|
||||||
tokens[count++] = make_token(TOK_PRINT, word);
|
tokens[count++] = make_token(TOK_IF, word);
|
||||||
} else if (strcmp(word, "while") == 0) {
|
} else if (strcmp(word, "while") == 0) {
|
||||||
tokens[count++] = make_token(TOK_WHILE, word);
|
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 {
|
} else {
|
||||||
tokens[count++] = make_token(TOK_ID, word);
|
tokens[count++] = make_token(TOK_ID, word);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ typedef enum {
|
|||||||
NODE_IF, // if cond: bloque
|
NODE_IF, // if cond: bloque
|
||||||
NODE_WHILE, // while cond: bloque
|
NODE_WHILE, // while cond: bloque
|
||||||
NODE_BLOCK, // secuencia de statements
|
NODE_BLOCK, // secuencia de statements
|
||||||
|
NODE_CALL,
|
||||||
} NodeType;
|
} NodeType;
|
||||||
|
|
||||||
typedef struct ASTNode {
|
typedef struct ASTNode {
|
||||||
@@ -48,6 +49,11 @@ typedef struct ASTNode {
|
|||||||
struct ASTNode *cond;
|
struct ASTNode *cond;
|
||||||
struct ASTNode *body;
|
struct ASTNode *body;
|
||||||
} if_statement; // NODE_IF
|
} if_statement; // NODE_IF
|
||||||
|
struct {
|
||||||
|
char *name;
|
||||||
|
struct ASTNode **args;
|
||||||
|
int arg_count;
|
||||||
|
} call;
|
||||||
} data;
|
} data;
|
||||||
} ASTNode;
|
} ASTNode;
|
||||||
|
|
||||||
@@ -71,10 +77,13 @@ ASTNode *parse_term(Token *tokens) {
|
|||||||
pos++;
|
pos++;
|
||||||
return node;
|
return node;
|
||||||
} else if (tokens[pos].type == TOK_ID) {
|
} else if (tokens[pos].type == TOK_ID) {
|
||||||
|
printf("Parsing token: %s\n", tokens[pos].value);
|
||||||
|
|
||||||
ASTNode *node = make_node(NODE_VAR);
|
ASTNode *node = make_node(NODE_VAR);
|
||||||
node->data.string_val = tokens[pos].value;
|
node->data.string_val = tokens[pos].value;
|
||||||
pos++;
|
pos++;
|
||||||
return node;
|
return node;
|
||||||
|
|
||||||
} else if (tokens[pos].type == TOK_MINUS) {
|
} else if (tokens[pos].type == TOK_MINUS) {
|
||||||
pos++; // consumir '-'
|
pos++; // consumir '-'
|
||||||
ASTNode *term = parse_term(tokens);
|
ASTNode *term = parse_term(tokens);
|
||||||
@@ -85,7 +94,9 @@ ASTNode *parse_term(Token *tokens) {
|
|||||||
neg->data.binop.right = term;
|
neg->data.binop.right = term;
|
||||||
return neg;
|
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);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -110,6 +121,32 @@ ASTNode *parse_expr(Token *tokens) {
|
|||||||
|
|
||||||
ASTNode *parse_statement(Token *tokens) {
|
ASTNode *parse_statement(Token *tokens) {
|
||||||
if (tokens[pos].type == TOK_ID) {
|
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;
|
char *name = tokens[pos].value;
|
||||||
pos++; // consumir ID
|
pos++; // consumir ID
|
||||||
pos++; // consumir "="
|
pos++; // consumir "="
|
||||||
@@ -120,23 +157,6 @@ ASTNode *parse_statement(Token *tokens) {
|
|||||||
node->data.assign.value = value;
|
node->data.assign.value = value;
|
||||||
return node;
|
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) {
|
if (tokens[pos].type == TOK_WHILE) {
|
||||||
pos++; // consumir 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);
|
ast_print(node->data.binop.right, new_prefix, 1);
|
||||||
break;
|
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:
|
case NODE_BLOCK:
|
||||||
printf("NODE_BLOCK\n");
|
printf("NODE_BLOCK\n");
|
||||||
for (int i = 0; i < node->data.block.count; i++) {
|
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);
|
ast_print(node->data.while_loop.body, new_prefix, 1);
|
||||||
break;
|
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:
|
default:
|
||||||
printf("UNKNOWN\n");
|
printf("UNKNOWN\n");
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -83,7 +83,8 @@ size_t eval(ASTNode *node, Environment *env, void *allocator, int debug,
|
|||||||
l->data.string_val.length);
|
l->data.string_val.length);
|
||||||
|
|
||||||
// Copy right text
|
// 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);
|
r->data.string_val.length);
|
||||||
tempBuff[n] = '\0';
|
tempBuff[n] = '\0';
|
||||||
|
|
||||||
@@ -145,6 +146,31 @@ size_t eval(ASTNode *node, Environment *env, void *allocator, int debug,
|
|||||||
}
|
}
|
||||||
break;
|
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:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user