diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..710d2ee --- /dev/null +++ b/Makefile @@ -0,0 +1,15 @@ +CC = gcc +CFLAGS = -Wall -Wextra -std=c99 +SRCS = src/main.c src/lexer.c src/parser.c src/interpreter.c +OBJS = $(SRCS:.c=.o) +EXEC = uzbeklang + +all: $(EXEC) + +$(EXEC): $(OBJS) + $(CC) $(CFLAGS) -o $(EXEC) $(OBJS) + +clean: + rm -f $(OBJS) $(EXEC) + +.PHONY: all clean diff --git a/examples/uzbeklang.uzb b/examples/uzbeklang.uzb new file mode 100644 index 0000000..6c6e9c6 --- /dev/null +++ b/examples/uzbeklang.uzb @@ -0,0 +1,3 @@ +Yoz "Mening ismim" +Yoz 14 +Qosh 14 53; \ No newline at end of file diff --git a/src/interpreter.c b/src/interpreter.c new file mode 100644 index 0000000..c95127e --- /dev/null +++ b/src/interpreter.c @@ -0,0 +1,38 @@ +#include +#include "interpreter.h" + +void interpret(ASTNode *node) { + if (!node) return; + + switch (node->type) { + case AST_PRINT: + interpret(node->left); + break; + case AST_ADD: { + ASTNode *left = node->left; + ASTNode *right = node->right; + if (left->type == AST_NUMBER && right->type == AST_NUMBER) { + int result = atoi(left->value) + atoi(right->value); + printf("%d\n", result); + } + break; + } + case AST_SUB: { + ASTNode *left = node->left; + ASTNode *right = node->right; + if (left->type == AST_NUMBER && right->type == AST_NUMBER) { + int result = atoi(left->value) - atoi(right->value); + printf("%d\n", result); + } + break; + } + case AST_NUMBER: + printf("%s\n", node->value); + break; + case AST_STRING: + printf("%s\n", node->value); + break; + default: + break; + } +} diff --git a/src/interpreter.h b/src/interpreter.h new file mode 100644 index 0000000..2a53302 --- /dev/null +++ b/src/interpreter.h @@ -0,0 +1,8 @@ +#ifndef INTERPRETER_H +#define INTERPRETER_H + +#include "parser.h" + +void interpret(ASTNode *node); + +#endif \ No newline at end of file diff --git a/src/interpreter.o b/src/interpreter.o new file mode 100644 index 0000000..8ffb547 Binary files /dev/null and b/src/interpreter.o differ diff --git a/src/lexer.c b/src/lexer.c new file mode 100644 index 0000000..581d19a --- /dev/null +++ b/src/lexer.c @@ -0,0 +1,118 @@ +#include +#include +#include +#include +#include "lexer.h" + +Lexer *init_lexer(char *source) { + Lexer *lexer = (Lexer *)malloc(sizeof(Lexer)); + lexer->source = source; + lexer->length = strlen(source); + lexer->pos = 0; + return lexer; +} + +void free_lexer(Lexer *lexer) { + free(lexer); +} + +Token *create_token(TokenType type, char *value) { + Token *token = (Token *)malloc(sizeof(Token)); + token->type = type; + token->value = value; + return token; +} + +void free_token(Token *token) { + if (token->value) free(token->value); + free(token); +} + +char peek(Lexer *lexer) { + if (lexer->pos < lexer->length) { + return lexer->source[lexer->pos]; + } + return '\0'; +} + +char advance(Lexer *lexer) { + lexer->pos++; + return peek(lexer); +} + +void skip_whitespace(Lexer *lexer) { + while (isspace(peek(lexer))) { + advance(lexer); + } +} + +Token *get_next_token(Lexer *lexer) { + skip_whitespace(lexer); + + char current = peek(lexer); + + if (current == '\0') { + return create_token(TOKEN_EOF, NULL); + } + + if (isalpha(current)) { + size_t start = lexer->pos; + while (isalpha(peek(lexer))) advance(lexer); + + size_t length = lexer->pos - start; + char *value = (char *)malloc(length + 1); + strncpy(value, lexer->source + start, length); + value[length] = '\0'; + + if (strcmp(value, "Yoz") == 0) return create_token(TOKEN_PRINT, value); + if (strcmp(value, "Qosh") == 0) return create_token(TOKEN_ADD, value); + if (strcmp(value, "Ayir") == 0) return create_token(TOKEN_SUB, value); + + return create_token(TOKEN_ID, value); + } + + if (isdigit(current)) { + size_t start = lexer->pos; + while (isdigit(peek(lexer))) advance(lexer); + + size_t length = lexer->pos - start; + char *value = (char *)malloc(length + 1); + strncpy(value, lexer->source + start, length); + value[length] = '\0'; + + return create_token(TOKEN_NUMBER, value); + } + + if (current == '\"') { + advance(lexer); // Skip the opening quote + size_t start = lexer->pos; + + while (peek(lexer) != '\"' && peek(lexer) != '\0') advance(lexer); + + size_t length = lexer->pos - start; + char *value = (char *)malloc(length + 1); + strncpy(value, lexer->source + start, length); + value[length] = '\0'; + + advance(lexer); // Skip the closing quote + + return create_token(TOKEN_STRING, value); + } + + if (current == '(') { + advance(lexer); + return create_token(TOKEN_LPAREN, strdup("(")); + } + + if (current == ')') { + advance(lexer); + return create_token(TOKEN_RPAREN, strdup(")")); + } + + if (current == ';') { + advance(lexer); + return create_token(TOKEN_SEMICOLON, strdup(";")); + } + + return create_token(TOKEN_ERROR, NULL); +} diff --git a/src/lexer.h b/src/lexer.h new file mode 100644 index 0000000..1e851f0 --- /dev/null +++ b/src/lexer.h @@ -0,0 +1,34 @@ +#ifndef LEXER_H +#define LEXER_H + +typedef enum { + TOKEN_EOF, + TOKEN_ID, + TOKEN_STRING, + TOKEN_NUMBER, + TOKEN_PRINT, + TOKEN_ADD, + TOKEN_SUB, + TOKEN_LPAREN, + TOKEN_RPAREN, + TOKEN_SEMICOLON, + TOKEN_ERROR +} TokenType; + +typedef struct { + TokenType type; + char *value; +} Token; + +typedef struct { + char *source; + size_t length; + size_t pos; +} Lexer; + +Lexer *init_lexer(char *source); +Token *get_next_token(Lexer *lexer); +void free_lexer(Lexer *lexer); +void free_token(Token *token); + +#endif \ No newline at end of file diff --git a/src/lexer.o b/src/lexer.o new file mode 100644 index 0000000..cfec31c Binary files /dev/null and b/src/lexer.o differ diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..90d0eff --- /dev/null +++ b/src/main.c @@ -0,0 +1,70 @@ +#include +#include +#include "lexer.h" +#include "parser.h" +#include "interpreter.h" + +void run_repl() { + char input[256]; + + printf("UzbekLang dasturiga xush kelibsiz!\n"); + + while (1) { + printf(">> "); + if (!fgets(input, sizeof(input), stdin)) break; + if (strncmp(input, "exit", 4) == 0) break; + + Lexer *lexer = init_lexer(input); + Parser *parser = init_parser(lexer); + ASTNode *root = parse(parser); + + interpret(root); + + free_ast(root); + free_parser(parser); + free_lexer(lexer); + } +} + +void run_file(const char *filename) { + FILE *file = fopen(filename, "r"); + if (!file) { + fprintf(stderr, "Faylni ochib bo'lmadi: %s\n", filename); + exit(1); + } + + fseek(file, 0, SEEK_END); + long length = ftell(file); + fseek(file, 0, SEEK_SET); + + char *input = (char *)malloc(length + 1); + if (!input) { + fprintf(stderr, "Xotirani ajratib bo'lmadi\n"); + exit(1); + } + + fread(input, 1, length, file); + input[length] = '\0'; + fclose(file); + + Lexer *lexer = init_lexer(input); + Parser *parser = init_parser(lexer); + ASTNode *root = parse(parser); + + interpret(root); + + free_ast(root); + free_parser(parser); + free_lexer(lexer); + free(input); +} + +int main(int argc, char **argv) { + if (argc == 2) { + run_file(argv[1]); + } else { + run_repl(); + } + + return 0; +} diff --git a/src/main.o b/src/main.o new file mode 100644 index 0000000..454da24 Binary files /dev/null and b/src/main.o differ diff --git a/src/parser.c b/src/parser.c new file mode 100644 index 0000000..0da5d9d --- /dev/null +++ b/src/parser.c @@ -0,0 +1,123 @@ +#include +#include +#include "parser.h" + +Parser *init_parser(Lexer *lexer) { + Parser *parser = (Parser *)malloc(sizeof(Parser)); + parser->lexer = lexer; + parser->current_token = get_next_token(lexer); + return parser; +} + +void free_parser(Parser *parser) { + free_token(parser->current_token); + free(parser); +} + +void free_ast(ASTNode *node) { + if (node) { + if (node->value) free(node->value); + free_ast(node->left); + free_ast(node->right); + free(node); + } +} + +Token *consume(Parser *parser, TokenType type) { + if (parser->current_token->type == type) { + Token *token = parser->current_token; + parser->current_token = get_next_token(parser->lexer); + return token; + } + return NULL; +} + +ASTNode *parse_number(Parser *parser) { + Token *token = consume(parser, TOKEN_NUMBER); + if (token) { + ASTNode *node = (ASTNode *)malloc(sizeof(ASTNode)); + node->type = AST_NUMBER; + node->value = token->value; + node->left = NULL; + node->right = NULL; + free(token); + return node; + } + return NULL; +} + +ASTNode *parse_string(Parser *parser) { + Token *token = consume(parser, TOKEN_STRING); + if (token) { + ASTNode *node = (ASTNode *)malloc(sizeof(ASTNode)); + node->type = AST_STRING; + node->value = token->value; + node->left = NULL; + node->right = NULL; + free(token); + return node; + } + return NULL; +} + +ASTNode *parse_expression(Parser *parser) { + if (parser->current_token->type == TOKEN_NUMBER) { + return parse_number(parser); + } else if (parser->current_token->type == TOKEN_STRING) { + return parse_string(parser); + } else { + return NULL; + } +} + +ASTNode *parse_print(Parser *parser) { + consume(parser, TOKEN_PRINT); + ASTNode *expr = parse_expression(parser); + consume(parser, TOKEN_SEMICOLON); + ASTNode *node = (ASTNode *)malloc(sizeof(ASTNode)); + node->type = AST_PRINT; + node->value = NULL; + node->left = expr; + node->right = NULL; + return node; +} + +ASTNode *parse_add(Parser *parser) { + consume(parser, TOKEN_ADD); + ASTNode *left = parse_expression(parser); + ASTNode *right = parse_expression(parser); + consume(parser, TOKEN_SEMICOLON); + ASTNode *node = (ASTNode *)malloc(sizeof(ASTNode)); + node->type = AST_ADD; + node->value = NULL; + node->left = left; + node->right = right; + return node; +} + +ASTNode *parse_sub(Parser *parser) { + consume(parser, TOKEN_SUB); + ASTNode *left = parse_expression(parser); + ASTNode *right = parse_expression(parser); + consume(parser, TOKEN_SEMICOLON); + ASTNode *node = (ASTNode *)malloc(sizeof(ASTNode)); + node->type = AST_SUB; + node->value = NULL; + node->left = left; + node->right = right; + return node; +} + +ASTNode *parse(Parser *parser) { + TokenType type = parser->current_token->type; + + if (type == TOKEN_PRINT) { + return parse_print(parser); + } else if (type == TOKEN_ADD) { + return parse_add(parser); + } else if (type == TOKEN_SUB) { + return parse_sub(parser); + } else { + return NULL; + } +} diff --git a/src/parser.h b/src/parser.h new file mode 100644 index 0000000..059a966 --- /dev/null +++ b/src/parser.h @@ -0,0 +1,31 @@ +#ifndef PARSER_H +#define PARSER_H + +#include "lexer.h" + +typedef enum { + AST_PRINT, + AST_ADD, + AST_SUB, + AST_NUMBER, + AST_STRING +} ASTNodeType; + +typedef struct ASTNode { + ASTNodeType type; + char *value; + struct ASTNode *left; + struct ASTNode *right; +} ASTNode; + +typedef struct { + Lexer *lexer; + Token *current_token; +} Parser; + +Parser *init_parser(Lexer *lexer); +ASTNode *parse(Parser *parser); +void free_parser(Parser *parser); +void free_ast(ASTNode *node); + +#endif diff --git a/src/parser.o b/src/parser.o new file mode 100644 index 0000000..1926789 Binary files /dev/null and b/src/parser.o differ