Как стать автором
Обновить
22
0
Vladimir Pekunov @pekunov

Исследователь

Отправить сообщение

C++ -- алгоритмически полный язык и позволяет сам по себе описать произвольный разрешимый алгоритм. Вопрос в том, насколько получается удобно и понятно. Для повышения такого удобства и понятности программ, а также для повышения краткости программ и разрабатываются новые языки. По моему мнению, Planning C позволяет достаточно компактно и понятно описывать ряд возможностей параллельного программирования, что я и старался продемонстрировать.

Кто будет поддерживать новый компилятор для нового языка, который подозрительно похож на C++? Сколько лет пройдёт чтобы новый компилятор, если таковой появиться, вошол на постоянной основе в основные дистрибутивы *nix систем?

Это Вы верно заметили. Пока компилятор поддерживаю только я, со всеми вытекающими отсюда следствиями (разрабатывается все это долго и тяжело :) ). Возможно когда-нибудь дело дойдет до написания полноценной версии транслятора, которая действительно войдет в какой-нибудь дистрибутив, но задача может и умереть, как, например, по факту скончался язык-расширение cilk++, который первоначально создавался и поддерживался Intel'ом, но впоследствии они отказались от его поддержки.

Нет, с этим ресурсом пока не работал. Интересная идея, спасибо.

Чтобы писать более компактные и понятные программы

Не все новые возможности языка можно уместно и компактно вписать в стандартный синтаксис C++. Я пока написал только о части возможностей. Вот пример: вычислительная топология - кольцо из 5 взаимодействующих потоков, по этому кольцу прогоняются некоторые данные. На Planning C записывается достаточно кратко, на обычном C++ так кратко и универсально вряд ли получится. Кстати, эта программа выведет на экран число 210.

#include "reentera.h"
#include <iostream>

using namespace std;

const int NP = 5;

int main() {
    int SUM = 0;

    auto c = chain[] <input_proc Src, int from, int val> {
      int id = reent_linear_num();

      if ((id == 1) ^ (from >= 1)) {
         reent_next_first(this[1 + id % NP], id, val+1);
      }
      if (from >= 1) {
         SUM += val;
         if (id == 1) {
            cout << SUM << endl;
            reent_topology_quit();
         }
      }
    } {
      1 -> 2 -> 3,
      5<-4<-3, 5->1
    };

    c(empty_proc, 0, 39);

    return 0;
}

А такая возможность, как оперативное расширение синтаксиса языка, в C++ вообще почти отсутствует. В этой статье я приводил пример такого оперативного расширения -- как средствами Planning C на ходу встроить в язык новую синтаксическую конструкцию -- цикл while с обработкой прерывания по break. То есть, нечто вроде:

while (k < 10) {
		cin >> A[k];
		if (A[k] == 0) break;
		k++;
	}
	else
		cout << "Был введен ноль!" << endl;

Формально это расширение (+ еще ряд конструкций) так и имеет свое название -- Planning C. За идею относительно pre-build -- спасибо :)

Да, так конечно правильнее (я упустил using), спасибо. Кстати, подозреваю, что под Linux отладить многострочный макрос не проще, чем в Windows.

А отлаживать получившуюся программу вы как собираетесь?

Кстати, по-моему, схожие проблемы не решены и в стандартном C++.

Например, как отлаживать программу с многострочным макросом? Для кода в макросе -- почти никак. По крайней мере в моей версии MSVC.

#include <iostream>
#define A(a,b,c) cout<<a<<endl; \
  cout<<b<<endl; \
  cout<<c<<endl;
int main() {
  A(1,2,3);
}

Чтобы решить такую проблему хотя бы частично, не остается ничего кроме, как написать для регэкспа, проверяющего, тип это или нет, предикат, позволяющий выполнять фрагменты кода C++, чтобы он всегда мог вычислить S<IsPrime(N)>::T. Кстати, в частном случае это, думаю, можно сделать сравнительно дешевым (хотя и медленным) способом -- вызывать в предикате стандартный компилятор C++ для интересующего кода с подобающей оберткой и возвращать результат. И конечно, есть и более дорогой (хотя и более правильный) метод -- воспользоваться каким-либо из существующих интерпретаторов C++, вызывая его из регэксп-предиката.

