Меню

Ошибка трансляции непарные скобки

Исправление ошибки «непарные круглые скобки»

Автор Konstanta, 25 октября 2019, 09:05

0 Пользователи и 1 гость просматривают эту тему.

Приветствую всех!

Простой макрос (поиск последней строки с переходом на число шагов вправо)
в LO вызывает синтаксическую ошибку «Непарные круглые скобки»

Вот код:
Range(«A» & Rows.Count).End(xlUp).Offset(0).Select
ActiveCell.Offset (0;7).Range («A1»).Select

Но все скобки парные! Я не могу понять что именно ему не нравится.


Точку с запятой заменить на запятую.



Так тут и зарыта проблема:
если я ставлю в синтаксисе LO в качестве разделителя точку с запятой, то появляется ошибка не парных круглых скобок.
Если ставлю запятую данная ошибка исчезает и макрос работает, но результат формулы выдаёт ошибку, поскольку LO преобразует формулу по-другому



Мне кажется, Вы путаете два разных языка.

В языке LibreOffice Basic разделителем параметров функций является всегда запятая. А в языке формул Calc разделитель — точка с запятой. Когда Вы задаёте в бейсике строку формулы для калька, в строке формулы должен использоваться синтаксис калька, а в самом бейсике — синтаксис бейска.


Если вы макросом хотите вставить формулу в ячейку, как было в начале поста, то нужно использовать точку с запятой, она является разделителем в табличных формулах. В самом коде vba/starbasic ,  разделитель запятая


Разобрался!

Задача решена, всем Спасибо!


Rust8

0 / 0 / 0

Регистрация: 02.04.2016

Сообщений: 2

1

02.04.2016, 07:20. Показов 2433. Ответов 4

Метки нет (Все метки)


