программирование

Хардлинки в WinXP

Я очень часто начинаю разрабатывать проект под Windows и заканчиваю — под Linux или freeBSD. Конечно, даже на уровне PHP, между этими группами операционных систем есть существенные различия. Обычно, они легко преодолеваются. В последнем проекте мне более всего не хватало функции link.

Поэкспериментировав с w32api и ffi, я понял, что этот путь — тупиковый. Побродив по поисковикам, я выяснил, что простейший выход — использовать в качестве заглушки утилиту fsutil из Windows XP. У неё есть параметр «hardlink create», позволяющий создавать ссылки.

if (PHP_OS == 'WINNT' && file_exists($_ENV['windir'].'\system32\fsutil.exe'))
{
    function link($target, $link)
    {
        $cmd = $_ENV['windir'].'\system32\fsutil.exe hardlink create';
        exec ($cmd.' "'.$link.'" "'.$target, $out, $ret);

        return !$ret;
    }
}

В случае, если вы будете использовать эту функцию в проекте, будьте осторожны — это всего лишь заглушка. Во-первых, одна ссылка создаётся примерно за 0.6 — 1сек, во-вторых, в ней нет проверки на наличие специальных символов в переменных $target и $link — если там попадётся кавычка, возникнет опасность внедрения вредоносного кода.

Оставить комментарий

LANG

«Его пример — другим наука». Господа, если при попытки инсталляции модуля для Perl, вы встретите сообщение вида «Makefile:85: *** missing separator. Stop.», не отчаивайтесь, а посмотрите значение переменной LANG. Её значение должно быть «en_US». Скорее всего у вас там «UTF8», измените его на «en_US» (обычно «export LANG en_US») и попробуйте установить модуль ещё раз.

Оставить комментарий

Как повалить PHP

Статья «Top 10 ways to crash PHP». Язык — английский, но примеры, которые там приведены, поймёт любой PHP-программист. Кстати, первый из них я приводил на старой версии сайта. Интересно, все ли способы работают в PHP 5.

Оставить комментарий

GIF в GD

Веб-разработчикам должно быть интересно: некоторое время назад вышла новая версия GD — 2.0.28. Главная особенность новой версии — поддержка формата GIF (чтение и запись).

Как известно, поддержка GIF была удалена из GD ещё в версии 1.6 в связи с тем, что алгоритм LZW, используемый в GIF оказался патентованным. После истечения срока действия патента, GD снова поддерживает GIF.

Оставить комментарий

Недокументированная debug_zval_dump

Кстати, одна из недокументированных функций PHP:

void debug_zval_dump(mixed var) Dumps a string representation of an internal zend value to output

Например, «debug_zval_dump(true)» выдаёт: «bool(true) refcount(1)»

Оставить комментарий

Вложенные запросы в MySQL

В интернете есть слухи о вложенных запросах в MySQL 3.xx. Кто-нибудь может подтвердить или опровергнуть? Вообще, мне верится достаточно легко. Вполне может быть, что разрабочики MySQL, как это у них обычно водится, решили приделать очередной костыль. Но передумали.

Оставить комментарий

99 бутылок: Refal-5, FOCAL

40. Refal. Литературы по этому языку достаточно, так что, если возникнет заинтересованность — поищите в интернете. Пожалуй, описывать я его не буду, лишь приведу небольшую выдержку из учебника.

«Рефал» — язык манипулирования символьными объектам: текстами, формулами, программами и т. п. Программа на «Рефале» состоит из функций, которые могут определяться друг через друга, т. е. рекурсивно. Отсюда и название: «Алгоритмический язык Рекурсивных Функций». Язык «Рефал» был создан В. Турчиным в качестве метаязыка для описания семантики других языков. Язык определения функций «Рефала», основанный на понятиях образца и результатного выражения, чрезвычайно прост и компактен. Образцы — […] в сжатой и наглядной форме обеспечивают как запись условий на вид аргумента, так и разбиение аргумента на составные части.

Программа, выводящая песню о пиве (beer.ref):

** Beer song. Written by Evgeny Stepanischev

Pr   {
     e1 = <PRINTLN! *STDOUT e1>;
     };

S    {
     1  = ;
     e1 = 's';
     };

Beer {
     0 = 'No bottles of beer';
     e1, <S e1>: e2 = e1 ' bottle' e2 ' of beer';
     };

Beers
    {
    e1 (e2), <Beer e1>: e.beer =
        <Pr e.beer ' on the wall, ' e.beer '.'>
        <Pr 'Take one and pass around,'>
        <Pr <Beer e2> ' on the wall.'>
        <Pr>;
    };

Start
    {
    0  = <Pr 'No more bottles of beer...'>
         <Pr 'Go to the store and buy some more...'>
         <Pr '99 bottles of beer.'>;

    e1, <- e1 1>: e2  = <Beers e1 (e2)> <Start e2>;
    };

$EXEC Start 99;

41. FOCAL. Название языка произошло от сокращения «Formula CALculator». В настоящее время язык, можно сказать, умер — в интернете мне с большим трудом удалось найти его описание. Ни одной действующей версии компилятора или интерпретатора языка мне найти не удалось.

Что интересно в языке — нумерация строк. Она двойная. Строки организуют группы с внутренней нумерацией, к которым (группам) можно обращаться при помощи различных конструкций. Другая интересная особенность — все операторы можно сокращать. Например, вполне можно писать COMMENT как C, а FOR — как F.

Как я сказал, компилятора или интерпретатора мне найти не удалось, так что пришлось писать программу по теории. В частности, по скудной литературе мне не удалось понять как должна работать функция FSBR (вызов группы строк как функции), поэтому пришлось определять функции другим путём.

Уже после выхода этой песни, со мной связался Алексей Томин и привёл описание функции FSBR. Вот, что он пишет: FSBR позволяет определить функцию с одним аргументом (с использованием & как параметра). Самое интересное — возможна рекурсия.

Пример, вычисление факториала:

11.1 I (&-1) 11.3,11.3,11.2
11.2 S &=&*FSBR(11,&-1)
11.3 R

Программа, выводящая песню о пиве (beer)

1.10 COMMENT Beer song. Written by Evgeny Stepanischev
1.20 FOR I=99, -1, 1; DO 2
1.30 TYPE "No more bottles of beer...", !
1.40 TYPE "Go to the store and buy some more...", !
1.50 TYPE "99 bottles of beer.", !
1.60 QUIT

2.10 SET B=1; DO 3; TYPE " on the wall, "; DO 3
2.20 TYPE !, "Take one and pass around,", !
2.30 SET B=2; DO 3; TYPE " on the wall.", !

3.10 DO 4.10; TYPE " of beer"; RETURN

4.10 IF (I-B) 4.20, 4.30, 4.40
4.20 TYPE "No bottles"; RETURN
4.30 TYPE "1 bottle"; RETURN
4.40 TYPE %4.00, I, "bottles"; RETURN


