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();
   ...