C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include<iostream>
#include<cstdio>
#include<clocale>
using namespace std;
int main()
{
    int a, b, f, i;
    setlocale(LC_CTYPE, "rus");
    for (i = 0; i < 10; i++)
    {
        a = rand();
 
        if (a % 2 == 0)
        {
            cout << a << "-четное число" << endl;
            cout << &a << "-адрес четного числа" << endl;
 
        }
        
        else {
 
            cout << a << "-нечетное число" << endl;
            cout << &a << "-адреса нечетного числа" << endl;
        }
    }
 
 
    system("pause");

__________________
Помощь в написании контрольных, курсовых и дипломных работ, диссертаций здесь



0



Вездепух

Эксперт CЭксперт С++

10420 / 5692 / 1550

Регистрация: 18.10.2014

Сообщений: 14,021

02.04.2016, 09:09

2

И? В коде очевидная непарная фигурная скобка. В чем вопрос-то?



0



SadenSC

2 / 2 / 1

Регистрация: 03.12.2015

Сообщений: 7

02.04.2016, 09:12

3

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include<iostream>
#include<cstdio>
#include<clocale>
#include<cmath>
#include<cstdlib>
using namespace std;
int main()
{
    int a, b, f, i;
    setlocale(LC_CTYPE, "rus");
    for (i = 0; i < 10; i++)
    {
        a = rand();
 
        if (a % 2 == 0)
        {
            cout << a << "-четное число" << endl;
            cout << &a << "-адрес четного числа" << endl;
 
        }
        
        else {
 
            cout << a << "-нечетное число" << endl;
            cout << &a << "-адреса нечетного числа" << endl;
        }
    }
 
    system("pause");
}



1



zss

Модератор

Эксперт С++

12629 / 10127 / 6097

Регистрация: 18.12.2011

Сообщений: 27,158

02.04.2016, 09:39

4

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include<iostream> // ввод-вывод
#include<clocale> //setlocale
#include<cstdlib> // rand srand
#include <ctime> // time
using namespace std;
int main()
{
    setlocale(LC_CTYPE, "rus");
    srand((unsigned)time(NULL));// Задание начального значения датчика случайных чисел
    int a;
    cout<< &a << " - адрес числа" << endl<<endl; // выводим ОДИН раз, адрес не меняется
    for (int i = 0; i < 10; i++)
    {
        a = rand();
        if (a % 2 == 0)
            cout << a << " - четное" << endl;
        else
            cout << a << " - нечетное" << endl;
    }
    system("pause");
    return 0;
}



1



0 / 0 / 0

Регистрация: 02.04.2016

Сообщений: 2

02.04.2016, 11:52

 [ТС]

5

Моя невнимательность, извиняюсь



0



<< вернуться к списку правил

Правило «Непарные скобки или апострофы»

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

Описание: Непарные скобки или апострофы
Категория: Пунктуация

(ID: PUNCTUATION)

Предложения с ошибками,
которые могут быть обнаружены эти правилом:
  • Самоотверженный поступок Оленина (подарок Лукашке коня вызывает лишь удивление и усиливает недоверие к нему станичников.

    Исправления:
    (

Правильные предложения
для проверки:
  • Самоотверженный поступок Оленина (подарок Лукашке коня) вызывает лишь удивление и усиливает недоверие к нему станичников.
Шаблон:

[Java правило]

Sourcecode

Проверить следующий текст только этим правилом:

Номер:

RU_UNPAIRED_BRACKETS

Версия: 6.1-SNAPSHOT (2023-01-29 21:33:03 +0000)

Эти
действия осуществляются в среде
программирования QBASIC.
Для входа в главное меню необходимо
нажать клавишу ALT.
Затем нажать подсвеченную букву пункта
меню и выбрать нужный пункт под меню.
Если пункт подменю оканчивается
троеточием «…», что при выборе
этого пункта возникнет диалоговое окно.

Главное
меню включает пункты «ФАЙЛ, РЕДАКТИРОВАНИЕ,
ПРОСМОТР, ПОИСК, ЗАПУСК, ОТЛАДКА,
ПАРАМЕТРЫ, СПРАВКА». Рассмотрим содержание
пунктов меню:

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

При
редактировании удаление текста слева
от курсора производится клавишей
Backspace
(),
а справа — клавишей Del.
Чтобы копировать, вырезать, удалить
текст, его предварительно необходимо
выделить. Выделяется текст с помощью
комбинации клавиши Shift
+ клавиши со стрелками или с нажатой
левой клавишей мыши. Приемы ввода текста
мало отличаются от работы в других
редакторах. Наиболее применяемые команды
меню дублируются комбинациями клавиш
(см. таблицу 0.0.5).

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

Вот
некоторые приемы, применяемые при
отладке программ. Например, если программа
по 2-й лабораторной работе дает неправильные
значения, то это может быть по двум
причинам: либо неправильно реализованы
формулы, либо не реализовано ветвление
и программа считает не по той формуле.
Чтобы проверить второй вариант, нужно
воспользоваться клавишей F8,
высвечивающей траекторию движения по
программе. При этом строки с оператором
IF…THEN
следует сделать многооператорными,
поставив в конце пустой PRINT.
Если какой-либо оператор мешает
разобраться в причинах появления ошибки,
то его можно вывести из рассмотрения,
не стирая, поставив перед ним оператор
REM.
А чтобы вывести из рассмотрения большой
фрагмент программы, следует использовать
GOTO
с указанием номера строки, куда следует
перепрыгнуть. Чтобы разобраться с
циклом, например, выяснить, правильно
ли считается сумма, можно в него вставить
оператор PRINT,
поставив за ним SLEEP,
организующий паузу до нажатия любой
клавиши. Впрочем, с целью создания паузы
можно применять и просто SLEEP.
Проверить, работает ли цикл или иной
фрагмент программы, можно, использовав
PRINT
«Я здесь».

Таблица 0.0.5.

Назначение
функциональных клавиш в среде
QBASIC

Клавиши

Назначение

F1

Справка
по ключевому слову, функции или
оператору, отмеченному курсором

Shift+F1

Вывод
на дисплей оглавления справочной
информации

F2

Вывод
на экран списка имен всех задействованных
в программе процедур и функций, а также
самой программы

Sfift+F2

Вывод
на экран следующей процедуры или
функции

Ctrl+F2

Вывод
на экран предыдущей процедуры или
функции

F3

Повтор
поиска по ключевому слову

F4

Переход
к экрану вывода и обратно

F5

Продолжение
работы по программе

Shift+F5

Запуск
программы

F6

Переброс
курсора из окна ввода программы в окно
непосредственного счета и обратно

Shift+F6

Переброс
курсора из одной створки окна
редактирования в другую и обратно

F7

Выполнение
программы до курсора

F8

Пошаговое
выполнение программы с заходом в
процедуры и функции

F9

Установка
или снятие контрольной точки в программе

F10

Пошаговое
выполнение программы без захода в
процедуры и функции

Shift+
+клавиши
со
стрелками

Выделение
фрагмента программы

Shift
+Del

Вырезание
фрагмента программы

Ctrl
+Y

Вырезание
строки программы

Shift
+Ins

Вставка
в программу ранее вырезанного фрагмента

Ctrl
+Ins

Копирование
выделенного фрагмента программы

Ctrl
+ Shift

Русский
шрифт (правые), английский (левые)

Ctrl +Break

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

Примечание:

Комбинация
клавиш, например, сначала нажать Ctrl,

затем, не отпуская Ctrl,
нажать Shift

Таблица 0.0.6.

Код

Сообщение об
ошибке и возможная причина

1

NEXT
без
FOR
(NEXT
without FOR)

Для
окончания цикла NEXT
нет соответствующего заголовка FOR.
Количество FOR
и NEXT
должны совпадать

2

Синтаксическая
ошибка
(Syntax error)

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

3

RETURN
без
GOSUB
(RETURN
without GOSUB)

Для
оператора возврата из подпрограммы
RETURN
нет соответствующего обращения к
подпрограмме GOSUB

4

Нет
данных
(Out of DATA)

В
операторе DATA
нет данных. Посчитайте количество
данных в операторе DATA
и количество считываний из него
оператором READ.
Посмотрите внимательно, не поставили
ли вы при перечислении данных в
каком-нибудь месте точку вместо запятой

5

Неверный
вызов
функции
(Illegal function call)

Возникает
чаще всего при попытке извлечения
квадратного корня из отрицательного
числа или появления отрицательного
числа или 0 под знаком логарифма, а
также применения графических операторов
без включения графического режим
SCREEN.
Вообще же подобное сообщение возникает
при попытке вызова функции с недопустимым
параметром

6

Переполнение
(Overflow)

Числовая
переменная или строковая константа
выходят за пределы допустимого
диапазона (например, в знаменателе
получается очень малая величина или
при работе с возведением в степень).
Проверьте и измените значение при
необходимости

7

Не
хватает
памяти
(Out of memory)

8

Метка
не определена
(Label not defined)

Для
операторов GOTO
или GOSUB
задается переход на несуществующую
метку

9

Индекс
вне
диапазона
(Subscript out of range)

Сообщение
возникает при работе с массивами,
когда индекс какого- либо элемента
массива превышает его объявленный в
операторе DIM
размер, а также в том случае, когда
массив занимает в памяти объем более
64 Кбайт. Появляется также, если в
формуле, оперирующей с элементами
массива, они заменены другими переменными
(x(i)
заменен на просто x).

10

Повторяющееся
определение
(Duplicate definition)

Может
возникнуть, если элемент массива,
объявленного в операторе DIM,
фигурирует далее (в формуле или
выражении) в несвязанном или неправильно
связанном виде

Продолжение таблицы
0.0.6.

11

Деление
на ноль
(Division of zero)

Выражение
в знаменателе после подстановки
значений переменных и вычислений,
видимо, обращается в ноль

12

Ошибка в режиме
управления

13

Ошибка ввода

14

В
строке нет места
(Out
of
string
space)

16

Слишком
сложная строковая формула

(String
formula too complex)

17

Невозможно
продолжить

18

Функция
не определена
(Function not defined)

Возможно,
используемая функция не определена
опера-тором DEF
FN,
или допущена ошибка при определении
или вызове функции

19

Нет
RESUME
(No
RESUME)

20

RESUME
без
ошибки
(RESUME
without error)

24

Устройство
в тайм-ауте
(Device timeout)

25

Ошибка
устройства
(Device fault)

26

FOR
без
NEXT (FOR
without NEXT)

Для
заголовка цикла FOR
нет соответствующего окончания цикла
NEXT.
Количество FOR
и NEXT
должны совпадать

27

Нет
бумаги
(Out of paper)

29

WHILE
без
WEND
(WHILE without WHILE)

Для
ключевого слова WHILE
нет соответствующего слова WEND

30

WEND
без
WHILE
(WEND without WHILE)

Для
ключевого слова WEND
нет соответствующего слова WHILE

33

Повторяющаяся
метка
(Duplicate label)

При
расстановке меток допущен повтор
одной и той же метки в разных местах
программы. Обычно возникает при
редактировании текста программы
копированием

35

Подпрограмма не
определена

Сообщение
возникает при попытке обращения к
несуществующей подпрограмме

37

Ошибка счетчика
аргументов

38

Массив не определен

Попытка
работать с элементами массива, который
не был объявлен оператором DIM

39

Требуется
CASE ELSE
(CASE ELSE expected)

40

Необходима
переменная
(Variable required)

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

Продолжение таблицы
0.0.6.

50

Переполнение
FIELD
(FIELD overflow)

51

Внутренняя
ошибка
(Internal
error)

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

52

Плохое
имя файла / плохой номер

(Bad
file name or number)

Имя
файла не соответствует требованиям
DOS
(например, не указан путь для файла не
из текущего каталога)

53

Файл
не
найден
(File not found)

При
попытке обращения к файлу неправильно
указано его имя или путь к нему

54

Плохой
режим файла
(Bad file mod)

Возникает,
если файл создан в редакторе не
совместном с редактором, используемым
в настоящем случае

55

Файл
уже
открыт
(File already open)

Попытка
повторного открытия файла или удаления
открытого файла

56

Оператор
FIELD активен
(FIELD statement activ)

57

Ошибка
в/вв устройства
(Device I/O error)

Ошибка
устройства ввода/вывода, с которой не
справляется DOS.
Попробуйте посмотреть, все ли в порядке
с аппаратной частью, т.е. внешними
устройства компьютера

58

Файл
уже существует
(File already exists)

Попытка
сохранить файл под именем уже
существующего на диске файла

59

Неверная
длина записи
(Bad record length)

61

Диск
заполнен
(Disk full)

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

62

Ошибка:
введен конец файла
(Input
past end of file)

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

63

Неверный
номер
записи
(Bad record number)

64

Плохое
имя
файла
(Bad file name)

Имя
файла не соответствует требованиям
DOS

67

Слишком
много файлов

(Too
many
files)

68

Устройство
недоступно

(Device
unavailable)

В
дисководе нет диска или он испорчен

Окончание таблицы
0.0.6.

69

Переполнение
буфера коммуникации

(Communication-buffer
overflow)

Попытка
копирования в буфер слишком большого
объема информации

70

Нет
разрешения

(Permission
denied)

71

Ошибка
формата диска

(Disk
not
ready)

Открыта
защелка дисковода, в дисководе нет
диска или он испорчен.

72

Ошибка
диска
(Disk-media error)

В
дисководе нет диска или он испорчен

73

Недоступная
возможность
(Advanced
feature unavailable)

74

Переименование
через диски
(Rename
across
disks)

75

Ошибка
доступа к пути / файлу
(Path
/ File
access
error)

76

Путь
не найден
(Path
not
found)

При
попытке обращения к файлу неправильно
указано его имя или путь к нему

dput(head("CustomTransformerData.csv"))

Вот что я пытаюсь сделать:

Применяет класс SimpleImputer к данным, для которых выбрана стратегия. Имя этого шага должно быть «импьютер».

Вот код, который я использую:

import numpy as np
import pandas as pd
import warnings
warnings.filterwarnings('ignore')

fileName = "CustomTransformerData.csv"
custom_transform = pd.read_csv("CustomTransformerData.csv")

data_num = custom_transform.drop(['x3'], axis = 1); #created the df for categorical data

data_cat = custom_transform.drop(['x1', 'x2', 'x4', 'x5'], axis = 1); #created the df for numerical data

#importing sklearn
from sklearn.base import BaseEstimator,TransformerMixin

##creating the transformer
class Assignment4Transformer(BaseEstimator, TransformerMixin):
    def __init__(self, drop_x4 = True, y = None):
        self.drop_x4 = drop_x4 #flag to drop the x4 column
    
    def fit_transform(self, data, y=None):
        return self

from sklearn.pipeline import Pipeline #importing the pipeline
from sklearn.impute import SimpleImputer #importing the SimpleImputer
from sklearn.preprocessing import StandardScaler #importint the preprocessor

def transform(self, data): #starting the function to determine x4
        #not adding the x3 categorical data
        
       
    if self.drop_x4: #a flag to catch and drop x4, giving a new index
        data = np.delete(data, 2, axis=1)
        return np.c_[data, new_col]

num_pipeline = Pipeline([('imputer', SimpleImputer(strategy='mean')]) # this is where I encounter the below error

  File "/var/folders/5v/f6glw1515sqbvblc482qs47c0000gn/T/ipykernel_42484/2823414947.py", line 1
    num_pipeline = Pipeline([('imputer', SimpleImputer(strategy='mean')])
                                                                       ^
SyntaxError: closing parenthesis ']' does not match opening parenthesis '('

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

num_pipeline = Pipeline([('imputer', SimpleImputer(strategy='mean')), 
                         ('attribs_adder', Assignment4Transformer()),])

std_scaler= StandardScaler(num_pipeline)
 
# Splitting the independent and dependent variables
std_scaler = data_num.data
response = data_num.target
 
# standardization 
scale = object.fit_transform(data_num)

TypeError                                 Traceback (most recent call last)
/var/folders/5v/f6glw1515sqbvblc482qs47c0000gn/T/ipykernel_42484/1423714864.py in <module>
----> 1 std_scaler= StandardScaler(num_pipeline)
      2 
      3 # Splitting the independent and dependent variables
      4 std_scaler = data_num.data
      5 response = data_num.target

TypeError: __init__() takes 1 positional argument but 2 were given

Поэтому я не уверен, что второй путь был действительно правильным, и мне просто нужна помощь с этой частью: Применяет пользовательский класс Assignment4Transformer к данным. Убедитесь, что ваш пользовательский преобразователь использует аргумент по умолчанию, когда вы отбрасываете столбец 𝑥4 x 4. Имя этого шага должно быть «custom_trans».

Применяет класс StandardScaler к данным. Имя этого шага должно быть «std_scaler?

Данные: (поскольку он, похоже, не проходит через

    x1  x2  x3  x4  x5          
1   1.5 2.354152979 COLD    593 0.75            
2   2.5 3.31404772  WARM    340 2.083333333         
3   3.5 4.021604459 COLD    551 4.083333333         
4   4.5     COLD    2368    6.75            
5   5.5 5.847601001 WARM    2636    10.08333333         
6   6.5 7.229910044 WARM    2779    14.08333333         
7   7.5 7.997255234 HOT 1057    18.75           
8   8.5 9.203946542 COLD    819 24.08333333         
9   9.5 10.33534766 WARM    3349                
10  10.5    11.11214192 HOT 3235    36.75           
11  11.5    11.75961084 WARM    216 44.08333333         
12  12.5    12.62909577 WARM    2529    52.08333333         
13  13.5    14.08258887 COLD    1735    60.75           
14  14.5    14.65767801 HOT 1254    70.08333333         
15  15.5        HOT 1245    80.08333333         
16  16.6    17.18411403 WARM    310 90.75           
17  17.5    17.80077555 HOT 201 102.0833333         
18  18.5    18.57886101 HOT 1767    114.0833333 

    
                            
                            
                            

1 ответ

В вашем первом блоке кода…

Этот

 num_pipeline = Pipeline([('imputer', SimpleImputer(strategy='mean')])

Должно быть это

 num_pipeline = Pipeline([('imputer', SimpleImputer(strategy='mean'))])

Я добавил закрывающую скобку после SimpleImputer(strategy='mean')

Во втором блоке кода…

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

В вашем коде здесь:

num_pipeline = Pipeline([('imputer', SimpleImputer(strategy='mean')), 
                         ('attribs_adder', Assignment4Transformer()),])

std_scaler= StandardScaler(num_pipeline)

Вы передаете свой num_pipeline классу, но вместо этого должны определить std_scaler, а затем использовать .fit или .fit_transform для данных или добавить его в конвейер следующим образом

num_pipeline = Pipeline([('imputer', SimpleImputer(strategy='mean')), 
                         ('attribs_adder', Assignment4Transformer()),])

std_scaler= StandardScaler()

# applying to data
std_scaler.fit_transform(some_data)

# adding to pipeline at 0th step
num_pipeline.steps.insert(0, ("scale", std_scaler))

# last step
num_pipeline.steps.extend([("scale", std_scaler)])

# some other step???
num_pipeline.steps.insert(1, ("scale", std_scaler))


0

Ian Thompson
5 Ноя 2022 в 00:27

Пишем простой транслятор на Лиспе — I +17

Lisp


Рекомендация: подборка платных и бесплатных курсов создания сайтов — https://katalog-kursov.ru/

Давайте попробуем написать на Лиспе… транслятор простого императивного языка. Нет-нет, я не ошибся – именно транслятор. Транслировать он будет в Лисп-код. А дальше этот код может быть выполнен Лисп-системой.

Здесь бесценную услугу нам окажет то обстоятельство, что в Лиспе нет барьера между кодом и данными (это редкое свойство некоторых языков программирования называется “гомоиконность”). Но и изобразительные возможности Лиспа тоже сыграют не последнюю роль.

В качестве реализации я буду использовать HomeLisp. Желающие смогут адаптировать этот проект под Common Lisp. Скажу сразу – применительно к рассматриваемой задаче существенная разница между Common Lisp и HomeLisp состоит только в обработке строк и файлов.

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

Предлагаемая вашему вниманию тема послужила основой для моей мастерской на знаменитой Новосибирской ЛШЮП-2018. С результатами мастерской можно ознакомиться здесь. А далее я излагаю свой подход. Предполагаю, что читатель знаком с языком Лисп.

Приступаем

Начнем с “простого императивного языка”, который мы будем транслировать в Лисп.
Язык будет обрабатывать только числовые данные. Код на этом языке состоит из функций (процедур, возвращающих значения). Среди этих функций одна должна называться main. Именно с этой функции начинается выполнение кода. Хотя зачем так себя связывать? Пишем функции на императивном языке, они транслируются в Лисп и могут использоваться вместе с лисповскими функциями. Но не будем забегать вперед…

Набор операторов языка обычен: присвоение, ветвление, арифметический цикл, досрочный выход из цикла, ввод, вывод и вызов функции. Впрочем, синтаксически вызов функции оформляется как присвоение (результата вызова). Комментарии пусть содержат звездочку в первой позиции строки. Язык, разумеется, должен обеспечивать возможность создания рекурсивных функций. Чтобы стало понятнее, приведу примеры кода – печать последовательных нечетных чисел и вычисление их суммы:

proc main()
  local s,n,k
  input n
  for i=1 to n
      k=2*i-1
      print k
      s=s+k
  end_for
  print s  
end_proc

По своему духу – это бэйсик-подобный язык. Я буду называть его “мини-бэйсик”. Наш транслятор должен преобразовать приведенный код в следующую Лисп-функцию:

(defun main nil
   (let ((s 0) (n 0) (k 0))
     (setq n (read))
     (iter (for i from 1 to n)
       (setq k (- (* 2 i) 1))
       (printline k)
       (setq s (+ s k)))
   (printline s)))

Мне очень нравится пакет iterate, который в профессиональных пакетах Common Lisp реализован в виде макро. В HomeLisp функция iter (реализующая значительную часть возможностей макро iterate) включена в ядро языка. Мое пристрастие к iter и послужило причиной того, что циклы нашего “мини-бэйсика” будут транслироваться в вызовы iter.

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

(defun start (&optional (fname nil))
   (setq *numline* 0)
   (setq *flagerr* nil)
   (when (null fname)
         (setq fname (sysGetOpenName (sysHome) "Мини-бэйсик|*.mbs")))
   (let ((fi (gensym 'fi)))
        (when fname          
          (filOpen fi fname _INPUT)
          (loop
              (getLine fi) 
              (when (or *flagerr* (filEOF fi)) (return t)))
          (filClose fi)
          (when *flagerr* (printsline "**** Были найдены ошибки"))))
   (unset '*numline*)
   (unset '*flagerr*))

Функция имеет необязательный параметр fname – имя файла, содержимое которого будет транслироваться. При входе в функцию создаются две глобальные переменные numLine номер строки исходного файла и flagerr — флаг состояния ошибки. Перед завершением функции эти переменные уничтожаются (функция HomeLisp-а unset уничтожает глобальные переменные).

Если имя входного файла опущено – то вызывается стандартный windows-диалог выбора файла (sysGetOpenName). В качестве стартовой директории используется текущая директория (sysHome). Далее создается уникальный символ для файлового манипулятора и файл открывается для текстового чтения. Затем в бесконечном цикле производится чтение файла строка за строкой (функция getLine). После каждой операции проверятся, не возникла ли ошибка, и не достигнут ли конец файла. Если возникла ошибка или зафиксирован конец файла – цикл разрывается, файл закрывается, и, если были ошибки – выводится итоговое сообщение.
Собственно чтение из файла выполняет функция getLine:

(defun getLine (fil)
  (let ((stri ""))
    (loop
      (when (filEof fil) (return ""))
      (setq *numline* (add1 *numline*)) 
      (setq stri (filGetline fil))
      (printsline (strCat (format *numline* "0000") " " 
                  (strRTrim stri)))
      (setq stri (strATrim stri)) 
      (unless (or (eq "" stri) (eq "*" (strLeft stri 1))) 
      (return stri)))))

Эта функция принимает идентификатор открытого файла и в бесконечном цикле выполняет следующие действия:

  • проверяет состояние “конец файла”. В этом случае цикл разрывается и функция возвращает пустую строку;
  • увеличивается на единицу счетчик прочитанных строк;
  • читается очередная строка файла;
  • прочитанная строка печатается с удалением возможных пробелов справа;
  • если прочитанная строка непуста и не содержит звездочку в первой позиции, то она
    возвращается из функции;

Таким образом, в выходной листинг попадают все строки файла в их исходном виде.

Разбиваем на процедуры

А теперь давайте научим наш код разбивать входной поток на отдельные процедуры. Сначала введенную строку потребуется разбить на лексемы (неделимые входные лексические единицы). Этот процесс называется парсингом; нам предстоит создать парсер. Написание парсеров — классическая тема, существуют библиотеки готовых парсеров и специальные средства, позволяющие сгенерировать нужный парсер… Мы пойдем своим путем.

Прежде, чем описывать алгоритм парсера, обратим внимание на то, что все символы входной строки можно поделить на два класса:

  • Обычные символы;
  • Символы-разделители.

Так, в операторе присвоения “x = 15 + y^2” символы x,1,5,y и 2 – есть обычные символы, а символы “пробел”, +,^ — разделители. Чем обычный символ отличается от разделителя? Разделитель – всегда отделяет одну лексему от другой. Наш оператор присвоения, будучи разбит на лексемы, выглядит так: “x”, “=”, ”15”, “y”, “^”, “2”.

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

Входом парсера будет строка, выходом – список строковых лексем. В качестве накопителя будет использоваться локальная переменная – аккумулятор. Первоначально аккумулятор содержит пустую строку.

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

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

Вот код парсера:

(defun parser (txt &optional (d1 " ,") (d2 "()+-*/^=<>%"))
  (let ((res nil)
        (lex "") )
   (iter (for s in-string (strCat txt (strLeft d1 1)))
     (cond ((plusp (strInd d1 s))
            (when (> (strLen lex) 0) (collecting lex into res))
                  (setq lex ""))
           ((plusp (strInd d2 s)) 
            (when (> (strLen lex) 0) (collecting lex into res))
                  (collecting s into res)  
                  (setq lex ""))
           (t (setq lex (strCat lex s))))) res))

У функции кроме обязательного параметра имеется два необязательных: d1 содержит строку, каждый символ которой есть разделитель первого типа, а строка d2 содержит разделители второго типа.

Программная логика функции parser описана выше. Следует только отметить, что перед началом работы к концу входной строки присоединяется разделитель. Это сделано для того, чтобы последняя обработанная лексема на “зависла” в аккумуляторе (роль аккумулятора играет локальная переменная lex).

Проверим наш парсер “в деле”:

(parser "x = 15 + y^2")
==> ("x" "=" "15" "+" "y" "^" "2")

Все верно, не так ли? Но работать со списками строк – это не вполне по-лисповски. Давайте от списков строк перейдем к списку атомов. Для этого нам понадобится функция, которая… склеит все лексемы опять в длинную строку (но между лексемами вставит по пробелу), потом к началу этой строки приклеит открывающую скобку, к концу – закрывающую… а затем заставит Лисп прочитать полученный список:

(defun mk-intf (txt)
  (let ((lex (parser txt " ," "()+-*/^=<>%"))
        (intf ""))
   (iter (for a in lex) (setq intf (strCat intf a " ")))
   (input (strCat "(" intf ")"))))

Теперь, если подать на вход функции mk-intf наш оператор присвоения, то получим:

(mk-intf "x = 15 + y^2")
==> (X = 15 + Y ^ 2)

Что, согласитесь, гораздо приятнее.

Теперь немного изменим функцию start: эта функция должна будет читать и обрабатывать целые процедуры:

(defun start (&optional (fname nil))
   (setq *numline* 0)
   (setq *flagerr* nil)
   (when (null fname)
         (setq fname (sysGetOpenName (sysHome) "Мини-бэйсик|*.mbs")))
   (when fname      
      (let ((fi (gensym 'fi)))
           (filOpen fi fname _INPUT)
           (loop
               (let ((curr-proc (action-proc fi)))
                    (when (or *flagerr* (filEOF fi)) (return t))
                    (eval curr-proc)))
           (filClose fi))
           (when *flagerr* (printsline "**** Были найдены ошибки")))
   (unset '*numline*)
   (unset '*flagerr*))

В теле цикла вызывается функция action-proc (обработать процедуру), которая будет формировать тело принятой процедуры уже на Лиспе. Тело процедуры, сохраненное как S-выражение в переменной curr-proc, передается затем на вход eval. И принятая функция “реинкарнируется” в среде Лисп!

Что должна делать action-proc? Эта функция получает в качестве параметра идентификатор открытого файла. Функция читает из файла строку за строкой, пропускает пустые строки и комментарии, остальные строки парсит, переводит в форму списка, и генерирует тело процедуры.

Мы будем постепенно “учить” action-proc генерации. И начнем с того, что научим нашу функцию распознавать начало и конец процедуры. В мини-бэйсике начало процедуры имеет вид:

proc name(p1,p2,p3)

попробуем распарсить такую строку:

(mk-intf "proc name(p1,p2,p3)")
==> (PROC NAME (P1 P2 P3))

Как же должна реагировать на этот ввод функция action-proc? Вполне естественно: убедившись, что голова списка есть атом PROC, нужно взять второй элемент списка как имя функции, а третий элемент – как список параметров. Имя и список параметров следует сохранить в локальных переменных. Когда же прочитывается оператор end_proc, то нужно из имени функции и списка параметров сформировать форму defun с пустым (пока) телом, и вернуть эту форму как результат. Вот как это выглядит:

(defun action-proc (fi)
   (let ((stmt nil)
         (proc-name nil)
         (proc-parm nil))
    (loop
         (setq stmt (mk-intf (getLine fi))) 
         (when (null stmt) (return t))
         (cond ((eq (car stmt) 'proc) 
                    (setq proc-name (nth 1 stmt))
                    (setq proc-parm (nth 2 stmt)))                    
               ((eq (car stmt) 'end_proc) (return t))
               (t (printsline (strCat "**** Оператор " 
                              (output stmt) 
                              " не распознан")) 
                  (setq *flagerr* t))))
    `(defun ,proc-name ,proc-parm (quote OK))))

Для окончательного формирования предложения defun используется обратная блокировка. Обратите внимание на то, что в качестве результата сгенерированная процедура будет выдавать атом OK.

Теперь мы можем проверить наш код в действии. Занесем в файл 0000.mbs следующий код:

proc f1(x,y)
end_proc 
proc f2(x)
end_proc

Запустим процедуру start, выберем 0000.mbs и увидим на консоли:

0001 proc f1(x,y)
0002 end_proc
0003 proc f2(x)
0004 end_proc

При желании можно убедиться, что Лисп-машине теперь доступны две (пока бесполезные) функции f1 и f2:

(getd 'f1)
==> (EXPR (X Y) (QUOTE OK))
(getd 'f2)
==> (EXPR (X) (QUOTE OK))

Более того! Их уже можно и запустить:

(f1 1 2)
==> OK
(f2 2)
==> OK

Наш транслятор сделал первый вдох…

Ввод, вывод и локальные переменные

А сейчас самое время научить наш новорожденный транслятор обрабатывать операторы input, print и local.

Проще всего обработаем ввод и печать. Оба оператора имеют одинаковую синтаксическую структуру: ключевое слово и переменная. Оператор input x должен превратиться в такую Лисп-форму (setq x (read)). Соответственно, оператор print x превращается в форму (printline x). Для хранения этих форм необходимо в функции action-proc предусмотреть локальную переменную body. В этой переменной будут накапливаться формы, осуществляющие вычисления будущей функции. Дальше все довольно просто:

(defun action-proc (fi)
   (let ((stmt nil)
         (proc-name nil)
         (proc-parm nil)
         (loc-var nil)
         (body nil))
    (loop
         (setq stmt (mk-intf (getLine fi))) 
         (when (null stmt) (return t))
         (cond ((eq (car stmt) 'proc) 
                    (setq proc-name (nth 1 stmt))
                    (setq proc-parm (nth 2 stmt)))                    
               ((eq (car stmt) 'end_proc) (return t))
               ((eq (car stmt) 'print) 
                    (setq body (append body 
                               (list (cons 'printline (cdr stmt))))))
               ((eq (car stmt) 'input) 
                    (setq body (append body 
                      (list (list 'setq (cadr stmt) (list 'read) )))))
               (t (printsline (strCat "**** Оператор " 
                              (output stmt) 
                              " не распознан"))
                              (setq *flagerr* t))))
    `(defun ,proc-name ,proc-parm ,@body)))

Давайте теперь подготовим вот такой исходник на мини-бэйсике:

proc f1(x,y)
 print x
 print y
end_proc 
proc f2(x)
 input x
 print x
end_proc

и попробуем его протранслировать… У нас появятся две лисповские функции f1 и f2. Посмотрим на их определяющие выражения и убедимся, что они сгенерированы верно:

(getd 'f1)
==> (EXPR (X Y) (PRINTLINE X) (PRINTLINE Y))
(getd 'f2)
==> (EXPR (X) (SETQ X (READ)) (PRINTLINE X))

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

Оператор local может находиться в любом месте процедуры и встречаться более одного раза. Если в процессе обработки процедуры встретился оператор local, то необходимо взять список переменных и сохранить его в локальной переменной. После встречи оператора end_proc необходимо сгенерировать форму let и “заключить в нее” все выполняемые операторы (пока – только input и print). Вот как теперь будет выглядеть action-proc:

(defun action-proc (fi)
   (let ((stmt nil)
         (proc-name nil)
         (proc-parm nil)
         (loc-var   nil)
         (lv        nil)
         (body      nil))
    (loop
         (setq stmt (mk-intf (getLine fi))) 
         (when (null stmt) (return t))
         (cond ((eq (car stmt) 'proc) 
                    (setq proc-name (nth 1 stmt))
                    (setq proc-parm (nth 2 stmt)))                    
               ((eq (car stmt) 'end_proc) (return t))
               ((eq (car stmt) 'print) 
                    (setq body (append body 
                               (list (cons 'printline (cdr stmt))))))
               ((eq (car stmt) 'input) 
                    (setq body (append body 
                               (list (list 'setq (cadr stmt) 
                                     (list 'read) )))))
               ((eq (car stmt) 'local) 
                    (setq loc-var (append loc-var (cdr stmt))))
               (t (printsline (strCat "**** Оператор " 
                              (output stmt) " не распознан")) 
                              (setq *flagerr* t))))
    (iter (for a in (setof loc-var)) (collecting (list a 0) into lv))           
    `(defun ,proc-name ,proc-parm (let ,lv ,@body))))

Список локальных переменных накапливается в переменной loc-var. После завершения обработки процедуры из этого списка строится список пар вида (имя 0). При этом нежелательно повторение одинаковых имен… Как его предотвратить? Конечно, можно на каждой обработке оператора local проверять, нет ли повторения имен (если есть – выдавать сообщение об ошибке). Но, мне кажется, лучше просто устранить повторения, что и делает вызов setof. Теперь давайте протранслируем и запустим вот эту программу:

proc f1(x,y)
 local a,b,c
 print x
 print y
 input a
 print a
end_proc

Убеждаемся, что она работает именно так, как и предполагает алгоритм. Но все самое интересное впереди!

Отсюда можно скачать окончательный вариант того, что мы с вами нашкодили…

Продолжение следует!

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

Таблица 1 – Сообщения об ошибках и их коды

Код

Сообщение об ошибке

1

NEXT без FOR

Для окончания цикла NEXT нет соответствующего заголовка FOR. Количество FOR и NEXT должно совпадать

2

Синтаксическая ошибка

Оператор содержит грамматическую ошибку в написании ключево­го слова или ошибку в пунктуации, либо есть непарные скобки или другие нарушения правил синтаксиса языка Бейсик

3

RETURN без GOSUB

Для оператора возврата из подпрограммы RETURN нет соответствующего обращения к подпрограмме GOSUB

4

Нет данных

В операторе DATA нет данных. Посчитайте количество данных в операторе DATA и количество считываний из него оператором READ. Посмотрите внимательно, не поставили ли вы при перечислении данных в каком-нибудь месте точку вместо запятой

5

Неверный вызов функции

Возникает чаще всего при попытке извлечения квадратного корня из отрицательного числа или применения графических операторов без включения графического режима SCREEN. Вообще же подобное сообщение возникает при попытке вызова функции с недопусти­мым параметром

6

Переполнение

Числовая переменная или строковая константа выходят за пределы допустимого диапазона. Проверьте и измените значение в случае необходимости

7

Не хватает памяти

8

Метка не определена

Оператор GOTO или GOSUB пытаются осуществить переход на несу­ществующую метку

9

Индекс вне режима

Сообщение возникает при работе «с массивами, когда индекс како­го-либо элемента массива превышает его объявленный в операторе DIM размер, а также в том случае, когда массив занимает в памяти объем более 64 Кбайт

10

Повторяющееся определение

11

Деление на ноль

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

12

Ошибка в режиме управления

13

Ошибка ввода

14

В строке нет места

16

Слишком сложная строковая формула

17

Невозможно продолжить

18

Функция не определена

Возможно, используемая функция не определена оператором DEF FN, или допущена ошибка при определении или вызове функции

19

Нет RESUME

20

RESUME без ошибки

24

Устройство в тайм-ауте

25

Ошибка устройства

26

FOR без NEXT

Для заголовка цикла FOR нет соответствующего окончания цикла NEXT. Количество FOR и NEXT должно совпадать

21

Нет бумаги

29

WHILE без WEND

Для ключевого слова WHILE нет соответствующего слова WEND

30

WEND без WHILE

Для ключевого слова WEND нет соответствующего слова WHILE

33

Повторяющаяся метка

При расстановке меток допущен повтор одной и той же метки в разных местах программы

35

Подпрограмма не определена

Сообщение возникает при попытке обращения к несуществующей подпрограмме

37

Ошибка счетчика аргументов

38

Массив не определен

Попытка работать с элементами массива, который не был объявлен оператором DIM

40

Необходима переменная

50

Переполнение FIELD

51

Внутренняя ошибка

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

52

Плохое имя файла/плохой номер

Имя файла не соответствует требованиям DOS

53

Файл не найден

При попытке обращения к файлу указано неправильное его имя или путь к нему

54

Плохой режим файла

55

Файл уже открыт

Попытка повторного открытия файла или удаления открытого файла

56

Оператор FIELD активен

57

Ошибка в/вв устройства

Ошибка устройства ввода/вывода, с которой не справляется DOS

Попробуйте посмотреть, все ли в порядке с аппаратной частью, т. е. внешними устройствами компьютера

58

Файл уже существует

Попытка сохранить файл под именем уже существующего на диске файла

59

Неверная длина записи

61

Диск заполнен

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

62

Ошибка: введен конец файла

63

Неверный номер записи

64

Плохое имя файла

Имя файла не соответствует требованиям DOS

67

Слишком много файлов

68

Устройство недоступно

В дисководе нет диска или он испорчен

69

Переполнение буфера коммуникации

Попытка копирования в буфер слишком большого обьема инфор­мации

70

Нет разрешения

71

Ошибка формата диска

В дисководе нет диска или он испорчен

72

Ошибка диска

В дисководе нет диска или он испорчен

73

Недоступная возможность

74

Переименование через диски

75

Ошибка доступа к пути/файлу

76

Путь не найден

При попытке обращения к файлу указано неправильное его имя или путь к нему

1

2

Показывать по
10
20
40
сообщений

Новая тема

Ответить

Ласка31

Дата регистрации: 21.12.2011
Сообщений: 1

rulevoy4,у меня проблема с новым контрагентом — при создании нового договора выдает ошибку » словосочетание содержит непарные скобки или кавычки». Оказалось, что при вводе ИНН и заполнении данных контрагента теперь автоматически заполняется вкладка «Контактные лица». В моем случае в графе «Должность» было указано: Генеральный директор ооо «ук «крата». Как только я убрала в строке Представление: Генеральный директор ооо «ук «крата» программа дала возможность создать новый договор у данного контрагента.

sergey dubovik

Дата регистрации: 18.02.2020
Сообщений: 1

Все просто, необходимо зайти в Администрирование — Интернет — поддержка и сервисы — Склонения представлений объектов и поставить галочку «Использовать альтернативный сервис склонений Морфер»

Контрольное Cоотношение Равенство

Дата регистрации: 28.01.2018
Сообщений: 229

Цитата
Наталья пишет:

1С:Предприятие 8.3 (8.3.15.1830) Бухгалтерия предприятия, редакция 3.0 (3.0.75.37) проф при загрузке из банка УралСиб в бухгалтерию 8.3 выходит ошибка — словосочетание содержит непарные скобки или кавычки, не удается провести выгруженную платежку на выплату зарплаты по зарплатному реестр. Помогите, кто может у

исправлено в последнем обновлении БП 3.0.80.36 от 29.07.2020

Цитирую баг-трекер:

https://bugboard.v8.1c.ru/version/bp3/000022264?status=fixed&page=3
Ошибка при открытии договора

Код ошибки: 10223303
Статус: Исправлена в выпущенной версии
Зарегистрирована: 05.06.2020

Исправлена: «Бухгалтерия предприятия, редакция 3.0», версия 3.0.80.36

Описание:
3.0.80.36
Если открыть ранее созданный договор с поставщиком, то появляется сообщение «Словосочетание содержит непарные скобки или кавычки»

0 0 голоса
Рейтинг статьи
Подписаться
Уведомить о
guest

0 комментариев
Старые
Новые Популярные
Межтекстовые Отзывы
Посмотреть все комментарии

А вот еще интересные материалы:

  • Яшка сломя голову остановился исправьте ошибки
  • Ясность цели позволяет целеустремленно добиваться намеченного исправьте ошибки
  • Ясность цели позволяет целеустремленно добиваться намеченного где ошибка
  • Ошибка тони вендиса фильм где снимали
  • Ошибка трансляции неверное объявление процедуры