Оставить комментарий

99 бутылок: XSLT и TBC

38. XSLT. Язык преобразований одного XML-документа в другой, основанный на XML же. Написано о нём достаточно много, так что останавливаться на нём не буду. Это, в отличие от большинства языков, на которых я программировал — декларативный язык. Строго говоря, XSLT мёртв без другого языка — XPath, языка выборки. С его помощью, например, выполняются все вычисления. В парсерах первых версий нет циклов, что кажется несколько странным, так что мне пришлось использовать рекурсию. Кстати, наиболее странное в XSLT другое — однажды объявленная переменная больше не может менять своего значения. Это ограничение обходят при помощи рекурсии и использования локальных переменных.

Запустить скрипт на выполнение можно, сохранив листинг в файл beer.xml и открыв его браузером Internet Explorer.

Программа, выводящая песню о пиве (beer.xml)

<?xml version="1.0"?>
<?xml-stylesheet type="text/xsl" href="#beer"?>

<!-- Beer song. Written by Evgeny Stepanischev -->

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
id="beer">
<xsl:output method="html"/>
<xsl:strip-space elements="*"/>

<xsl:template name="beer">
  <xsl:param name="n"/>
  <xsl:choose>
    <xsl:when test="boolean($n)">
      <xsl:value-of select="$n"/>
    </xsl:when>
    <xsl:otherwise>
      No
    </xsl:otherwise>
  </xsl:choose>
  <xsl:text> bottle</xsl:text>

  <xsl:if test="boolean($n - 1)">
    <xsl:text>s</xsl:text>
  </xsl:if>
</xsl:template>

<xsl:template name="while" match="/">
  <xsl:param name="i" select="99"/>
  <xsl:choose>
    <xsl:when test="$i != 0">
      <xsl:variable name="str">
        <xsl:call-template name="beer">
          <xsl:with-param name="n" select="$i"/>
        </xsl:call-template>
      </xsl:variable>

      <xsl:value-of select="$str"/>
      <xsl:text> on the wall, </xsl:text>
      <xsl:value-of select="$str"/>
      <xsl:text> of beer.</xsl:text><br />
      <xsl:text>Take one and pass around,</xsl:text><br />
      <xsl:call-template name="beer">
          <xsl:with-param name="n" select="$i - 1"/>
      </xsl:call-template>
      <xsl:text> on the wall.</xsl:text><br /><br />

      <xsl:call-template name="while">
        <xsl:with-param name="i" select="$i - 1"/>
      </xsl:call-template>
    </xsl:when>
    <xsl:otherwise>
      No more bottles of beer...<br />
      Go to the store and buy some more...<br />
      99 bottles of beer.
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>

</xsl:stylesheet>

39. TBC (Tokiwa BASIC Compiler). Эта бесплатная версия компилятора является урезанной версией коммерческого компилятора TWK-86BC и написал её японец Tokiwa.

Компилятор умеет компилировать код в COM и DOS EXE-файлы и интересен тем, что имеет интеграцию со встроенным ассемблером и довольно развитый интересный синтаксис, основанный на языке BASIC. Например, присутствует оператор DefInt, который сообщает компилятору, что переменные, начинающиеся с заданных оператором букв, имеют целочисленный тип.

Есть блочные конструкции, операторы обработки ошибок, выбора альтернативы (on … goto …), поддержка строк и меток, в связи с чем поддерживаются как обычные процедуры и функции, так и переходы по номерам строк. Предусмотрены операторы ввода-вывода для работы с устройствами DOS и файлами и многое другое.

Кстати, что неприятно удивило — возвращаемым значением для процедур и функций (кстати, можно сказать, что процедуры и функции тут различаются только ключевыми словами) может быть только числовое значение.

Программа, выводящая песню о пиве (beer.tkw)

* Beer song. Written by Evgeny Stepanischev

Integer I
Character S

For I=99 To 1 Step -1
    Call Beer(I)

    Print S; " on the wall, ";S;"."
    Print "Take one and pass around,"

    Call Beer(I-1)
    Print S; " on the wall." : Print
Next I

Print "No more bottles of beer..."
Print "Go to the store and buy some more..."
Print "99 bottles of beer."

SubRoutine Beer(I)
    Integer I

    If I=0 Then S="No" Else S=Str$(%1I I)
    S=S+" bottle"

    If I<>1 Then S=S+"s"

    S=S+" of beer"

    Return
SubEnd

End


Оставить комментарий

99 бутылок: NSIS, Photoshop JavaScript

Сериал «99 бутылок пива» продолжается. Сегодня — 36 и 37-я серии, на сцене языки программирования инсталлятора фирмы Nullsoft и JavaScript for Adobe Photoshop.

36. Nullsoft (SuperPiMP|Scriptable) Install System. NSIS — настраиваемый инсталлятор от компании «Nullsoft», позволяющий создать пакет для инсталляции и деинсталляции вашего собственного продукта. Выходной файл представляет собой обычную программу. Для сжатия данных NSIS может использовать алгоритмы Zip и Bzip2, так что весь код получается довольно компактным.

Весь процесс установки и удаления продукта описывается на собственном языке программирования, где есть опции управления внешним видом инсталлятора, команды использования внешних плагинов, поддержки нескольких языков, команды предпроцессора и собственно язык с поддержкой функций, секций, ветвления, файлового ввода-вывода. Язык поддерживает так же несложную обработку событий в виде callback-функций с зарезервированными именами.

Я использовал версию 2.0b2. Язык инсталлятора крайне простой, поэтому не поддерживает локальных переменных и параметров у пользовательских функций — вместо них приходится использовать глобальные пользовательские переменные (их 20 штук) или стек. Кстати, и параметры плагинам передаются именно через стек.

Все имена переменных начинаются с доллара, программист для своих собственных целей может использовать лишь двадцать переменных — $0..$9, $R0..$R9, переменные не типизированы, в строках выполняется интерполяция, в качестве ограничителей строк подходят любые кавычки. Ветвление выполняется командами сравнения, которые в качестве аргумента принимают три ссылки, по одной из которых происходит переход в зависимости от результата сравнения.

Операции с числами так же выглядят несколько неожиданно. Вообще, даже прочитав полностью документацию, без примеров достаточно просто оставить без внимания некоторые возможности, которые становятся очевидными при просмотре примеров. Так что будете писать инсталлятор для своего продукта — загляните ещё и в примеры.

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

Программа, выводящая песню о пиве (beer.nsi)

; Beer song.  Written by Evgeny Stepanischev
Name "Beer song"
Caption "Beer song"
OutFile "beer99.exe"
BrandingText "Beer song (Evgeny Stepanischev)"
ShowInstDetails show

!macro c
    StrCpy $2 ""
    Call PrintBeer
!macroend

Function PrintBeer
    IntCmp $1 0 no "" ""
    StrCpy $2 "$2$1"
    Goto +2
