]]> ]]>
Править | Обсудить | История

Whitespace

Дата создания:
01 апреля 2003
Парадигма:
Типизация:
Принятые расширения файлов:
.ws
Реализации и версии (свернуть все | развернуть все):
Язык программирования

Whitespace — популярный эзотерический язык программирования, известный тем, что исходный код программы состоит только из непечатаемых символов.

Whitespace был создан в 2003 году Эдвином Брейди (Edwin Brady) и Крисом Моррисом (Chris Morris). Его спецификации достаточно просты, а сам язык не имеет практической ценности, поэтому авторское описание является единственным стандартом. Язык не породил диалектов, т.к. он сам по себе совершенен в своем роде.

Whitespace был создан как компенсация несправедливости по отношению к непечатаемым символам. Большинство современных языков их просто игнорирует, но ведь нечестно не принимать что-то во внимание лишь потому, что его не видно! Поэтому новый язык должен был игнорировать все символы, кроме невидимых. Видимые символы можно использовать в качестве комментариев, хотя при этом следует соблюдать осторожность и не вставить в комментариях лишний пробел или перевод строки. Написание кода на этом языке возможно либо в шестнадцатеричном редакторе, либо в среде разработки, которая обозначает пробелы и знаки табуляции видимым образом.

Все команды языка состоят из трех типов символов: пробел (Space, ASCII 32), табуляция (Tab, ASCII 9) и новая строка (LF, ASCII 10). Сами команды довольно длинные (обычно 3-4 символа), и их немало; они систематизированы посредством использования префикса (т.н. параметр модификации инструкции), который обозначает тип команды: операции со стеком, арифметика, доступ к куче, управление потоком выполнения программы, ввод/вывод.

Виртуальная машина языка оснащена стеком и кучей, которые могут обрабатывать целые числа произвольной разрядности. Стек используется для выполнения команд, а куча играет роль хранилища данных.

В языке используется только один тип данных — целые числа в двоичном представлении. Число начинается с задания его знака (Space — положительное, Tab — отрицательное), затем следует двоичная запись абсолютного значения числа (Space — 0, Tab — 1) и LF, сигнализирующий о конце числа.

Метка — это произвольный список пробелов и знаков табуляции, оканчивающийся переводом строки. Метки используются в управлении потоком выполнения программы, и должны быть уникальны в пределах программы.

Команды языка (сгруппированы по типу):

Операции со стеком

  • Space-Space-Number : добавить число в стек
  • Space-LF-Space : продублировать число на вершине стека
  • Space-LF-Tab : поменять местами два верхних элемента стека
  • Space-LF-LF : извлечь из стека верхний элемент и выбросить его
  • Space-Tab-Space-Number : скопировать N-ый элемент стека (индекс задается аргументом) на вершину стека
  • Space-Tab-LF-Number : “сдвинуть” со стека N элементов, сохраняя при этом верхний

Две последние команды — расширение, доступное с версии Whitespace 0.3, предназначенное для упрощения работы с рекурсивными функциями.

Арифметика

  • Tab-Space-Space-Space : сложение
  • Tab-Space-Space-Tab : вычитание
  • Tab-Space-Space-LF : умножение
  • Tab-Space-Tab-Space : деление (целочисленное)
  • Tab-Space-Tab-Tab : остаток от деления

Операция применяется к двум верхним элементам стека. Левым операндом считается более ранний элемент стека (добавленный первым).

Доступ к куче

  • Tab-Tab-Space : сохранить верхний элемент стека в ячейке памяти, адрес которой задан во втором сверху элементе
  • Tab-Tab-Tab : извлечь содержимое ячейки памяти, адрес которой задан в верхнем элементе стека, и поместить его на вершину стека

Управление потоком выполнения программы

  • LF-Space-Space-Label : создать метку
  • LF-Space-Tab-Label : вызвать подпрограмму
  • LF-Space-LF-Label : перейти к метке
  • LF-Tab-Space-Label : перейти к метке, если верхний элемент стека равен нулю
  • LF-Tab-Tab-Label : перейти к метке, если верхний элемент стека отрицателен
  • LF-Tab-LF : закончить подпрограмму и передать управление вызвавшей ее программе
  • LF-LF-LF : закончить программу

Ввод/вывод

  • Tab-LF-Space-Space/Tab : вывести верхний элемент стека на печать как символ/число
  • Tab-LF-Tab-Space/Tab : прочитать из потока символ/число и сохранить его в ячейку памяти, адрес которой задан в верхнем элементе стека

Следует отметить, что при использовании элементов стека в выполнении команд в большинстве случаев они удаляются из стека.

Примеры:

Hello, World!:

Пример для версий Whitespacers (Ruby)

Для простоты понимания код откомментирован: буква означает, что следующий фрагмент кода добавляет в стек ASCII-код этой буквы, а после print следует команда вывода верхнего элемента стека на печать как символа. Последовательности символов, задающие ASCII-коды, заключены в фигурные скобки (за исключением перевода строки).

H  { 	  	   }
print	
  e  { 		  	 	}
print	
  l  { 		 		  }
print	
  l  { 		 		  }
print	
  o  { 		 				}
print	
  ,  { 	 		  }
print	
  space  { 	     }
print	
  W  { 	 	 			}
print	
  o  { 		 				}
