Помощь новичкам

Я думал, Вы не можете не знать. Видимо, просто забыли

Что до интерпретатора - это значит полный анализ каждой функции, диагностика ошибок, ведение таблицы переменных, выполнение “на лету” библиотечных функций… маленький дипломчик?

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

Нет, это алгоритм слишком простой. Я бы писал полноценный top-down парсер

Не совсем. Технологии сейчас далеко продвинулись. Там работы - на день максимум.

А кратчайший путь на графе?

А ну да, ещё и это. Кратчайший путь и goto

Возможно. Если знать эти технологии и владеть каким-то инструментальным языком, для них подходящим.

Дам кому-нибуть в качестве допзадания на курсе по компиляторам

Видимо, пора записываться на курс по компиляторам. Не приходилось этими делами лет так под 30 заниматься, у меня все представления остались на уровне книги Д.Гриса. Когда-то писал на PL/1 кросс-компилятор с придуманного самим же для работников радиозавода технологического языка в модифицированный бейсик для микроконтроллера.

Встретилась вот такая задачка.

Дана вещественная матрица размера n x m, все элементы которой различны. В каждой строке выбирается элемент с наименьшим значением, затем среди этих чисел выбирается наибольшее. Указать индексы элемента с найденным значением.

Решил, чтобы не мучиться со вводом, инициализировать матрицу случайными числами. Но загвоздка в том, что матрица вещественная, а MatrRandomReal (что ожидаемо), заполняет её значениями с “бешеной” дробной частью. Поэтому приходится получать подобные данные из целых чисел путем деления на 10, 100, 1000 и т.п. И вот тут не удалось обойтись без оператора цикла (а хотелось!).

// PascalABC.NET 3.2, сборка 1482 от 12.06.2017
// Внимание! Если программа не работает, обновите версию!

begin
  var n:=ReadInteger('Количество строк в матрице:');
  var m:=ReadInteger('Количество столбцов в матрице:');
  var a:=new real[n,m]; // создали матрицу
  var s:=SeqRandom(m,1000,9999).Select(x->x/100); // шаблон случайной строки
  for var i:=0 to n-1 do a.SetRow(i,s.ToArray); // заполнили матрицу
  Writeln('*** Исходная матрица [',n,',',m,'] ***');
  a.Println(6,2); Writeln(6*a.ColCount*'-');
  // собственно, поиск нужного элемента
  var r:=a.Rows.Select((x,i)->(x.Select((y,j)->(y,j))
    .MinBy(y->y[0]),i)).MaxBy(x->x[0][0]);
  Writeln('Искомый элемент A[',r[1]+1,',',r[0][1]+1,']=',r[0][0])
end.

Вывод получается примерно такой (задание подразумевало индексы от единицы)::

Количество строк в матрице: 4
Количество столбцов в матрице: 7
*** Исходная матрица [4,7] ***
 95.22 17.16 14.35 66.27 20.10 91.88 67.96
 20.80 32.71 45.44 35.80 20.17 58.59 24.22
 93.03 93.99 18.30 75.80 65.47 97.14 56.24
 16.95 73.12 48.54 75.72 91.90 67.95 95.71
------------------------------------------
Искомый элемент A[2,5]=20.17

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

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

begin
  var a := MatrGen(3,4,(i,j)->Random(1000)/100);
  a.Println(6);
end.
1 лайк

Добрый день!

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

Смотря на сколько разнятся версии. В принципе, Вам ничто не мешает переименовать текущую папку, куда установлен PascalABC.NET и сделать новую установку.

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

Можно

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

Может быть, нельзя одновременно работать с несколькими версиями? Ведь PABCRtl.dll не устанавливает какой-то процесс, постоянно находящийся в памяти?

Если отключать запуск с ускорением из оболочки, то можно без конфликтов

Известно, что PascalABC.NET реализует ссылочную объектную модель. Как следствие, если X - объект, принадлежащий некоторому классу, то в результате присваивания var Y:=X произойдет копирование ссылки на X в объявленную переменную Y с автовыводом её класса, но при этом X и Y будут ссылаться на один и тот же объект. Это хорошо, потому что просто и наглядно позволяет написать P:=<выражение> и ни о чем не заботиться. Но одновременно это бывает и плохо. Например, если как было указано выше X и Y - это ссылки на один объект, то изменение, сделанное в Х, будет отражаться и в Y, а также, наоборот. Чтобы избежать такой связки, приходится явно выполнять копирование объекта. Так, для массивов имеется функция Copy и мы пишем a:=Copy(b);

А теперь, собственно, проблема. Пусть создается некий класс P

type P=class
   x:array of real;
   y:real;

   constructor(px:array of real; py:real);
   begin
      x:=Copy(px);
      y:=py
   end;

   constructor (n:integer);
   begin
      x:=new real[n];
      y:=0.0
   end;
end;

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

begin
  var a:=new P(Arr(1.0,2.0,3.0),-1.0);
  var b:=new P(a.x,a.y);
end.

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

type P=class
  x:array of real;
  y:real;

  constructor(px:array of real; py:real);
  begin
    x:=Copy(px);
    y:=py
    end;

  constructor (n:integer);
  begin
    x:=new real[n];
    y:=0.0
    end;
   
  class procedure operator :=(var pp:P; value:P);
  begin
    pp.x:=Copy(value.x);
    pp.y:=Value.y;
    end; 
end;

begin
  var a:=new P(Arr(1.0,2.0,3.0),-1.0);
  var b:=new P(a.x,a.y);
end.

Компилятор ругается на строку var a:=new P(Arr(1.0,2.0,3.0),-1.0); - пишет “Несколько подпрограмм могут быть вызваны”.

Хотелось бы увидеть решение, если оно возможно.

Нет, семантику присваивания менять нельзя. То есть, ссылочное всегда останется ссылочным. Оператор := как в C++ тоже перегружать нельзя. Сакрального знания нет.

напиши функцию clone, делов то?

function clone:= new P(self.x,self.y);

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