no:
    StrCpy $2 "$2No"
    StrCpy $2 "$2 bottle"
    IntCmp $1 1 nos "" ""
    StrCpy $2 "$2s"
nos:
    StrCpy $2 "$2 of beer"
FunctionEnd

Section ""
    StrCpy $1 99

loop:
    !insertmacro c
    StrCpy $2 "$2 on the wall, "
    Call PrintBeer
    DetailPrint "$2."
    DetailPrint "Take one and pass around,"
    IntOp $1 $1 - 1

    !insertmacro c
    DetailPrint "$2 on the wall."
    DetailPrint ""
    IntCmp $1 0 "" loop loop

    DetailPrint "No more bottles of beer..."
    DetailPrint "Go to the store and buy some more..."
    DetailPrint "99 bottles of beer."

SectionEnd

37. JavaScript for Adobe Photoshop (Photoshop 7.0 Scripting plug-in v.1.0.2a). В Adobe Photoshop с версии 7.0 появились полноценные скриптовые языки. Если верить руководству можно использовать три языка — JavaScript, VBScript и AppleScript.

Описывать JavaScript не интересно — базовые конструкции стандартные, добавлены лишь специфические объекты для управления всем тем, что есть в Photoshop, соответственно и объектная модель отличается от той, что принята, например, в браузерах.

Одним словом — полное управление всем, до чего можно дотянуться в бесконечных меню и опциях Adobe Photoshop (включая фильтры), из скриптового языка. Грандиозные возможности для дизайнеров, пробующих себя в программировании, или программистов, пытающихся заняться дизайном. :)

Программа, выводящая песню о пиве (beer.js)

preferences.rulerUnits = Units.POINTS
preferences.typeUnits  = TypeUnits.POINTS

var docRef = documents.add(640, 480)
displayDialogs = DialogModes.NO

var textColor = new SolidColor
textColor.rgb.red = textColor.rgb.green = textColor.rgb.blue  = 0

var TextLayer = docRef.artLayers.add()
TextLayer.kind = LayerKind.TEXT;

TextLayer.textItem.font     = "Tahoma"
TextLayer.textItem.position = Array(10, 10)
TextLayer.textItem.size     = 12
TextLayer.textItem.color    = textColor

var content = ''

function WriteLn(str)
{
    content += '\r'+str
}

function PrintBeer(n)
{
    return (n ? n : 'No') + ' bottle' + (n-1 ? 's' : '') + ' of beer'
}

for (i = 99; i>0;)
{
    WriteLn (PrintBeer(i) + ' on the wall, '+PrintBeer(i)+'.')
    WriteLn ('Take one and pass around,')
    WriteLn (PrintBeer(--i) + ' on the wall.')
    WriteLn ('')
}

WriteLn ('No more bottles of beer...')
WriteLn ('Go to the store and buy some more...')
WriteLn ('99 bottles of beer.')

TextLayer.textItem.contents = content
docRef = textColor = TextLayer = null


Оставить комментарий

Win errs, ICQ 4 DOS, PHP arrays, Colorer, www

Ссылочка (страница больше не существует) на страницу с «недокументированными» кодами ошибок Windows. Страница на английском, но язык выражений настолько прост, что человек, привычный к англоязычными интерфейсам программ, прочтет их без проблем.

Наиболее понравившиеся перлы:

WinErr 001: Windows loaded — System in danger
WinErr 002: No Error — Yet
WinErr 009: Horrible bug encountered — God knows what has happene
WinErr 019: User error — Not our fault. Is Not! Is Not!
WinErr 01B: Illegal error — You are not allowed to get this error. Next time you will get a penalty for that.

Ссылочку прислал Макс Симонов.

Моя кошка в очередной раз завела Любовную Песнь Ко Всем Котам Мира. Песня любовная, но почему такая пошлая? Раз за разом, наполняя воздухом мощные легкие, моя кошка являет миру свою песнь. Витас отдыхает. Боже, дай мне силы вытерпеть это еще раз.

За предоставленную информацию спасибо кошке Брусничке

Как не странно, существуют еще люди, которые ходят в интернет из DOS. Видимо, где-то на Земле сохранились еще компьютеры, которые не работают ни под чем, кроме этой БГом забытой ОС.

Для таких людей существует Lynx под DOS, Arachne и… порт ICQ под DOS. У меня эта программа запускаться отказалась — потребовала установить загадочный «packet driver», где его взять я не знаю, видимо, если у вас настроен TCP/IP под DOS, этот драйвер у вас уже имеется.

Насколько я понял, бегло прочитав руководство, интерфейс у этого клона текстовый, как, например, у его Unix-собрата vICQ. Последний, кстати, весьма любопытен тем, что написан он на языке Perl, т. е. при желании его можно как угодно модифицировать.

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

Любопытная, для PHP-программистов, мысль пришла мне недавно в голову. Никогда не задумывались, почему некоторые люди инициализируют массивы явно, вызовом array(), а другие — неявно, присваиванием?

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

В Perl, например, это делается по-другому — для массивов используются все те же скобки, а для строк пользуются функцией substr, которая ко всему прочему умеет становиться lvalue

Казалось бы, где грабли? Грабли в инициализации. PHP, если вы ничего не меняли в файле настроек, умеет превращать параметры POST— и GET-запросов в переменные скрипта, которому этот запрос адресован. Таким образом, если я вызову некий скрипт с параметром, скажем, ?config=s переменная $config получит значение «s» и тип «строка».

Если далее в программе встретится участок кода, который, по идее, должен был бы работать так, как будто переменная $config является массивом, на деле он будет работать с этой переменной, как со строкой, т. е. конструкция

$config[user_dir] = "/home/www/users";

заменит значение первого символа строки, хранящейся в $config на символ / и, при следующем чтении этого значения, вызов $config[user_dir] вернет слэш, что, потенциально, позволит какому-нибудь кулхацкеру, в зависимости от того, чем занимается этот скрипт, скачивать какие-либо файлы на сервере или изменять их.

Многим давно уже кажется, что то, чем PHP часто привлекает веб-программистов — содержимое главы Variables from outside PHP руководства по PHP, часто на практике приносит больше вреда, чем пользы.

В умах созревает идея заставить разработчиков PHP по-умолчанию эту фичу отключать, а внешние значения выбирать через соответствующие массивы, тем более, что разработчики пошли нам всем навстречу и присвоили им в последних версиях языка альтернативные короткие имена, доступные, к тому, из функций без определения их как global.

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

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

Владислав в скором времени обещает запустить веб-интерфейс, так что форум можно будет читать прямо из браузера. Для тех, кто не знает что такое ньюсы и как их читать, на сайте есть инструкция. Welcome!

Еще одна хорошая новость. На этот раз для поклонников FAR’a и Colorer’a. Хотя на страничке автора никаких анонсов не замечено, Colorer продолжается развиваться. Его страничка переехала на SourceForge и содержит уже два патча. Список изменений не анонсируется.

