Добрый всем вечер Я хотел бы узнать как мне "внести" через экран значения в переменные Код (Text): y dt 2.0 x dt -2.0 И как их вывести результат на экран? Я так полагаю что нужно сначала просто выделить место под переменные и уж потом их вносить Код (Text): y dt ? x dt ? Помогите Пожалуйста, уже столько электронок пересмотрел, и ничего не понял. Вот Алгоритм Юрова Код (Text): .586p masm model user16 small .stack 100h .data ;сегмент данных flag db 0 p1 dd 0 y dt 2.0 ;основание степини x dt -2.0 ;показатель степени .code main: main proc ;начало процедуры main mov ax, @data mov ds, ax finit fld y fld x ftst fstsw ax sahf jnc m1 ;перход если х >=0 jnx flag ;взведем флаг, если х <0 fabs ; |x| m1: fxch fy12x fst st(1) fabs ;|z| ;сравним !z! с единицей fld1 fcom fstsw ax sahf jp exit ;операнды не сравнимы jnc m2 ;если !Z!<1 то переходим на м2 jz m3 ;если !з!=1 то переходим на м3 ;если "з">1 то приводим к формуле z=z1+z2 ,z1 - целое, z2 - дробное or ecx,ecx ;счетчик вычитаний m12:inc cx fsub st(1), st(0) fcom fstsw ax sahf jp exit ;операнды не сравнимы jz m12 jnc m2 ;если !z! <1, то переходим на m2 jmp m12 ;если !z! >1, то переходим на m12 m3:mov p1, ecx jmp $+7 m2:mov p1, ecx fxch f2xm1 fadd ;компенсируем 1 fild p1 ;показатель степенидля fscale fld1 fscale fxch fincstp fmul ;проверка на отрицательную степень cmp flag, 1 jnz exit fld1 fxch fdiv exit: mov ax, 4c00h int 21h main endp end main Програма под WIN.
УСТАНОВКА КУРСОРА ------------------------------------------------------------ Экран можно представить в виде двумерного пространства с адресуемыми позициями в любую из которых может быть установ лен курсор. Обычный видеомонитор, например, имеет 25 строк (нумеруемых от 0 до 24) и 80 столбцов (нумеруемых от 0 до 79). В следующей таблице приведены некоторые примеры положений курсора на экране: -------------------------------------------------------- Дес. формат Шест.формат -------------- -------------- Положение строка столбец строка столбец -------------------------------------------------------- Верхний левый угол 00 00 00 00 Верхний правый угол 00 79 00 4F Центр экрана 12 39/40 00 27/28 Нижний левый угол 24 00 18 00 Нижний правый угол 24 79 18 4F -------------------------------------------------------- Команда INT 10H включает в себя установку курсора в любую позицию и очистку экрана. Ниже приведен пример установки курсора на 5-ую строку и 12-ый столбец: MOV AH,02 ;Запрос на установку курсора MOV BH,00 ;Экран 0 MOV DH,05 ;Строка 05 MOV DL,12 ;Столбец 12 INT 10H ;Передача управления в BIOS Ассемблер для IBM PC. Глава 8 174 Значение 02 в регистре AH указывает команде INT 10H на выпол нение операции установки курсора. Значение строки и столбца должны быть в регистре DX, а номер экрана (или страницы) в регистре BH (обычно 0). Содержимое других регистров несущест венно. Для установки строки и столбца можно также использо вать одну команду MOV c непосредственным шест. значением: MOV DX,050CH ;Строка 5, столбец 12 ОЧИСТКА ЭКРАНА ------------------------------------------------------------ Запросы и команды остаются на экране пока не будут смеще ны в результате прокручивания ("скролинга") или переписаны на этом же месте другими запросами или командами. Когда программа начинает cвое выполнение, экран может быть очищен. Очищаемая область экрана может начинаться в любой позиции и заканчиваться в любой другой позиции с большим номером. Начальное значение строки и столбца заносится в регистр DX, значение 07 - в регистр BH и 0600H в AX. В следующем примере выполняется очистка всего экрана: MOV AX,0600H ;AH 06 (прокрутка) ;AL 00 (весь экран) MOV BH,07 ;Нормальный атрибут (черно/белый) MOV CX,0000 ;Верхняя левая позиция MOV DX,184FH ;Нижняя правая позиция INT 10H ;Передача управления в BIOS Значение 06 в регистре AH указывает команде INT 10H на выполнение опарации очистки экрана. Эта операция очищает экран пробелами; в следующей главе скролинг (прокрутка) будет пассмотрен подробнее. Если вы по ошибке установили нижнюю правую позицию больше, чем шест. 184F, то очистка перейдет вновь к началу экрана и вторично заполнит некоторые позиции прробелами. Для монохромных экранов это не вызывает каких-либо неприятностей, но для некоторых цветных мониторов могут возникнуть серьезные ошибки. ЭКРАННЫЕ И КЛАВИАТУРНЫЕ ОПЕРАЦИИ: БАЗОВАЯ ВЕРСИЯ DOS ------------------------------------------------------------ Обычно программы должны выдать на экран сообщение о завер шении или об обнаружении ошибки, отобразить запрос для ввода данных или для получения указания пользователя. Рассмотрим сначала методы, применяемые в базовой версии DOS, в последую щих pазделах будут показаны расширенные методы, введенные в DOS версии 2.0. Операции из базовой DOS работают во всех версиях, хотя в руководстве по DOS рекомендуется применять расширенные возможности для новых разработок. В базовой версии DOS команды вывода на экран более сложны, но команды ввода с клавиатуры проще в использовании, благодаря встроен ным проверкам. Ассемблер для IBM PC. Глава 8 175 ВЫВОД НА ЭКРАН: БАЗОВАЯ ВЕРСИЯ DOS ------------------------------------------------------------ Вывод на экран в базовой версии DOS требует определения текстового сообщения в области данных, установки в регистре AH значения 09 (вызов функциии DOS) и указания команды DOS INT 21H. В процессе выполнения операции конец сообщения определяется по oграничителю ($), как это показано ниже: NAMPRMP DB 'Имя покупателя?','$' . . MOV AH,09 ;Запрос вывода на экран LEA DX,NAMPRMP ;Загрузка адреса сообщ. INT 21H ;Вызов DOS Знак ограничителя "$" можно кодировать непосредственно после cимвольной строки (как показано в примере), внутри строки: 'Имя покупателя?$', или в следующем операторе DB '$'. Используя данную операцию, нельзя вывести на экран символ доллара "$". Кроме того, если знак доллара будет отсутство вать в коце строки, то на экран будут выводиться все последующие символы, пока знак "$" не встретиться в памяти. Команда LEA загружает адрес области NAMPRMP в регистр DX для передачи в DOS адреса выводимой информации. Адрес поля NAMPRMP, загружаемый в DX по команде LEA, является oтноси тельным, поэтому для вычисления абсолютного адреса данных DOS складывает значения регистров DS и DX (DSX). ПРОГРАММА: ВЫВОД НА ЭКРАН НАБОРА СИМВОЛОВ КОДА ASCII ------------------------------------------------------------ Большинство из 256 кодов ASCII имеют символьное представ ление, и могут быть выведены на экран. Шест. коды 00 и FF не имеют символов и выводятся на экран в виде пробелов, хотя символ пробела имеет в ASCII шест. код 20. На рис. 8.1 показана COM-программа, которая выводит на экран полный набор символов кода ASCII. Программа вызывает три процедуры; B10CLR, C10SET и D10DISP. Процедура B10CLR очищает экран, а процедура C10SET устанавливает курсор в положение 00,00. Процедура D10DISP выводит содержимое поля CTR, которое в начале инициализировано значением 00 и затем yвеличивается на 1 при каждом выводе на экран, пока не достигнет шест. значения FF. ------------------------------------------------------------ ------------------------------------------------------------ Рис. 8.1. Вывод на экран набора символов кода ASCII Так как символ доллара не выводится на экран и кроме того коды от шест. 08 до шест. 0D являются специальными управляющими cимволами, то это приводит к перемещению Ассемблер для IBM PC. Глава 8 176 курсора и другим управляющим воздействиям. Задание: введите программу (рис.8.1), выполните ассемблирование, компановку и преобразование в COM-файл. Для запуска программы введите ее имя, например, В:ASCII.COM. Первая выведенная строка начинается с пробельного символа (шест.00), двух "улыбающихся лиц" (шест. 01 и 02) и трех карточных символов (шест.03, 04 и 05). Код 07 выдает звуко вой сигнал. Код 06 должен отобразиться карточным символом "пики", но управляющие символы от шест.08 до 0D сотрут его. Код 0D является "возвратом каретки" и приводит к переходу на новую (следующую)строку. Код шест.0E - представляется в виде музыкальной ноты. Символы после шест. 7F являются графически ми. Можно изменить программу для обхода управляющих символов. Ниже приведен пример фрагмента программы, позволяющий обойти все символы между шест. 08 и 0D. Вы можете поэкспериментировать, oбходя только, скажем, шест. 08 (возврат на символ) и 0D (возврат каретки): CMP CTR,08H ;Меньше чем 08? JB D30 ; да - принять CMP CTR,0DH ; Меньше/равно 0D? JBE D40 ; да - обойти D30: MOV AH,40H ;Вывод символов < 08 ... ; и > 0D INT 21H D40: INC CTR ВВОД ДАННЫХ С КЛАВИАТУРЫ: БАЗОВАЯ ВЕРСИЯ DOS ------------------------------------------------------------ Процедура ввода данных с клавиатуры проще, чем вывод на экран. Для ввода, использующего базовую DOS, область ввода требует наличия cписка параметров, содержащего поля, которые необходимы при выполнении команды INT. Во-первых, должна быть определена максимальная длина вводимого текста. Это необходимо для предупреждения пользователя звуковым сигна лом, если набран слишком длинный текст; символы, превышающие максимальную длину не принимаются. Во-вторых, в списке параметров должно быть определенное поле, куда команда возвращает действительную длину введенного текста в байтах. Ниже приведен пример, в котором определен список парамет ров для области ввода. LABEL представляет собой директиву с атрибутом BYTE. Первый байт содержит максимальную длину вводимых данных. Так как это однобайтовое поле, то возможное максимальное значение его - шест. FF или 255. Второй байт необходим DOS для занесения в него действительного числа введенных символов. Третьим байтом начинается поле, которое будет содержать введенные символы. NAMEPAR LABEL BYTE ;Список параметров: Ассемблер для IBM PC. Глава 8 177 MAXLEN DB 20 ; Максимальная длина ACTLEN DB ? ; Реальная длина NAMEFLD DB 20 DUP (' ') ; Введенные символы Так как в списке параметров директива LABEL не занимает места, то NAMEPAR и MAXLEN указывают на один и тот же aдрес памяти. В трансляторе MASM для определения списка параметров в виде структуры может использоваться также директива STRUC. Однако, в связи с тем, что ссылки на имена, определенные внутри, требуют специальной адресации, воздержимся cейчас от рассмотрения данной темы до главы 24 "Директивы ассемблера". Для запроса на ввод необходимо поместить в регистр AH номер функции - 10 (шест. 0AH), загрузить адрес списка пара метров (NAMEPAR в нашем примере) в регистр DX и выполнить INT 21H: MOV AH,0AH ;Запрос функции ввода LEA DX,NAMEPAR ;Загрузить адреса списка параметров INT 21H ;Вызвать DOS Команда INT ожидает пока пользователь не введет с клавиа туры текст, проверяя при этом, чтобы число введенных cимво лов не превышало максимального значения, указанного в списке параметров (20 в нашем примере). Для указания конца ввода пользователь нажимает клавишу Return. Код этой клавиши (шест. 0D) также заносится в поле ввода (NAMEFLD в нашем примере). Если, например, пользователь ввел имя BROWN (Return), то cписок параметров будет содержать информацию: дес.: │20│ 5│ В│ R│ O│ W│ N│ #│ │ │ │ │ ... шест.: │14│05│42│52│4F│57│4E│0D│20│20│20│20│ ... Во второй байт списка параметров (ACTLEN в нашем примере) команда заносит длину введенного имени - 05. Код Return находится по адресу NAMEFLD +5. Символ # использован здесь для индикации конца данных, так как шест. 0D не имеет отображаемого символа. Поскольку максимальная длина в 20 символов включает шест.0D, то действительная длина вводимого текста может быть только 19 символов. Текст был скопирован и тупо вставлен, поэтому не гарантирую что без ошибок. Разберешься... А вот для того что-бы строку в число перевести, придется попотеть... Посоветую перегнать строку до запятой в десятеричное число и после запятой в него же... Как перегнать строковое представление числа в десятеричное число вы в инете найдете... Придется только отследить где же запятая... Потом при помощи одной интересной команды сопроцессора fbld помещаете в стек сопроцессора оба этих числа (до и после запятой)... то число что после запятой делится на 10 или на 100 или на 1000 и т.д. в зависимости от того сколько в нем знаков(можно делимое получать сразу при перегонке строки после запятой в число вставив в цикл определенные строки и потом поместив его так же как и другие целочисленные переменные в стек сопроцессора) А потом складываются оба числа(то что до запятой и то что после деленное на 10*x). Ну в масме есть еще и макрос FpuAtoFL для перегонки строкового представления числа, но я им не пользовался и говорить не буду. Надеюсь помог. Удачи!
перевод числа в строку (правда не работает с "нечислом" и бесконечностью) Код (Text): .686 .model flat include windows.inc includelib user32.lib extern _imp__MessageBoxA@16:dword .code start: fld x xchg ebx,eax mov edi,offset String fldz fcomip st,st(1) ;сравниваю число с нулем jnz @f mov byte ptr [edi],'0' jmp b0 @@: jb @f mov al,'-' ;если отрицательное вывожу знак минус stosb fchs ;и получаю модуль числа @@: fstcw control ;устанавливаю режим "округление к нулю" or control,0C00h fldcw control fld st ;дублирую содержимое st(0) в st(1) frndint ;округляю до целого содержимое st(0) fsub st(1),st ;в st(1) остается дробная часть fldz fcomip st,st(1) ;сравниваю число с нулем jnz @f mov al,'0' stosb jmp b3 @@: call bcd2str fldz b3: fcomip st,st(1) jz b0 mov al,'.' stosb inc ebx fmul y ;умножаю дробную часть на 1.0e17 call bcd2str b0: push 0 push 0 push offset String push 0 call _imp__MessageBoxA@16 retn bcd2str proc fbstp temp mov ecx,9 ;в десятом байте информация о знаке числа test ebx,ebx jnz b1 @@: cmp byte ptr [ecx-1+temp],0 jnz b1 loop @b ;пропускаем незначащие (нулевые) разряды слева b1: mov al,byte ptr [ecx-1+temp];загружаем первую значащую пару разрядов cmp al,9 ;если в старшей тетраде 0 - пропустить старшую тетраду ja @f add al,30h ;младшую тетраду переводим в ASCII stosb dec ecx jz b2 @@: movzx ax,byte ptr [ecx-1+temp];распаковываем остальные разряды числа ror ax,4 ;выделяем старшую и младшую тетрады shr ah,4 add ax,'00' ;переводим в ASCII-код stosw loop @b b2: retn bcd2str endp x dt -0.123456789;.987654321 control dw ? ;переменная под содержимое регистра CWR temp dt ? ;переменная под BCD y dq 1.0e17 ;множитель String db 30 dup (0) end start и для преобразования строки в число (код alexcoder, взято здесь) Код (Text): value_s2f dw 0 ;переменая для функции преобразования строки в число ;+==============================================+ ;| ПЕРЕВОД ИЗ STRING В FLOAT | ;+==============================================+ ;| SI - указатель на строку | ;+----------------------------------------------+ ;| ST(0) - преобрезованное число | ;| cf=1 если в строке ошибка | ;+==============================================+ STRTOFLOAT PROC jmp @STARTCONVERSATION_S2F ; стартуем в рабочую область @STARTCONVERSATION_S2F: pusha mov value_s2f, 0 ; обнуляем локальную переменную xor bx, bx ; очищаем указатель позиции cmp byte ptr [si], '-' ; проверяем на отрицательность jne @POSITIVE_S2F ; число не отрицательное inc bx ; число отрицательное, увеличиваем позицию @POSITIVE_S2F: mov value_s2f, 10 ; загружаем число в переменную fild value_s2f ; загружаем в стэк число 10 fldz ; загружаем в стэк число 0 @REPEAT_BEFORE: mov al, byte ptr si[bx] ; получаем символ cmp al, byte ptr '.' ; проверяем точка ли это je @ISPOINTBEFORE ; точка - идем дальше cmp al, byte ptr 13 ; проверяем конец ли строкиа je @ENDASINT ; уже конец и хватит искать дроби cmp al, '0' ; если текущий символ не цифра jc @END_S2F_ERR ; то выход с ошибкой cmp al,'9' ja @END_S2F_ERR sub al, 30h ; делаем из CHAR - INT mov byte ptr value_s2f, al ; копируем в память fiadd value_s2f ; складываем из тем, что есть в стэке fmul st(0), st(1) ; умножаем на 10 inc bx ; увеличиваем указатель jmp @REPEAT_BEFORE ; повторяем @ISPOINTBEFORE: inc bx ; увеличиваем указатель fdiv st(0), st(1) ; делим число на 10, т.к. оно уже больше fxch st(1) ; меняем местами регистры mov al, byte ptr 13 ; ищем символ конца строки @FINDNEXT: cmp si[bx], al ; ищем конец строки je @FINDEND ; нешел конец строки inc bx ; получаем следующий адрес символа jmp @FINDNEXT ; не нашел, еще ищем @FINDEND: dec bx ; переходим на предыдущий символ fldz ; загружаем в стэк число 0 @REPEAT_AFTER: mov ax, word ptr si[bx] ; получаем символ cmp al, byte ptr '.' ; проверяем точка ли это je @WASPOINTAFTER ; точка - идем дальше cmp al, '0' ; если текущий символ не цифра jc @END_S2F_ERR ; то выход с ошибкой cmp al,'9' ja @END_S2F_ERR sub al, 30h ; делаем из CHAR - INT mov byte ptr value_s2f, al ; копируем в память fiadd value_s2f ; складываем из тем, что есть в стэке fdiv st(0), st(1) ; делим на 10 dec bx ; декрементируем указатель loop @REPEAT_AFTER ; повторяем @WASPOINTAFTER: fxch st(1) ; меняем число 10 и остаток местами fxch st(2) ; меняем целое и 10 местами faddp st(1) ; складываем число до и после запятой fxch st(1) ; меняем местами результат и 10 fistp value_s2f ; извлекаем из стэка 10 jmp @FULLEND ; полный конец процедуры @ENDASINT: fdiv st(0), st(1) ; делим число на 10, т.к. оно уже больше fxch st(1) ; меняем местами регистры fistp value_s2f ; извлекаем из стэка 10 @FULLEND: cmp byte ptr [si], '-' ; проверяем на отрицательность jne @END_S2F ; число не отрицательное fchs ; число отрицательное, меняем знак @END_S2F: popa ; выгружаем все регистры clc ;ошибки нет ret ; возврат из процедуры @END_S2F_ERR: popa ; выгружаем все регистры fistp value_s2f ;очищаем st0 stc ;ошибка ret ; возврат из процедуры STRTOFLOAT ENDP
Код (Text): .586p ;masm .model small .stack 100h .data ;сегмент данных flag db 0 p1 dd 0 y dt 2.0 ;основание степини x dt -2.0 ;показатель степени .code main: main proc ;начало процедуры main mov ax, @data mov ds, ax finit fld y fld x ftst fstsw ax sahf jnc m1 ;перход если х >=0 inc flag ;взведем флаг, если х <0 fabs ; |x| m1: fxch fyl2x fst st(1) fabs ;|z| ;сравним !z! с единицей fld1 fcom fstsw ax sahf jp exit ;операнды не сравнимы jnc m2 ;если !Z!<1 то переходим на м2 jz m3 ;если !з!=1 то переходим на м3 ;если "з">1 то приводим к формуле z=z1+z2 ,z1 - целое, z2 - дробное or ecx,ecx ;счетчик вычитаний m12:inc cx fsub st(1), st(0) fcom fstsw ax sahf jp exit ;операнды не сравнимы jz m12 jnc m2 ;если !z! <1, то переходим на m2 jmp m12 ;если !z! >1, то переходим на m12 m3:mov p1, ecx jmp $+7 m2:mov p1, ecx fxch f2xm1 fadd ;компенсируем 1 fild p1 ;показатель степенидля fscale fld1 fscale fxch fincstp fmul ;проверка на отрицательную степень cmp flag, 1 jnz exit fld1 fxch fdiv exit: mov ax, 4c00h int 21h main endp end main Вылетает ошибка Assembling: 1.asm 1.asm(13) : error A2005: symbol redefinition : main 1.asm(70) : fatal error A1010: unmatched block nesting : main Всё же верно! Что не так?
Действительно main не нужно. Ошибок больше столо - Assembling: 1.asm 1.asm(12) : error A2006: undefined symbol : DGROUP 1.asm(15) : error A2074: cannot access label through segment registers 1.asm(16) : error A2074: cannot access label through segment registers 1.asm(21) : error A2074: cannot access label through segment registers 1.asm(46) : error A2074: cannot access label through segment registers 1.asm(48) : error A2074: cannot access label through segment registers 1.asm(52) : error A2074: cannot access label through segment registers 1.asm(59) : error A2074: cannot access label through segment registers 1.asm(69) : warning A4023: with /coff switch, leading underscore required for start address : main Ошибка в 12 строке - это mov ax, @data почему? опять глобальная ошибка?
model small под винду не канает, там только флэт. с другой стороны под винду запрещены прерывания, а у вас они есть. непонятно у вас программа под что.