print	
  r  { 			  	 }
print	
  l  { 		 		  }
print	
  d  { 		  	  }
print	
  !  { 	    	}
print	
  \n  { 	 	 }
print	
  


end

Факториал:

Пример для версий Whitespacers (Ruby)

В этом примере используется другой метод комментирования — каждая команда предваряется ее словесным описанием. Числа и метки, кроме заключительного переноса строки, заключены в скобки.

Куча используется для хранения переменных: 1 — первое число, факториал которого не нужен, 2..5 — ASCII-коды символов, используемых при выводе на печать, 6 и 7 — текущее число и его факториал. Сам факториал вычисляется итеративно: на каждой итерации печатаются ранее вычисленное число и факториал, затем вычисляются и заносятся в память новые. После этого, новое число (ячейка 6) сравнивается с ячейкой 1: если число меньше, цикл повторяется, иначе прекращается.

Интересо, что в Whitespace ноль “отрицательный”: число должно содержать в записи хотя бы один Tab, в двоичной записи нуля единиц нет, поэтому приходится задавать знаковый бит и записывать ноль как Tab-LF.

push_1  { 	}
push_17  { 	   	}
store		 push_2  { 	 }
push_33  { 	    	}
store		 push_3  { 		}
push_32  { 	     }
store		 push_4  { 	  }
push_61  { 				 	}
store		 push_5  { 	 	}
push_10  { 	 	 }
store		 push_6  { 		 }
push_0  {	 }
store		 push_7  { 			}
push_1  { 	}
store		 label
  { }
printing_block_push_6  { 		 }
retrieve			print_as_number	
 	push_2  { 	 }
retrieve			print_as_char	
  push_3  { 		}
retrieve			print_as_char	
  push_4  { 	  }
retrieve			print_as_char	
  push_3  { 		}
retrieve			print_as_char	
  push_7  { 			}
retrieve			print_as_number	
 	push_5  { 	 	}
retrieve			print_as_char	
  increase_counter_block_push_6  { 		 }
push_6  { 		 }
retrieve			push_1  { 	}
add	   store		 calculate_next_factorial_block_push_7  { 			}
push_7  { 			}
retrieve			push_6  { 		 }
retrieve			multiply	  
store		 conditional_return_block_push_6  { 		 }
retrieve			push_1  { 	}
retrieve			subtract	  	jump_if_negative
		{ }
quit


end

Числа Фибоначчи:

Пример для версий Whitespacers (Ruby)

Пример работает аналогично факториалу, но интенсивнее использует хранение данных в стеке и команду копирования верхнего элемента стека, чтобы избежать лишних обращений к памяти. Кроме того, в этом примере счетчик отрицательный и увеличивается на каждой итерации.

push_1  { 	}
push_-16  {		    }
store		 push_2  { 	 }
push_44  { 	 		  }
store		 push_3  { 		}
push_32  { 	     }
store		 push_4  { 	  }
push_0  {	 }
store		 push_5  { 	 	}
push_1  { 	}
store		 label
  { }
start_loop_push_5  { 	 	}
push_4  { 	  }
retrieve			push_4  { 	  }
duplicate 
 push_5  { 	 	}
retrieve			duplicate 
 print_as_number	
 	push_2  { 	 }
retrieve			print_as_char	
  push_3  { 		}
retrieve			print_as_char	
  store		 retrieve			add	   store		 push_1  { 	}
duplicate 
 duplicate 
 duplicate 
 retrieve			add	   store		 retrieve			jump_if_negative
		{ }
push_10  { 	 	 }
push_46  { 	 			 }
duplicate 
 duplicate 
 print_as_char	
  print_as_char	
  print_as_char	
  print_as_char	
  quit


end

CamelCase:

Пример для версий Whitespacers (Ruby)
push-1  { 	}
push-1  { 	}
save		 LOOP-START.label-0
  { }
push-2  { 	 }
readchar	
	 push-2  { 	 }
load			CHECK-WHETHER-IS-EOL.duplicate 
 push-10  { 	 	 }
subtract	  	if-0-goto-1
	 {	}
CONVERT-TO-LOWERCASE.duplicate 
 push-A  { 	     	}
subtract	  	if-neg-goto-2
		{	 }
duplicate 
 push-Z  { 	 		 	 }
swap 
	subtract	  	if-neg-goto-2
		{	 }
push-32  { 	     }
add	   label-2
  {	 }
CHECK-WHETHER-IS-LETTER.duplicate 
 push-a  { 		    	}
subtract	  	if-neg-goto-3
		{		}
duplicate 
 push-z  { 				 	 }
swap 
	subtract	  	if-neg-goto-3
		{		}
ACTION-IF-LETTER.CHECK-WHETHER-LAST-WAS-SPACE.push-1  { 	}
load			if-0-goto-4
	 {	  }
push-32  { 	     }
subtract	  	label-4
  {	  }
print	
  push-1  { 	}
push-0  {	 }
save		 goto-0
 
{ }
label-3
  {		}
ACTION-IF-NOT-LETTER.push-1  { 	}
push-1  { 	}
save		 goto-0
 
{ }
label-1
  {	}
push-10  { 	 	 }
print	
  


end.memory:1-was-last-space,2-currentchar

Комментарии

]]>

blog comments powered by Disqus

]]>

Работа программистам