Ставятся оба патча один поверх другого, в соответствующие папки, после чего плагина надо будет удалить директорий bin. Патчи являются бетами, но, работая с ними уже две недели, я никаких глюков не обнаружил.

Картинка, ссылку на которую прислали мне по аське. Кто-нибудь видел два евро? Оно (она? он?) действительно так выглядит?

Кто придумал, что сайты обязаны начинаться с www? В последнее время есть тенденция изменения в лучшую сторону, но некоторые упорно не хотят сдаваться. DNS местной фирмы «Мелт», при попытке выкусить у их сайта www грустно сообщает, что IP адрес такого сервера он не знает.

Я тут подсчитал, что если открыть в браузере журнал Хакер по его адресу без «www», браузер пошлет серверу на 360 байт меньше, чем, если бы ссылка эти буквы содержала. Сейчас, сидя на двух мегабитах, мне от такой цифры делается смешно, но дома, на модеме 33600, который вечно сползает до 28800, с постоянными ретрейнами и speed shift, я начинаю тихо плакать в уголке.

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

Господа веб-мастера, заводя сайты, пожалуйста, вписывайте в DNS и веб-сервер, адреса и без этой злосчастной комбинации тоже, если вам не жалко тех, кто сидит на паршивом диал-апе, то подумайте хотя бы о тех, кто пытается продиктовать ваш адрес по телефону или прочитать по радио! «Дабл-ю, дабл-ю, дабл-ю» или «ве-ве-ве» понятности адресу не добавляют.

Всем удачных выходных! Пишите в ящик и в ньюсы!

Оставить комментарий

99 бутылок: «Паркетчик», Pocket Basic

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

Кроме основых конструкций ветвления, циклов и поддержки подпрограмм, язык предоставляет средства управления «Паркетчиком» — неким средством рисования цветных квадратов на ограниченом поле. В программе я специально разбил содержимое цикла на две фазы, чтобы показать, как «Паркетчика» можно использовать, например, для контроля за четностью.

Из недостатков.

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

Насколько я понял из файлов примеров, в программе нет циклов с произвольным шагом, приходится для этого использовать циклы «пока».

Кроме того, в бесконечном цикле «Паркетчик» умудрился намертво завесить мою Windows XP. Никакой возможности прервать программу я не нашел, компьютер ни на что не реагировал.

Скрипт, выводящий песню о пиве (beer.prg)

цел пиво;

Программа {
  пиво:=198;
  Делать пока (пиво>0) { 
    если (слева стена) то {
        если (пиво=2) то {
          Сообщить "1 bottle of beer on the wall, 1 bottle of beer."
        } иначе
        {
          Сообщить пиво/2, " bottles of beer on the wall, ",
          пиво/2, " bottles of beer."
        };
        
        Сообщить "Take one down, pass it around."
        Шаг вправо;
    } иначе
    {
      если (пиво=2) то {
        Сообщить "1 bottle of beer on the wall."
      } иначе {
        если (пиво>1) то {
          Сообщить пиво/2, " bottles of beer on the wall."
        } иначе {
          Сообщить "No bottles of beer on the wall.";
        };
      };
    
      Шаг влево;
    };
    
    пиво:=пиво-1;
  };
  
  Сообщить "No more bottles of beer...";
  Сообщить "Go to the store and buy some more...";
  Сообщить "99 bottles of beer.";
}

35. Pocket Basic 1.00 для Casio PV. Несмотря на то, что его автор, Petr Vlcek называет этот язык Бейсиком, Бейсиком он не является. Достаточно хотя бы взглянуть на синтаксис, если это для кого-то не аргумент, то скажу, что каждый элемент строки является число от -128 до 127, над которыми можно производить обычные арифметические действия, например вот так:

ASSIGN text<a+1>=text<a+1>+2

Для того, чтобы работать со элементами строки, как с символьными значениями, применяется модификатор точка («.»).

Язык довольно минималистский (например, из операторов ввода присутствует только TOUCH, позволяющий узнать в каком месте экрана было произведено касание, в функцию нельзя передать параметр и так далее), а потому малораспространенный. Несмотря на это язык мне понравился, своей простотой и, если так можно выразиться, средой разработки.

В отличие от OWBasic, где для редактирования программ используется встроенное в ОС приложение Memo, Pocket Basic предоставляет собственную среду для создания программ. Реализация имеет массу недостатков, в частности, встроенная клавиатура не содержит национальных символов, нет возможности переименования файлов и так далее, но есть и достоинства. Большим достоинством среды Pocket Basic является возможность набора операторов за один клик.

Каждый оператор языка начинаются с уникальной буквы, так что если редактор ждет ввода оператора, при нажатии на нужную букву оператор вводится целиком. Такой подход потребовал от создателя языка некоторых жертв, например блочный оператор IF выглядит довольно неожиданно, его полная конструкция выглядит, как IF — ELSE — CONTINUE. Другим достоинством среды является возможность использования колеса PV для передвижения по тексту.

Теперь, что касается программы, которая получилась в конечном счете. Поскольку документация весьма скудная, да еще и на немецком я не смог узнать если ли в языке условие «неравно». Испробовав все возможные варианты, я пришел к выводу, что нету. В конце цикла я использую очистку экрана перед выводом следующей фразы, у Pocket Basic’a есть серьезные проблемы со скроллингом, так что, чтобы избежать мусора на экране мне пришлось просто очищать экран. Как видно у программы отсутствует форматирование отступом, причина — среда разработки не позволяет производить такое форматирование.

Программа, выводящая песню о пиве (Beer)

! Beer song. Written by Evgeny Stepanischev
PROC beer
IF b=0
WRITE "No"
ELSE
WRITE b
CONTINUE
!
WRITE " bottle"
IF b=1
ELSE
WRITE "s"
CONTINUE
!
WRITE " of beer"
RETURN
!
!
VAR INT b
ASSIGN b=99
!
FOR b>0
USE beer
WRITE " on the wall, "
USE beer
WRITE "."l
WRITE "Take one down and pass around."l
ASSIGN b=b-1
USE beer
WRITE "."
SLEEP 4
BOX
ASSIGN posy=0
ASSIGN posx=0
NEXT
!
WRITE "No more bottles of beer..."l
WRITE "Go to the store and buy some more..."l
WRITE "99 bottles of beer."
SLEEP 20


Оставить комментарий

99 бутылок: Parrot, OW-BASIC

32. Parrot. Очень молодой, его первый компилятор в байт-коды появился 10 сентября (дело происходило в 2001 году — более позднее примечание), язык виртуальной машины для интерпретируемых языков. Насколько я понимаю, разрабатывался специально для Perl6.

