Цикл «для»

This commit is contained in:
rexim 2024-02-28 01:05:50 +07:00
parent c88594805a
commit 18ac43be10
8 changed files with 130 additions and 99 deletions

View File

@ -28,12 +28,14 @@
- [x] Инициализация локальных переменных
- [x] Локальные массивы
- [x] Локальные константы
- [ ] Циклы «для»
- [x] Циклы «для»
- [ ] Объявление переменных в цикле «для»
- [ ] Перечисления в каком-нибудь виде
- [ ] Switch-case-ы в каком-то виде
- [ ] Динамическая память в каком-нибудь виде
- [ ] Типизированные константы
- [ ] Через интерпретацию ПП
- [ ] Передача переменных по ссылке
- [ ] Перечисления в каком-нибудь виде
- [ ] Динамическая память в каком-нибудь виде
- [ ] Знаковые целые
- [ ] Что дальше?

View File

@ -304,19 +304,10 @@ fn скомпилировать_выражение(пп: &mut ПП, имена:
return Ok(Тип::Цел64);
}
if let Some((переменная, локация)) = найти_переменную_по_имени(&лексема.текст, имена, текущая_процедура, локальные_имена) {
match локация {
Локация::Глобальная => {
пп.заплаткиеиниц_указателей.push(пп.код.len());
пп.код.push(Инструкция{ вид: ВидИнструкции::ГлобальныеДанные(переменная.смещение), лок: лексема.лок.clone() });
}
Локация::Стековая => {
пп.код.push(Инструкция{ вид: ВидИнструкции::Кадр(переменная.смещение), лок: лексема.лок.clone() });
}
}
локация.протолкнуть_смещение(пп, &лексема.лок, переменная.смещение);
if переменная.тип.примитивный() {
прочитать_примитивный_тип(&лексема.лок, &mut пп.код, переменная.тип.размер(&имена.структуры))?;
}
return Ok(переменная.тип.clone());
}
@ -566,15 +557,7 @@ fn скомпилировать_выражение(пп: &mut ПП, имена:
}
// СДЕЛАТЬ: принимать срез по аналогии с ПечатьСтроки
match локация {
Локация::Глобальная => {
пп.заплаткиеиниц_указателей.push(пп.код.len());
пп.код.push(Инструкция{ вид: ВидИнструкции::ГлобальныеДанные(переменная.смещение), лок: имя.лок.clone() });
}
Локация::Стековая => {
пп.код.push(Инструкция{ вид: ВидИнструкции::Кадр(переменная.смещение), лок: имя.лок.clone() });
}
}
локация.протолкнуть_смещение(пп, &имя.лок, переменная.смещение);
пп.код.push(Инструкция{ вид: ВидИнструкции::Целое(*размер), лок: имя.лок.clone() });
пп.код.push(Инструкция{ вид: ВидИнструкции::Ввод, лок: имя.лок.clone() });
return Ok(Тип::Цел64);
@ -622,16 +605,7 @@ fn скомпилировать_выражение(пп: &mut ПП, имена:
let тип_размера_среза = скомпилировать_выражение(пп, имена, текущая_процедура, локальные_имена, &размер_среза, временный_размер)?;
проверить_типы(&размер_среза.лок(), &Тип::Цел64, &тип_размера_среза)?;
match локация {
Локация::Глобальная => {
пп.заплаткиеиниц_указателей.push(пп.код.len());
пп.код.push(Инструкция{ вид: ВидИнструкции::ГлобальныеДанные(переменная.смещение), лок: имя.лок.clone() });
}
Локация::Стековая => {
пп.код.push(Инструкция{ вид: ВидИнструкции::Кадр(переменная.смещение), лок: имя.лок.clone() });
}
}
локация.протолкнуть_смещение(пп, &имя.лок, переменная.смещение);
let типачала = скомпилировать_выражение(пп, имена, текущая_процедура, локальные_имена, &начало_среза, временный_размер)?;
проверить_типы(&размер_среза.лок(), &Тип::Цел64, &типачала)?;
@ -747,15 +721,7 @@ fn скомпилировать_выражение(пп: &mut ПП, имена:
return Err(());
};
match локация {
Локация::Глобальная => {
пп.заплаткиеиниц_указателей.push(пп.код.len());
пп.код.push(Инструкция{вид: ВидИнструкции::ГлобальныеДанные(переменная.смещение), лок: имя.лок.clone()});
}
Локация::Стековая => {
пп.код.push(Инструкция{вид: ВидИнструкции::Кадр(переменная.смещение), лок: имя.лок.clone()});
}
}
локация.протолкнуть_смещение(пп, &имя.лок, переменная.смещение);
// СДЕЛАТЬ: проверка входа за границы массива.
@ -880,6 +846,20 @@ enum Локация {
Стековая,
}
impl Локация {
fn протолкнуть_смещение(&self, пп: &mut ПП, лок: &Лок, смещение: i32) {
match self {
Локация::Глобальная => {
пп.заплаткиеиниц_указателей.push(пп.код.len());
пп.код.push(Инструкция{ вид: ВидИнструкции::ГлобальныеДанные(смещение), лок: лок.clone() });
}
Локация::Стековая => {
пп.код.push(Инструкция{ вид: ВидИнструкции::Кадр(смещение), лок: лок.clone() });
}
}
}
}
fn найтионстанту_по_имени<'ы>(имя: &str, имена: &'ы Имена, локальные_имена: Option<&'ы ЛокальныеИмена>) -> Option<&'ы СкомпКонстанта> {
if let Some(локальные_имена) = локальные_имена {
if let Some(константа) = локальные_имена.найтионстанту_по_имени(имя) {
@ -936,15 +916,7 @@ fn скомпилировать_левое_выражение(пп: &mut ПП,
}
Выражение::Идент(имя) => {
if let Some((переменная, локация)) = найти_переменную_по_имени(&имя.текст, имена, текущая_процедура, локальные_имена) {
match локация {
Локация::Глобальная => {
пп.заплаткиеиниц_указателей.push(пп.код.len());
пп.код.push(Инструкция{ вид: ВидИнструкции::ГлобальныеДанные(переменная.смещение), лок: имя.лок.clone() });
}
Локация::Стековая => {
пп.код.push(Инструкция{ вид: ВидИнструкции::Кадр(переменная.смещение), лок: имя.лок.clone() });
}
}
локация.протолкнуть_смещение(пп, &имя.лок, переменная.смещение);
return Ok(переменная.тип.clone());
}
@ -959,15 +931,7 @@ fn скомпилировать_левое_выражение(пп: &mut ПП,
let индекс = &аргументы[0];
if let Some((переменная, локация)) = найти_переменную_по_имени(&имя.текст, имена, текущая_процедура, локальные_имена) {
match локация {
Локация::Глобальная => {
пп.заплаткиеиниц_указателей.push(пп.код.len());
пп.код.push(Инструкция{ вид: ВидИнструкции::ГлобальныеДанные(переменная.смещение), лок: имя.лок.clone() });
}
Локация::Стековая => {
пп.код.push(Инструкция{ вид: ВидИнструкции::Кадр(переменная.смещение), лок: имя.лок.clone() });
}
}
локация.протолкнуть_смещение(пп, &имя.лок, переменная.смещение);
let тип_элемента = индексироватьассив(&имя.лок, переменная, пп, имена, текущая_процедура, локальные_имена, индекс, временный_размер)?;
return Ok(тип_элемента);
}
@ -1027,6 +991,16 @@ fn скомпилировать_левое_выражение(пп: &mut ПП,
}
}
fn записать_тип(лок: &Лок, код: &mut Vec<Инструкция>, структуры: &HashMap<String, Структура>, тип: &Тип) -> Результат<()> {
if тип.примитивный() {
записать_примитивный_тип(лок, код, тип.размер(структуры))?;
} else {
код.push(Инструкция{ вид: ВидИнструкции::Целое(тип.размер(структуры)), лок: лок.clone() });
код.push(Инструкция{ вид: ВидИнструкции::СкопироватьПамять, лок: лок.clone() });
}
Ok(())
}
fn скомпилировать_утверждение(пп: &mut ПП, имена: &Имена, текущая_процедура: &СкомпПроцедура, локальные_имена: &mut ЛокальныеИмена, утверждение: &Утверждение, отложенныеозвраты: &mut Vec<usize>) -> Результат<()> {
match утверждение {
Утверждение::Присваивание{ключ, левое, правое} => {
@ -1034,12 +1008,7 @@ fn скомпилировать_утверждение(пп: &mut ПП, имен
let правый_тип = скомпилировать_выражение(пп, имена, текущая_процедура, локальные_имена, правое, &mut временный_размер)?;
let левый_тип = скомпилироватьевое_выражение(пп, имена, текущая_процедура, локальные_имена, левое, &mut временный_размер)?;
проверить_типы(правое.лок(), &левый_тип, &правый_тип)?;
if левый_тип.примитивный() {
записать_примитивный_тип(&ключ.лок, &mut пп.код, левый_тип.размер(&имена.структуры))?;
} else {
пп.код.push(Инструкция{ вид: ВидИнструкции::Целое(левый_тип.размер(&имена.структуры)), лок: ключ.лок.clone() });
пп.код.push(Инструкция{ вид: ВидИнструкции::СкопироватьПамять, лок: ключ.лок.clone() });
}
записать_тип(&ключ.лок, &mut пп.код, &имена.структуры, &левый_тип)?;
if временный_размер > 0 {
пп.код.push(Инструкция{ вид: ВидИнструкции::ОсвободитьСоСтека(временный_размер as u64), лок: ключ.лок.clone() })
}
@ -1193,12 +1162,7 @@ fn скомпилировать_утверждение(пп: &mut ПП, имен
let тип = скомпилировать_выражение(пп, имена, текущая_процедура, локальные_имена, &выражение, &mut временный_размер)?;
проверить_типы(&выражение.лок(), &результат.тип, &тип)?;
пп.код.push(Инструкция{ вид: ВидИнструкции::Кадр(результат.смещение_от_кадра), лок: ключ.лок.clone() });
if тип.примитивный() {
записать_примитивный_тип(&ключ.лок, &mut пп.код, тип.размер(&имена.структуры))?;
} else {
пп.код.push(Инструкция{ вид: ВидИнструкции::Целое(тип.размер(&имена.структуры)), лок: ключ.лок.clone() });
пп.код.push(Инструкция{ вид: ВидИнструкции::СкопироватьПамять, лок: ключ.лок.clone() });
}
записать_тип(&ключ.лок, &mut пп.код, &имена.структуры, &тип)?;
let размерсехокальных_переменных = локальные_имена
.стек_областей
.iter()
@ -1251,6 +1215,69 @@ fn скомпилировать_утверждение(пп: &mut ПП, имен
пп.код[точка_условного_прыжка].вид = ВидИнструкции::УсловныйПрыжок(точка_выхода);
Ok(())
}
Утверждение::Для{ключ, индекс, нижняя_граница, верхняя_граница, тело} => {
if let Some((переменная, локация)) = найти_переменную_по_имени(&индекс.текст, имена, текущая_процедура, локальные_имена) {
проверить_типы(&индекс.лок, &Тип::Цел64, &переменная.тип)?;
// Инициализация индексной переменной
let mut временный_размер = 0;
let тип_нижней_границы = скомпилировать_выражение(пп, имена, текущая_процедура, локальные_имена, &нижняя_граница, &mut временный_размер)?;
проверить_типы(&нижняя_граница.лок(), &переменная.тип, &тип_нижней_границы)?;
локация.протолкнуть_смещение(пп, &индекс.лок, переменная.смещение);
записать_тип(&индекс.лок, &mut пп.код, &имена.структуры, &переменная.тип)?;
if временный_размер > 0 {
пп.код.push(Инструкция{ вид: ВидИнструкции::ОсвободитьСоСтека(временный_размер as u64), лок: ключ.лок.clone() });
временный_размер = 0;
}
// Проверка условия выхода из цикла
let точка_условия = пп.код.len();
локация.протолкнуть_смещение(пп, &индекс.лок, переменная.смещение);
прочитать_примитивный_тип(&индекс.лок, &mut пп.код, переменная.тип.размер(&имена.структуры))?;
let типерхней_границы = скомпилировать_выражение(пп, имена, текущая_процедура, локальные_имена, &верхняя_граница, &mut временный_размер)?;
проверить_типы(&верхняя_граница.лок(), &переменная.тип, &типерхней_границы)?;
пп.код.push(Инструкция{ вид: ВидИнструкции::ЦелБольше, лок: ключ.лок.clone() });
let точка_условного_прыжка = пп.код.len();
пп.код.push(Инструкция{ вид: ВидИнструкции::Ноп, лок: ключ.лок.clone() });
if временный_размер > 0 {
пп.код.push(Инструкция{ вид: ВидИнструкции::ОсвободитьСоСтека(временный_размер as u64), лок: ключ.лок.clone() });
}
let переменная_тип = переменная.тип.clone();
let переменная_смещение = переменная.смещение;
// Тело
локальные_имена.стек_областей.push(Default::default());
for утверждение in тело.iter() {
скомпилировать_утверждение(пп, имена, текущая_процедура, локальные_имена, утверждение, отложенныеозвраты)?;
}
let размер_области = локальные_имена
.стек_областей
.pop()
.expect("Тело цикла «для» не трогает область которую мы протолкнули")
.размер_переменныха_стеке;
if размер_области > 0 {
пп.код.push(Инструкция{ вид: ВидИнструкции::ОсвободитьСоСтека(размер_области as u64), лок: ключ.лок.clone() });
}
// Инкремент
локация.протолкнуть_смещение(пп, &индекс.лок, переменная_смещение);
прочитать_примитивный_тип(&индекс.лок, &mut пп.код, переменная_тип.размер(&имена.структуры))?;
пп.код.push(Инструкция{ вид: ВидИнструкции::Целое(1), лок: ключ.лок.clone() });
пп.код.push(Инструкция{ вид: ВидИнструкции::ЦелСложение, лок: ключ.лок.clone() });
локация.протолкнуть_смещение(пп, &индекс.лок, переменная_смещение);
записать_тип(&индекс.лок, &mut пп.код, &имена.структуры, &переменная_тип)?;
пп.код.push(Инструкция{ вид: ВидИнструкции::Прыжок(точка_условия), лок: ключ.лок.clone() });
let точка_выхода = пп.код.len();
пп.код[точка_условного_прыжка].вид = ВидИнструкции::УсловныйПрыжок(точка_выхода);
return Ok(())
}
диагностика!(&индекс.лок, "ОШИБКА", "Неизвестная переменная «{имя}»", имя = индекс.текст);
Err(())
}
Утверждение::ДекларацияПеременной{ключ, имя, тип, значение} => {
let размерсехокальных_переменных = локальные_имена
.стек_областей
@ -1271,12 +1298,7 @@ fn скомпилировать_утверждение(пп: &mut ПП, имен
let тип_значения = скомпилировать_выражение(пп, имена, текущая_процедура, локальные_имена, значение, &mut временный_размер)?;
проверить_типы(&значение.лок(), &тип_переменной, &тип_значения)?;
пп.код.push(Инструкция{ вид: ВидИнструкции::Кадр(смещение), лок: ключ.лок.clone() });
if тип_переменной.примитивный() {
записать_примитивный_тип(&ключ.лок, &mut пп.код, тип_переменной.размер(&имена.структуры))?;
} else {
пп.код.push(Инструкция{ вид: ВидИнструкции::Целое(тип_переменной.размер(&имена.структуры)), лок: ключ.лок.clone() });
пп.код.push(Инструкция{ вид: ВидИнструкции::СкопироватьПамять, лок: ключ.лок.clone() });
}
записать_тип(&ключ.лок, &mut пп.код, &имена.структуры, &тип_переменной)?;
if временный_размер > 0 {
пп.код.push(Инструкция{ вид: ВидИнструкции::ОсвободитьСоСтека(временный_размер as u64), лок: ключ.лок.clone() });
}

View File

@ -7,6 +7,7 @@ pub const ПРИСТАВКИ_ПРЕПИНАНИЙ: &[(&[char], ВидЛексе
(&['('], ВидЛексемы::ОткрытаяСкобка),
(&[')'], ВидЛексемы::ЗакрытаяСкобка),
(&[';'], ВидЛексемы::ТочкаЗапятая),
(&['.', '.'], ВидЛексемы::ТочкаТочка),
(&['.'], ВидЛексемы::Точка),
(&[':', '='], ВидЛексемы::Присваивание),
(&[':'], ВидЛексемы::Двоеточие),
@ -29,6 +30,7 @@ pub const КЛЮЧЕВЫЕ_СЛОВА: &[(&str, ВидЛексемы)] = &[
("то", ВидЛексемы::КлючТо),
("иначе", ВидЛексемы::КлючИначе),
("пока", ВидЛексемы::КлючПока),
("для", ВидЛексемы::КлючДля),
("вернуть", ВидЛексемы::КлючВернуть),
("не", ВидЛексемы::КлючНе),
("мн", ВидЛексемы::КлючМн),
@ -57,6 +59,7 @@ pub enum ВидЛексемы {
КлючТо,
КлючИначе,
КлючПока,
КлючДля,
КлючВернуть,
КлючНе,
КлючМн,
@ -76,6 +79,7 @@ pub enum ВидЛексемы {
ЗакрытаяСкобка,
ТочкаЗапятая,
Точка,
ТочкаТочка,
Двоеточие,
Запятая,
Плюс,
@ -106,6 +110,7 @@ impl ВидЛексемы {
ВидЛексемы::КлючТо => Сущ{текст: "«то»", род: Род::Сред},
ВидЛексемы::КлючИначе => Сущ{текст: "«иначе»", род: Род::Сред},
ВидЛексемы::КлючПока => Сущ{текст: "«пока»", род: Род::Сред},
ВидЛексемы::КлючДля => Сущ{текст: "«для»", род: Род::Сред},
ВидЛексемы::КлючВернуть => Сущ{текст: "«вернуть»", род: Род::Сред},
ВидЛексемы::КлючНе => Сущ{текст: "«не»", род: Род::Сред},
ВидЛексемы::КлючМн => Сущ{текст: "«мн»", род: Род::Сред},
@ -126,6 +131,7 @@ impl ВидЛексемы {
ВидЛексемы::ЗакрытаяСкобка => Сущ{текст: "закрытая скобка", род: Род::Жен},
ВидЛексемы::ТочкаЗапятая => Сущ{текст: "точка с запятой", род: Род::Жен},
ВидЛексемы::Точка => Сущ{текст: "точка", род: Род::Жен},
ВидЛексемы::ТочкаТочка => Сущ{текст: "точка точка", род: Род::Жен},
ВидЛексемы::Двоеточие => Сущ{текст: "двоеточие", род: Род::Сред},
ВидЛексемы::Запятая => Сущ{текст: "запятая", род: Род::Жен},
ВидЛексемы::Плюс => Сущ{текст: "плюс", род: Род::Муж},
@ -262,7 +268,9 @@ impl<'a> Лексер<'a> {
while self.символы.get(self.позиция).map(|сим| сим.is_numeric()).unwrap_or(false) {
self.отрезать_символ();
}
if let Some('.') = self.символы.get(self.позиция) {
// Это условие крайне важно, чтобы разобрать выражение
// "1..10" как "1", "..", "10".
if Some('.') == self.символы.get(self.позиция).cloned() && Some('.') != self.символы.get(self.позиция + 1).cloned() {
self.отрезать_символ();
while self.символы.get(self.позиция).map(|сим| сим.is_numeric()).unwrap_or(false) {
self.отрезать_символ();

View File

@ -211,6 +211,7 @@ pub enum Утверждение {
Присваивание{ключ: Лексема, левое: Выражение, правое: Выражение},
Выражение{выражение: Выражение},
Пока{ключ: Лексема, условие: Выражение, тело: Vec<Утверждение>},
Для{ключ: Лексема, индекс: Лексема, нижняя_граница: Выражение, верхняя_граница: Выражение, тело: Vec<Утверждение>},
Если{ключ: Лексема, условие: Выражение, тело: Vec<Утверждение>, иначе: Vec<Утверждение>},
Вернуть{ключ: Лексема, выражение: Option<Выражение>},
ДекларацияПеременной{ключ: Лексема, имя: Лексема, тип: Выражение, значение: Option<Выражение>},
@ -258,6 +259,16 @@ fn разобрать_утверждение(лекс: &mut Лексер) -> Р
let тело = разобрать_блок_кода(лекс)?;
Ok(Утверждение::Пока{ключ, условие, тело})
}
ВидЛексемы::КлючДля => {
let ключ = лекс.вытащитьексему().unwrap();
let индекс = лекс.вытащитьексему_вида(&[ВидЛексемы::Идент])?;
let _ = лекс.вытащитьексему_вида(&[ВидЛексемы::Присваивание])?;
let нижняя_граница = Выражение::разобрать(лекс)?;
let _ = лекс.вытащитьексему_вида(&[ВидЛексемы::ТочкаТочка])?;
let верхняя_граница = Выражение::разобрать(лекс)?;
let тело = разобрать_блок_кода(лекс)?;
Ok(Утверждение::Для{ключ, индекс, нижняя_граница, верхняя_граница, тело})
}
ВидЛексемы::КлючВернуть => {
let ключ = лекс.вытащитьексему().unwrap();
if лекс.подсмотретьексему()?.вид == ВидЛексемы::ТочкаЗапятая {

View File

@ -4,8 +4,5 @@
про главная() нч
пер а: цел = 0;
пока а мн РАЗМЕР нч
печать(а, «\н»);
а := а + 1;
кц
для пер а := 1..РАЗМЕР то печать(а-1, «\н»);
кц

View File

@ -1,17 +1,14 @@
вкл прелюдия;
конст ЛИМИТ = 100;
про главная() нч
// // СДЕЛАТЬ: цикл «для»
// для счет := 1..ЛИМИТ нч
пер счет: цел = 1;
пока счет мн ЛИМИТ + 1 нч // СДЕЛАТЬ: ввести операцию мнрв
// СДЕЛАТЬ: объявление индексной переменной прямо в цикле
// для пер счет := 1..100 нч
пер счет: цел;
для счет := 1..100 нч
если счет % 15 == 0 то печать(«ФиззБазз\н»);
// СДЕЛАТЬ: подумать как сократить конструкцию «иначе то если»
иначе то если счет % 3 == 0 то печать(«Физз\н»);
иначе то если счет % 5 == 0 то печать(«Базз\н»);
иначе то печать(счет, «\н»);
счет := счет + 1;
кц
кц

View File

@ -24,13 +24,12 @@
про главная() нч
установить_случайное_семя(69);
пер индекс: цел = 0;
пока индекс мн ОБЪЁМ нч
пер индекс: цел;
для индекс := 0..ОБЪЁМ-1 нч
позиции(индекс).икс := случайноеещественное()*50.0;
позиции(индекс).игрек := случайноеещественное()*10.0;
дельты(индекс).икс := случайноеещественное()*400.0;
дельты(индекс).игрек := случайноеещественное()*200.0;
индекс := индекс + 1;
кц
открыть_окно(800, 600, адрес(«Привет, Raylib!»));
@ -45,8 +44,7 @@
начать_рисовать();
очистить_фон(ЦВЕТОНА);
индекс := 0;
пока индекс мн ОБЪЁМ нч
для индекс := 0..ОБЪЁМ-1 нч
если не пауза нч
пер новая_позиция: Вектор2;
новая_позиция.икс := позиции(индекс).икс + дельты(индекс).икс*дельтаремени;
@ -64,7 +62,6 @@
позиции(индекс).игрек как цел,
ШИРИНА, ВЫСОТА, ЦВЕТ_КРАСНЫЙ);
индекс := индекс + 1;
кц
закончить_рисовать();
кц

View File

@ -5,10 +5,7 @@
про отступ(ширина: цел) нч
пер индекс: цел = 0;
пока индекс мн ширина нч
печать(« »);
индекс := индекс + 1;
кц
для индекс := 1..ширина то печать(« »);
кц
про дерево(глубина: цел) нч