This commit is contained in:
Ilya Bezrukov 2024-10-15 20:35:50 +03:00
commit 652d7cd7f0
2 changed files with 248 additions and 0 deletions

35
Makefile Normal file
View File

@ -0,0 +1,35 @@
CC := gcc
CFLAGS := -Wall
LDFLAGS :=
INCLUDE := -I include
EXENAME := nrr
OBJ := obj
BIN := bin
SOURCES := main.c
OBJECTS := $(addprefix $(OBJ)/, $(SOURCES:.c=.o))
TARGET := $(BIN)/$(EXENAME)
all: $(TARGET)
run: $(TARGET)
@./$(TARGET)
$(TARGET): $(OBJECTS) | $(BIN)
$(CC) $(CFLAGS) $(INCLUDE) $(OBJECTS) -o $(TARGET) $(LDFLAGS)
$(OBJ)/%.o: %.c | $(OBJ)
$(CC) $(CFLAGS) $(INCLUDE) -c $< -o $@
$(BIN):
@mkdir -p $(BIN)
$(OBJ):
@mkdir -p $(OBJ)
clean:
@rm -rf $(BIN) $(OBJ)
.PHONY: all clean run

213
main.c Normal file
View File

@ -0,0 +1,213 @@
/*
E ::= UT{+T}{-T}
T ::= F{*F}{/F}
F ::= (E)|i
U ::= -|+|_
'_' stands for empty sequence
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#define fatal(...) {\
fprintf(stderr, "\nError at char %d\n", number);\
fprintf(stderr, "%s\n", line);\
for (int i = 0; i < number - 1; i++)\
fputc(' ', stderr);\
fprintf(stderr, "^\nMessage: ");\
fprintf(stderr, __VA_ARGS__);\
exit(1);\
}
typedef enum _NodeType {
NNUM = 1,
NOP = 2
} NodeType;
typedef struct _Node Node;
struct _Node {
Node *parent;
Node *left;
Node *right;
NodeType type;
int number;
char operator; // + - * / m p
};
Node *e();
Node *t();
Node *f();
Node *u();
char line[1024];
int symbol;
int number = 0;
void scan();
int LRN(Node *node);
int main(int argc, char* argv[]) {
memset(line, 0, 1024);
scan();
Node *root = e();
if (symbol != '\n') {
fatal("Syntax invalid\n");
}
printf("Success\n");
printf("Answer: %d\n", LRN(root));
return 0;
}
void scan() {
symbol = getchar();
if (symbol == '\n')
line[number++] = ' ';
else
line[number++] = symbol;
}
Node *e() {
Node *left, *right, *root;
root = u();
left = t();
if (root != NULL) {
root->left = left;
left = root;
}
while (symbol == '+' || symbol == '-') {
root = calloc(sizeof(Node), 1);
root->type = NOP;
root->operator = symbol;
scan();
right = t();
root->left = left;
root->right = right;
left->parent = root;
right->parent = root;
left = root;
right = NULL;
}
return root;
}
Node *t() {
Node *left, *right, *root;
root = left = f();
while (symbol == '*' || symbol == '/') {
root = calloc(sizeof(Node), 1);
root->type = NOP;
root->operator = symbol;
scan();
right = f();
root->left = left;
root->right = right;
left->parent = root;
right->parent = root;
left = root;
right = NULL;
}
return root;
}
Node *f() {
Node *node;
if (symbol == '(') {
scan();
node = e();
if (symbol != ')') {
fatal("Expected parentheses, found '%c'\n", symbol);
}
}
else if (symbol < '0' || symbol > '9') {
if (symbol == '\n') {
fatal("LF too early\n");
}
else {
fatal("Unexpected symbol '%c'\n", symbol);
}
}
else {
node = calloc(sizeof(Node), 1);
node->type = NNUM;
node->number = (int) (symbol - '0');
}
scan();
return node;
}
Node *u() {
if (symbol == '-' || symbol == '+') {
Node *node = calloc(sizeof(Node), 1);
node->type = NOP;
node->operator = (symbol == '+') ? 'p' : 'm';
scan();
return node;
}
return NULL;
}
int LRN(Node *node) {
int l, r, answer;
if (node == NULL)
return 0;
if (node->left != NULL)
l = LRN(node->left);
if (node->right != NULL)
r = LRN(node->right);
if (node->type == NOP) {
switch (node->operator) {
case '+':
answer = l + r; break;
case '-':
answer = l - r; break;
case '*':
answer = l * r; break;
case '/':
answer = l / r; break;
case 'm':
answer = -l; break;
case 'p':
answer = +l; break;
default:
fatal("Invalid operator indentifier: '%c'\n", node->operator); break;
}
}
else if (node->type == NNUM) {
answer = node->number;
}
else {
answer = 0;
}
free(node);
return answer;
}