Язык по базовым конструкциям беднее ассемблера — нет ни одной конструкции цикла, все они заменяются условными переходами, ограниченное количество переменных (по 32 на каждый тип переменной), зато есть поддержка функций (параметры передаются через стек), операций с файлами, операторов ввода-вывода и так далее. Поскольку интерпретатору около месяца, диагностика ошибок еще весьма бедная, иногда единственное сообщение, которое получаешь на экран — «Segmentation fault». :)

Скрипт, выводящий песню о пиве (beer.pasm)

# Beer song. Written by Evgeny Stepanischev

        set      I1, 99
        branch   MAIN

beer:   if       I1, _NZERO
        print    "No"
        branch   _I1_EL

_NZERO: print    I1
_I1_EL: print    " bottle"
        eq       I1, 1, _NO_S

        print    "s"
_NO_S:  ret



MAIN:   bsr      beer
        print    " of beer on the wall, "
        bsr      beer
        print    " of beer."
        print    "\nTake one and pass around,\n"

        dec      I1

        bsr      beer
        print    " on the wall.\n\n"

        if       I1, MAIN

        print    "No more bottles of beer...\n"
        print    "Go to the store and buy some more...\n"
        print    "99 bottles of beer.\n"

        end

33. OW-BASIC — наиболее популярный, среди пользователей PV-S450, диалектов языка BASIC. Ему присущи все основные черты небольших современных интерпретаторов этого языка — наличие процедур с локальными параметрами и параметрами по указателю, блочные конструкции, функции работы со строками и отсутствие необходимости нумеровать строки.

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

Программа, выводящая песню о пиве (! beer)

! beer
! Beer song. Written by Evgeny Stepanischev

PROC beer i, VAR s$
  IF i>0 THEN
    s = STRING(i)
  ELSE
    s = "No"
  ENDIF

  s = s+" bottle"

  IF i<>1 THEN
    s = s+"s"
  ENDIF
  s = s+" of beer"
ENDP

FOR i=0 TO 98
  beer 99-i, s$
  ? s;" on the wall, ";s;"."
  ? "Take one and pass around,"
  beer 98-i, s
  ? s;" on the wall.":? ""
NEXT

? "": ? "No more bottles of beer..."
? "Go to the store and buy some more..."
? "99 bottles of beer."


Оставить комментарий

99 бутылок: базовый SIMPLE, Bascom-8051

30. Базовый SIMPLE. Необычный язык с интересными синтаксическими конструкциями, поддержкой списков (как в LISP), кортежей, функций с произвольным количеством параметров, псевдоассемблера, предпроцессора и фреймовых структур. Это язык со строгой типизацией и чувствительный к регистру.

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

Скрипт, выводящий песню о пиве (beer.smp)

// Written by Evgeny Stepanischev

define beer(n) {
    cond {
         n>0 do princ(n);
         n<1 do princ("No");
    };

    princ(" bottle");
    if (n<>1) {princ("s");};
    princ(" of beer");
};

define main() {
    declare b=99;

    lcond {
        b=0 do {
            print("No more bottles of beer...");
            print("Go to the store and buy some more...");
            print("99 bottles of beer.");
        };

        do {
            beer(b); princ(" on the wall, ");
            beer(b); print(".");
            print("Take one down, pass it around.");

            b:=b-1;
            beer(b); print(" on the wall.");
            print("");
        };
    };
};

31. Bascom-8051 (версия два). Язык для программирования микроконтроллеров, как следствие специализации имеет операторы для работы с битовыми типами, LCD, внешней памятью, таймерами и сигналами и так далее.

Расшифровывается BASCOM, как «BASic COMpilator». По моему мнению, он если и похож на Бейсик, то весьма отдаленно. Язык имеет ряд тонких особенностей, с которыми мне пришлось столкнуться при написании даже такой простой программы: оператор for с ключевым словом downto не требует указания отрицательного step, переменная «B» зарезервирована, процедуры надо сначала объявлять, потом только использовать, процедуры являются входимыми (возврат осуществляется по стеку) и программу перед их телом надо останавливать, аргументы функций ассоциируются с переданной переменной по имени, т. е. передав значение процедуре printbeer я присвою значение переменной beer. И т. д. и тому подобное.

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

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

Программа, выводящая песню о пиве (beer.bas)

' Written by Evgeny Stepanischev

Dim Beer As Byte , Res As String * 10
Declare Sub Printbeer(beer As Byte)

Beer = 2

While Beer > 0
   Call Printbeer(beer)

   Print Res ; " on the wall, " ; Res ; "."
   Print "Take one down, pass it around."

   Decr Beer
   Call Printbeer(beer)

   Print Res ; " on the wall."
   Print
Wend

Print "No more bottles of beer..."
Print "Go to the store and buy some more..."
Print "99 bottles of beer."

End

Sub Printbeer(beer As Byte)
   Dim Tmp As String * 10

   If Beer = 0 Then Res = "No" Else Res = Str(beer)

   Tmp = Res + " bottle" : Res = Tmp
   If Beer <> 1 Then Res = Tmp + "s"

   Tmp = Res : Res = Tmp + " of beer"
End Sub


Оставить комментарий

99 бутылок: RW1, Euphoria

28. RW1. Язык используется в основном для программирования виртуальных роботов, между которыми проводятся такие же виртуальные бои.

В языке есть возможность описания пользовательских функций, но я не смог ими воспользоваться из-за… отсутствия в языке символьных типов. Хорошо хоть оператор SAY понимает строки, причем с возможностью вывода значений переменных.

О самом интерпретаторе. Программы прекомпилируются в собственную систему байт-кодов, после чего исполняются интерпретатором. У прекомпилятора, который и выполняет проверку синтаксиса очень бедные возможности диагностики, так что мне приходилось подолгу ломать голову на тем, почему программа не работает. В частности из-за конструкции «var—», которая в языке существует, но не может быть применена, как самостоятельная конструкция.

И, наконец, что касается вечного цикла в конце. Программы на языке RW1 (по крайней мере, что касается описания роботов, представляет собой зацикленную программу и вечный цикл нужен для того, что бы программа не начала выполняться заново.

Скрипт, выводящий песню о пиве (beer.rw1)

% Written by Evgeny Stepanischev

ROBOT "Beer"
AUTHOR "Evgeny Stepanischev"

main()
{
  beer=99
  while(beer>0)
  {
     IF(beer>1) SAY "&BEER bottles of beer on the wall, &BEER bottles of beer."
     ELSE SAY "&BEER bottle of beer on the wall, &BEER bottle of beer."

     SAY "Take one down, pass it around."

     beer = beer-1

     IF(beer>1) SAY "&BEER bottles of beer on the wall."
     ELSE
     {
        IF(beer) SAY "&BEER bottle of beer on the wall."
        ELSE SAY "No bottles of beer on the wall."
     }

     SAY ""
     
  }

  SAY "No more bottles of beer..."
  SAY "Go to the store and buy some more..."
  SAY "99 bottles of beer."

  WHILE(1)
  {
  }
}

29. Euphoria. Очень интересный язык с возможностью оперирования списками, как базовыми типами. Например, их можно складывать, сравнивать и вообще производить любые операции, как над атомарными типами. Единственное, что для меня оказалось странным, это тот факт, что атомарные типы не являются частным случаем списков (последовательностей).

В общем не знаю чем, но язык мне понравился. :) Кстати, в языке, насколько я понимаю, есть разница между операция «запятая» (разделение элементов в списке) и «запятая с пробелом» (разделение аргументов функции). Свое предположение я не проверял (а описание читал очень бегло), но, если будете писать программы на этом языке, будьте осторожны с запятой.

