JSFiddle - React, Tailwind, and code Playground
by malikzh
HTML
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.bundle.min.js"></script>
<div class="container" style="padding-bottom: 200px;">
<h2 class="text-center">
Стек и обратная польская запись
</h2>
<div class="row mt-4">
<div class="col-6">
Выражение:
<form action="#" id="expr-form">
<div class="row mt-2">
<div class="col-7">
<input type="text" class="form-control" name="expr" value="5 + 4 * (6 - 2) / 2">
</div>
<div class="col-5">
<button type="submit" class="btn btn-success btn-block">
Начать
</button>
</div>
</div>
</form>
<div class="alert alert-danger mt-4" style="display: none;" id="err">
Ошибка в выражении.
</div>
<div class="row mt-4">
<div class="col-12">
<p>Обратная польская запись:</p>
<input id="rpn" type="text" readonly class="form-control">
</div>
</div>
<div class="row mt-4">
<div class="col-12">
<p>Команды:</p>
<div id="instructions">
</div>
</div>
</div>
</div>
<div class="col-6">
<p>
Стек:
</p>
<div id="stack">
</div>
</div>
</div>
</div>
CSS
#instructions > div {
border: 1px solid #ccc;
background: #FAFAFA;
margin-bottom: 4px;
padding: 5px 4px;
}
#instructions > div.current {
background-color: #fffacf;
}
#stack > div {
border: 1px solid #ccc;
background: #FAFAFA;
margin-bottom: 4px;
padding: 5px 4px;
}
#stack > div:last-of-type {
background-color: #fffacf;
}
JavaScript
///
/// Проверяет, является ли символ цифрой
///
function isDigit(c) {
return '0123456789'.indexOf(c) > -1;
}
///
/// Проверяет, является ли символ оператором
///
function isOp(c) {
return '()+-*/'.indexOf(c) > -1;
}
///
/// Функция токенайзер. Разбивает числа и операторы на отдельные элементы массива
///
function tokenize(sourceCode) {
let tokens = [];
let tmp = '';
let state = "wait"; // Переменная хранит в себе состояние
for (let i=0; i<sourceCode.length;) {
let c = sourceCode.charAt(i);
// Пропускаем пробелы
if (c === ' ' || c ==="\t" || c === "\n" || c === "\r") {
i++;
continue;
}
if (state === 'wait') {
if (isDigit(c)) {
state = 'num'
tmp += c;
++i;
continue;
}
if (isOp(c)) {
tokens.push(c);
++i;
continue;
}
} else if (state === 'num') {
if (isDigit(c)) {
tmp += c;
++i;
continue;
} else {
if (tmp !== "") {
tokens.push(parseInt(tmp))
tmp = '';
}
state = 'wait';
continue;
}
} else {
return null;
}
}
if (state === 'num' && tmp.length > 0) {
tokens.push(parseInt(tmp))
tmp = '';
}
return tokens;
}
// Алгоритм конвертации в обратную польскую запись (RPN)
function toRpn(tokens) {
let result = [];
let stack = [];
for (let i=0; i<tokens.length; ++i) {
if ((typeof tokens[i]) === 'number') {
result.push(tokens[i]);
}
else if (tokens[i] === '(') {
stack.push(tokens[i]);
}
else if (tokens[i] === ')') {
let t = stack.pop();
while(t !== '(' && stack.length > 0) {
result.push(t);
t = stack.pop();
}
}
else if (isOp(tokens[i])) {
while (stack.length > 0 && "*/".indexOf(stack[stack.length - 1]) > -1) {
result.push(stack.pop());
}
stack.push(tokens[i]);
}
}
do {
let t = stack.pop();
...