Тяжелые решения. Однако успокаивает, что Ваш пример все-таки искусственный. Не надо бы писать такой код, он чреват тяжелыми синтаксическими ошибками со стороны программиста :)

Допустим, вам каким-то чудом удалось правильно распарсить исходник на С++ с помощью регулярок, развернуть макросы и откомпилировать. А отлаживать получившуюся программу вы как собираетесь? Компилятор отладочную информацию создаст для текста после вашего чудо-препроцессора.

Да, есть и такая проблема. Ее решением я не занимался, но если вдруг этот проект получит реальное практическое применение, подумаю. Вообще же, "проблем, не разрешимых ни при каких мыслимых условиях -- не существует" (А.Азимов).

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

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

Что же касается регэкспов, то как я уже упоминал, при полноценном разборе текста на ЯВУ (кстати, такая задача в простых случаях абсолютно не нужна, в чем можно убедиться из примера в моей статье) они выполняют исключительно лексический и часть синтаксического разбора. Весь оставщийся синтаксический разбор выполняет код компилирующего макроса (это, фактически, GNU Prolog, полный по Тьюрингу). Для С (не C++) работает прекрасно.

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

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

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

Да, такая проблема есть. Вряд ли в данном подходе ее можно решить полностью, но частичное решение может быть таким: в компилирующем макросе при генерации кода можно вставлять конструкции вида "write('#line '), write(__LINE__+относительный_номер_строки), nl", которые укажут компилятору (через стандартную директиву #line) на строку исходного кода, на которую он сошлется при возникновении ошибки в текущем сгенерированном фрагменте.

Прекрасная задача :) Одним регэкспом здесь, конечно, не обойтись, нужно несколько, причем они будут работать с единой базой данных/фактов. Применительно к тому, о чем я писал в статье: здесь надо ввести как минимум K+1 сканеров -- первые K находят и разбирают все возможные определения типов, занося имена типов в базу фактов (в которую также уже занесены все стандартные типы). А последний сканер разбирает выражение a*b, проверяя по базе, является ли a именем типа и принимая решение о расстановке пробелов для компилирующего макроса.

Я не зря писал про предикативные расширения регэкспов. С их помощью (например, написав предикат выделения сбалансированных по тегам подстрок) можно распознать и HTML (не берусь утверждать что все его конструкции, но можно). Причем здесь не будет противоречия с упомянутой Вами статьей, поскольку в ней упор идет на то, что HTML не описывается регулярной грамматикой. Вводя предикаты, можно распознавать уже не только регулярные грамматики, просто части, не являющиеся регулярными, возьмут на себя предикаты. Собственно, в приведенном мной примере один такой предикат Predicates.BAL уже есть -- он тестирует подстроку -- является ли она сбалансированным по различного видам скобок выражением.

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

Интересная идея, так можно получить еще бОльшее ускорение. Однако интерполирование в таком случае может давать несколько бОльшую погрешность, чем если просто пересчитать транзакцию y=g(x) по новому x.
В случае Var[@A=1 or @A=2] таблица истинности предиката включает единственную переменную A, при чем же здесь B?
А случай Var[@A=1 or @B=2] породит три варианта:
A=«1»
B=«2»
A=«1» B=«2»
Относительно формальной постановки. Думаю, так:
Генерация минимальных дополнений исходного XML, таких, что:
1. Гарантированно истиннен каждый шаг заданного XPath;
2. Если на шаг был наложен логический предикат [], то полученный XML удовлетворяет ВСЕМ случаям из его таблицы истинности, дающим в результате истинное значение.
Отличается, повторюсь, применением XPath в конструирующем смысле, и минимализмом средств.

Информация

В рейтинге
Не участвует
Откуда
Иваново, Ивановская обл., Россия
Зарегистрирован
Активность