Для этого языка существуют интерпретаторы под DOS, Windows и Linux, а так же транслятор в язык Си. Описание языка распространяется вместе с интерпретатором.

Программа, выводящая песню о пиве (beer.ex)

-- Written by Evgeny Stepanischev
integer beer
beer = 99

procedure PrintBeer (integer b)
    if b then
        printf (1, "%d", b)
    else
        puts (1, "No")
    end if

    puts (1, " bottle")

    if b!=1 then puts (1, 's') end if
end procedure

while beer>0 do
    PrintBeer(beer) puts (1, " of beer on the wall, ")
    PrintBeer(beer) puts (1, " of beer.\n")
    puts (1, "Take one down, pass it around.\n")

    beer = beer - 1
    PrintBeer(beer) puts (1, " of beer on the wall.\n\n")
end while

puts (1, "No more bottles of beer...\n")
puts (1, "Go to the store and buy some more...\n")
puts (1, "99 bottles of beer.")


Оставить комментарий

99 бутылок: RBASIC, MACS

26. RBASIC. Язык RBASIC предназначен для того, что бы предоставить пользователю возможность быстро создавать свои программы для решения задач по ведению радиомониторинга с помощью широкодиапазонных компьютерных сканирующих приемников фирмы Winradio Communications.

Основа языка — BASIC к которому добавлены некоторые конструкции и специальные функции для управления приемниками, такие например, как управления шумоподавителем, громкостью, модуляцией и т. п.

Скрипт, выводящий песню о пиве (beer.rbp)

# Beer song. Written by Evgeny Stepanischev
LET b=99
LET s$=""
FOR i=99 TO 1 STEP -1
GOSUB @beer     
PRINT s$+" on the wall, "+s$+" of beer."
PRINT "Take one and pass around,"
b = b-1
GOSUB @beer
PRINT s$+" on the wall."
PRINT ""    
NEXT i
     
PRINT "No more bottles of beer..."
PRINT "Go to the store and buy some more..."
PRINT "99 bottles of beer."
     
END
       
@beer
LET s$=""
IF b>0 THEN s$ = s$ + str$ (i) ELSE s$ = s$ + "No"
s$ = s$ + " bottle":IF b<>1 THEN s$ = s$+"s"
RETURN

27. MACS (MACrotestSoftware). Язык управления стендом и описания технологического процесса ремонта электронных плат. Для этой цели в языке есть весьма специфические конструкции. Из недостатков языка — отсутсвие возможности описания пользовательских процедур и функций и наличие всего двух типов данных — целых чисел и строк. Из глюков интерпретатора — необходимый последний перевод строки.

Программа, выводящая песню о пиве (beer.mcs)

// Written by Evgeny Stepanischev

cls
 string beer
 string w = " on the wall"
 def b

 for def i=198 to i > 0, i=i-1
 do
    b = i/2

    if b beer = b else beer = "No" endif
    beer = beer+" bottle"
    ifs b!=1 beer = beer+"s"

    if i&1
       beer w ".\r\n\r\n"
    else
       beer w ", " beer "."
       "\r\nTake one down and pass it around,\r\n"
    endif

 done


 "No more bottles of beer...\r\n"
 "Go to the store and buy some more...\r\n"
 "99 bottles of beer."

 pause


Оставить комментарий

99 бутылок: KiXtart, Omens

24. KiXtart. Язык пакетных файлов. Достаточно простой, наглядный и функциональный. Интересны конструкции вывода на экран и принципы построения функций. Функции (точнее подпрограммы) можно строить при помощи блока Function или, как в BASIC’е, через GOSUB и метки. Что мне понравилось — KiXtart предоставляет большую свободу в форме записи. Так, например, операторы можно разделять переводом строки, табуляциями, пробелами.

Скрипт, выводящий песню о пиве (beer.kix)

; Beer song. Written by Evgeny Stepanischev

Function Beer($n)
  If $n
    $n
  Else
    "No"
  Endif

  " bottle"
  If $n<>1 "s" Endif
EndFunction


FOR $beer = 99 TO 1 STEP -1
  Beer ($beer) " on the wall, "
  Beer ($beer) " of beer."

  ? "Take one and pass around,"

  ? Beer ($beer-1)
  
  " on the wall."??

NEXT

"No more bottles of beer..." ?
"Go to the store and buy some more..." ?
"99 bottles of beer."

25. Omens (Object manageMENt System). Язык, сочетающий в себе черты Cи, Cи++ и Java. Например, конструкции он унаследовал от Си, принципы работы с указателями и ссылками — из Си++, а описания классов — из Java.

В данный момент язык и система разработки (компилятор в платформо-независимый байткод и интерпретатор) находятся в стадии бета-тестирования. Наверное, поэтому циклы for и while интерпретатор (даже в файлах примеров) выполнять отказался из-за чего мне пришлось использовать рекурсию.

Сам Omens разрабатывался, как платформонезависимая среда со встроенным облегченным механизмом описания и манипулирования сложными данными, в том числе и с базами данных (DB2, Oracle, MS SQL, dBASE, MS Access, …). Из интересных особенностей — у программы может быть несколько точек входа.

Программа, выводящая песню о пиве (beer.oms)

//  Beer song. Written by Evgeny Stepanischev

class beer {
    private void PrintBeer(byte n) {
        if (n>0)
        system.out.print(lang.ltoa(n)); else
        system.out.print("No");
        system.out.print(" bottle");

        if (n!=1) system.out.print("s");
    }


    private void For(byte i) {
        PrintBeer(i);
        system.out.print(" on the wall, ");
        PrintBeer(i);
        system.out.print(" of beer.");

        system.out.println("Take one and pass around,\n");
        PrintBeer(i-1);
        system.out.print(" on the wall.\n\n");
        if (i>1) For(i-1);
    }


    public void main() {
        For(99);

        system.out.print("No more bottles of beer...");
        system.out.println("Go to the store and buy some more...");
        system.out.println("99 bottles of beer.");
    }
};


Оставить комментарий

99 бутылок: Miva, Ruby

22. Miva. Доступ к этому языку я получил чисто случайно. Будем считать, что я нашел распечатки парочки программ на этом языке на улице. Это недалеко от истины, ибо документацию по Miva я в глаза не видел.

Итак Miva — это скриптовый полнофункциональный язык, применяемый исключительно в веб-программировании. Синтаксис, на мой взгляд, несколько неуклюж, что, впрочем, легко объяснимо способом его внедрения, и неоправданно многословен. Из интересных особенностей — разделение локальных, глобальных и системных (?) переменных через объекты «l», «g» и «s».

Скрипт, выводящий песню о пиве (beer.mv)

<HTML><MIVA STANDARDOUTPUTLEVEL = "text, html, compresswhitespace">

<MvCOMMENT>
| Beer song. Written by Evgeny Stepanischev
</MvCOMMENT>

<MvFUNCTION NAME="Beer" PARAMETERS="n">
<MvIF EXPR = "{ l.n NE 0 }">&[ l.n ]<MvELSE>No</MvIF>
bottle<MvIF EXPR = "{ l.n NE 1 }">s</MvIF>
of beer</MvFUNCTION>

<MvASSIGN NAME = "g.i" VALUE = 99>

<MvWHILE EXPR = "{ g.i GE 1 }">
<MvEVAL EXPR="{ Beer(g.i) }"> on the wall, <MvEVAL EXPR="{ Beer(g.i) }">.<BR>
Take one and pass around,<BR>
<MvASSIGN NAME = "g.i" VALUE = "{ g.i - 1 }">
<MvEVAL EXPR="{ Beer(g.i) }">
on the wall.<BR><BR>

</MvWHILE>

No more bottles of beer...<BR>
Go to the store and buy some more...<BR>
99 bottles of beer.

</HTML>

23. Ruby. Скриптовый язык, который я посчитал очень похожим на Перл, поэтому писал на нём как на Перле. Отличия есть, и существенные, но тем не менее. Как и предыдущем языке, есть префиксные различия между глобальными (начинаются на «$» или «@») и локальными переменными. Из странностей — конструкцию «1?2:3» не удалось заставить работать с локальными переменными. Возможно это особенность языка, но не ясен её смысл.

Скрипт, выводящий песню о пиве.

# Beer song. Written by Evgeny Stepanischev

def Beer (n)
  if n!=0 then
    print n
  else
    print 'No'
  end

  print " bottle"
  print "s" unless n==1
end

$i = 99

while $i>0 do
  Beer ($i)
  print " on the wall, "
  Beer ($i)
  print "\nTake one and pass around,\n"
  $i-=1;
  Beer ($i)
  print " on the wall.\n\n"
end

print <<EOF
No more bottles of beer...
Go to the store and buy some more...
99 bottles of beer.
EOF


2 комментария

99 бутылок: PasScript, ActionScript

20. PasScript. Можно сказать, что это VIRT со всеми присущими ему особенностями и конструкциями (например, «P << [[ 70, 5], <<P]»), только с синтаксисом Object Pascal. Из глюков интерпретатора я заметил нежелание конструкции «for» работать с переменными типов «byte» и «word», плюс конструкция «writeln» сначала печатает перевод строки и только потом —свой параметр.

Скрипт, выводящий песню о пиве (beer.pas)

// Beer song.  Written by Evgeny Stepanischev

program Beer;
procedure PrintBeer( n: byte );
begin
      if n<>0 then write (n)
      else write ('No');

      write (' bottle');
      if n<>1 then write ('s');

      write (' of beer');     
end;

var
  I: integer;

begin
      for I:=99 downto 1 do
      begin
           PrintBeer (I);
           write (' on the wall, ');
           PrintBeer (I);
           write ('.');
           writeln ('Take one and pass around,');
           writeln ();

           PrintBeer (I-1);
           write (' on the wall.');
           writeln ();
           writeln ();
      end;
      write ('No more bottles of beer...');
      writeln ('Go to the store and buy some more...');
      writeln ('99 bottles of beer.')
end.

21. ActionScript5. Внутренний язык Flash5. По виду очень похож на JavaScript (если не считать «add», обязательные точки с запятой и прочие мелочи), даже многие предопределенные объекты те же, но по идеологии — нет. Например, как в JavaScript осуществляется доступ к каким-либо внешним сущностям? Через коллекции. В ActionScript доступ происходит по имени.

Из интересных особенностей интерпретатора… ActionScript от версии к версии сильно изменяется. Вплоть до несовместимости. Так вот, если интепретатору подсунуть Flash предыдущей версии, он выполняет все необходимые преобразования в ActionScript за программиста, комментируя все свои действия.

Скрипт, выводящий песню о пиве.

// Beer song. Written by Evgeny Stepanischev

function PrintBeer (i)
{
    return (i?i:'No') add ' bottle' add (i-1?'s':'') add
    ' of beer';
}


for (i = 99; i>0; i--)
{
    trace ((b=PrintBeer (i)) add ' on the wall, ' add b add '.');
    trace ('Take one down and pass it around,');
    trace (PrintBeer (i-1) add ' on the wall.\n');
};

trace ('No more bottles of beer...\n' add
'Go to the store and buy some more...\n' add
'99 bottles of beer.');


Оставить комментарий

99 бутылок: РАПИРА (КИ) и VIRT

18. РАПИРА. Точнее некий диалект языка РАПИРА для Конструктора Исполнителей.
Среда разработки и диалект мне не понравились. Не запоминаются положения и размеры окон, расцветка хромает, после вывода ошибки происходит выход, не хватает множества функций, синтаксис, не смотря на заявление разработчика, все-таки частично регистро-зависим и т. д. и т. п.

Сам язык РАПИРА (расшифровывается, как «Расширенный Адаптированный Поплан-Интерпретатор, Редактор, Архив») был придуман, как видно из синтаксиса, в Советском Союзе для обучения программированию в школах. Похоже, что конструктивно представляет из себя простую кальку с Паскаля.

Программа, выводящая песню о пиве (Panupa для Конструктора Исполнителей).

// Песня о пиве. Написал Степанищев Евгений
фун встр (и)
    старш:= и/10
    младш:= и mod 10

    если старш>0
        возврат симв(48+старш)+симв(48+младш)
    иначе
        возврат симв(48+младш)
    всё
кон фун

фун пиво (и)
    если и=0
        стр:= 'No'
    иначе
        стр:= встр (и)
    всё

    стр:= стр+' bottle'
    если и<>1
        стр:= стр+'s'
    всё

    возврат стр
кон фун

проц старт()
    для и от 99 до 1 шаг -1
        печать пиво (и)+' on the wall, '+пиво (и)+'.'
        печать 'Take one and pass it around,'
        печать пиво (и-1)+' on the wall.'
        печать ''
    кц

    печать 'No more bottles of beer...'
    печать 'Go to the store and buy some more...'
    печать '99 bottles of beer.'

кон проц

19. VIRT. Объекно-ориентированный язык. По синтаксису напоминает Object Pascal, Modula 2, Modula 3 и Oberon. Особенности. Специальные конструкции языка позволяют легко задавать списки и деревья, есть возможность перегрузки операторов «+», «-», «[]» и тому подобных, конструкции обработки исключительных ситуаций, вычисления языковых конструкций и многое другое.

Пара слов о реализации. Отступы в программе осуществляются при помощи пробелов, табуляции интерпретатор не любит, кроме того не любит он пробелов между именем функции и скобками. Но это не самое странное. Реализованный язык, по всей видимости, не дает использовать многобуквенные переменные, по крайней мере внутри функций. Так что, если вдруг, будьте внимательны.

На сайте есть компонент (45$) для Delphi, позволяющий использовать интерпретатор в качестве внутреннего языка для какого-либо проекта.

Программа, выводящая песню о пиве (beer.w).

-- Песня о пиве. Написал Евгений Степанищев

function PrintBeer(n)
    s := ''
    if n<>0 then
        s := s+str(n)
    else
        s := s+'No'
    end
    s := s+' bottle'
    if n<>1 then
        s := s+'s'
    end
return s+' of beer'

-- Main program

    P := 99
    While P Do
        Writeln( PrintBeer( P )+' on the wall, '+PrintBeer( P )+'.' )
        Writeln( 'Take one and pass it around,' )
        P := P-1
        Writeln( PrintBeer( P )+' on the wall.'+EOL() )
    End

    Writeln( 'No more bottles of beer...' )
    Writeln( 'Go to the store and buy some more...' )
    Writeln( '99 bottles of beer.')
return


Оставить комментарий

Читаем Excel 2.0

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

Проблема заключалась в чтении данных из формата Excel 2. Обычно, под ASP для доступа к Excel используется ADODB. Загвоздка в том, что драйвер, используемый системой в этом случае работает с форматом Excel версий 3.0 и выше. Так что мне пришлось искать другой путь.

Попытки найти другой драйвер или использовать DDE ничего не дали, я решил поискать в Интернете описание этого формата и попробовать написать собственный парсер (WinCGI). Выручила поисковая машина Google, просмотрев более 500 ссылок, я нашел то, что искал.

Итак, формат Excel 2 a.k.a. Excel BIFF представляет собой набор записей (record) определенного формата:

| Заголовок записи  | Тело записи
Номер байта      | 0    1    2    3  | 0    1   ...
                -----------------------------------
Содержимое       | XX | XX | XX | XX | XX | XX | ...
                -----------------------------------
                 | тип     | длина   | данные

В первых двух байтах записан числовой тип записи, о нём позже, далее идут два байта, это длина данных, далее — сами данные. Записи — это то, чем мы будет оперировать.

Пример на Delphi, читающий одну запись:

...
var F: File of byte;
    Opcode, Len,
    Code: Word;
    Operand: Array of byte;

begin
        AssignFile(F, 'имя_файла.xls');
        FileMode := 0;
        Reset(F);

        BlockRead (F, Opcode, 2);
        BlockRead (F, Len, 2);
        SetLength (Operand, Len);
        BlockRead (F, Operand[0], Len);
        Proccess (Opcode, Operand); // Функция для обработки записи
        CloseFile (F);
end;

Типов записей около 64, но я, для обработки данных, использовал только 7. Заголовок файла (BOF), где описан версия файла и его тип; размер листа Excel (DIMENSION); пустая запись (BLANK); целое число (INTEGER); строка (LABEL); число с плавающей точкой (NUMBER), совмещенное поле — логический тип или поле ошибки (BOOLERR) и поле формата числа (FORMAT).

Семь типов записей:

const xBOF       = 09;
      xDIMENSION = 00;
      xFORMAT    = $1E;
      xBLANK     = 01;
      xINTEGER   = 02;
      xLABEL     = 04;
      xNUMBER    = 03;
      xBOOLERR   = 05;

Запись типа BOF содержит два слова [1]. В первом записана версия файла (в данном случае «2») и тип файла (обычно это $10 [2] — worksheet). Эта запись — первая в любом файле формата Excel, прежде чем заниматься дальнейшим разбором стоит проверить ее содержимое.

Следующий тип, DIMENSION содержит данные о размере листа данных. Запись этого типа содержит четыре слова: номер первой строки, номер последней строки плюс один, номер первого столбца, номер последнего столбца плюс один. Я использую это поле для выделения места под данные, которые будут преобразованы из Excel.

Тип FORMAT содержит в поле данных строку форматирования в виде Pascal string (т. е. в первом байте длина, далее — строка). Строки формата идентифицируются в порядке следования, начиная с нуля. Тут есть одна тонкость: типы, выбираемые в Excel из списка «Формат ячеек», хранятся, как INTEGER или NUMBER. То, как они будут представлены человеку определяется форматными строками. Форматы даты и времени совпадают с принятыми в функции FormatDateTime среды разработки Delphi, а численные форматы могут быть легко сведены к параметрам функции Format.

BLANK — пустое поле. Как и любой из последующих типов, содержит в первом слове строку, а во втором — столбец ячейки на листе Excel.

INTEGER — целое. В 7 и 8-м байте (в 4-м слове данных) содержится обычное двухбайтовое целое. Как я понимаю, знаковое. В первых 6 битах пятого байта записан номер формата число (см. FORMAT).

LABEL — строка. Начиная с 7-го байта записан Pascal string. Пример чтения этого и следующих типов будет ниже.

NUMBER — число. С 7-го байта записано число с плавающей точкой в формате IEEE. Так же, как и для INTEGER в первых 6 битах 5-го байта записан номер формата.

BOOLERR — в 8-м байте указывает используется ли это поле для булевского типа (записан «0») или содержит ошибку (записан «1»). Само значение, как не трудно догадаться, записано в 7-м бите («0» — ложь, «1» — истина). Я обрабатывал только булевскую часть.

Простой пример чтения LABEL, NUMBER и BOOLERR.

...
Procedure Proccess (Opcode: Word; Op: array of byte);
var Str: ShortString;
    Dbl: Double;

Begin
        if (Opcode=xLABEL) Or (Opcode=xBOOLERR) Or (Opcode=xNUMBER) Then
        Begin
                iX:=Op[2]+Op[3]*256;
                iY:=Op[0]+Op[1]*256;
        End;

        Case OpCode of
        xLABEL:   begin
                        Move (Op[7], Str, SizeOf(Str));
                        MBuff[iY][iX]:= Str;
                  end;

        xBOOLERR: If Op[8]=0 Then MBuff[iY][iX]:= IntToStr(Op[7]) Else
                  MBuff[iY][iX]:= '';

        xNUMBER:  begin
                        Move (Op[7], Dbl, 8);
                        MBuff[iY][iX]:= FloatToStr (Dbl)
                  end;
End;

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

[1] слово (здесь) — два байта, записанных в обычном, для процессоров Intel, порядке: сначала младший, потом старший. В Delphi — это тип word.
[2] в Паскале запись вида $00 означает шестнадцатеричную систему счисления.

Оставить комментарий

← 1 62 63 64 65 66 67 →