Hệ điều hành MS-DOS Dịch vụ ROM-BIOS Chương trình TSR Kỹ xảo lập trình

TRUY XUẤT HỆ ĐIỀU HÀNH MS-DOS

I.1. Môi trường MS-DOS

· Lấy phiên bản MS-DOS

 Function DOSVersion : Word;

Hàm này trả về 2 bytes chứa số hiệu phiên bản của hệ điều hành, byte thấp chứa

chỉ số chính (major version), byte cao chứa chỉ số phụ (minor version).

Ví dụ:

Uses DOS;

Begin

Writeln(’DOS Version : ’,Lo(DOSVersion),’.’,Hi(DOSVersion));

End.

· Cài đặt biến môi trường (environment string)

Trong MS-DOS tồn tại các biến môi trường sau:

COMSPEC = đường dẫn đến trình phân giải lệnh nội trú, thường là C:\COMMAND.COM hay

C:\WINDOWS\SYSTEM\COMMAND.COM

OS = hệ điều hành được sử dụng, ví dụ Windows_NT

PATH = đường dẫn đến các thư mục để HĐH truy tìm các chương trình.

PROMPT = định dạng dấu nhắc DOS, thường là $P$G

. . .

Để truy xuất đến các biến môi trường, unit DOS cung cấp một số hàm sau:

Function EnvCount : Integer;

Hàm này trả về số lượng biến môi trường đã được cài đặt.

Function EnvStr(Index : integer) : string;

Hàm này trả về nội dung của biến môi trường có thứ tự Index.

Ví dụ: Chương trình liệt kê tất cả các biến môi trường của MS-DOS.

pdf74 trang | Chia sẻ: hienduc166 | Lượt xem: 503 | Lượt tải: 0download
Bạn đang xem trước 20 trang tài liệu Hệ điều hành MS-DOS Dịch vụ ROM-BIOS Chương trình TSR Kỹ xảo lập trình, để xem tài liệu hoàn chỉnh bạn click vào nút TẢI VỀ ở trên
hai cách chuyển kiểu này có một số quy 
tắc khác biệt. 
IX.1. Chuyển kiểu đối với trị 
Việc chuyển kiểu đối với trị được thực hiện khi giá trị cần chuyển và kiểu được 
chuyển đều cùng kiểu thứ tự (ordinal type) hoặc cả hai đều mang kiểu con trỏ. Dưới đây là một số 
ví dụ chuyển kiểu theo trị: 
Integer(’A’) Chuyển ký tự A sang số 
Char(48) Chuyển số sang ký tự 
Boolean(0) Chuyển số sang kiểu luận lý 
Longint(@Buffer) Chuyển địa chỉ vùng đệm sang kiểu số longint. 
 jishan_vn@msn.com - 71 - 
Kiểu kết quả sau khi chuyển có thể bị cắt bỏ nếu kiểu được chuyển không thích hợp. 
Ví dụ: 
I:=Byte(539) kết quả I mang trị 27, lý do 539 là một số lớn hơn kích thước của 
một byte (255). Cho nên 539(10) = 1000011011(2) và khi chuyển qua kiểu byte, trình biên dịch chỉ 
giữ lại 8 bits cuối, kết quả thu được 00011011(2) = 27(10). 
IX.2. Chuyển kiểu đối với biến 
Ta có thể chuyển kiểu dữ liệu cho biến sang hầu hết các kiểu dữ liệu khác. Ví dụ: 
 Char(I) 
 Boolean(Count) 
 TSomeDefinedType(MyVariable) 
Chuyển kiểu cho biến còn được thực hiện ở cả hai vế của câu lệnh gán. Ví dụ: 
 var MyChar:Char; 
 ... 
 Shortint(MyChar):=122; 
 ... 
Chuyển kiểu theo cách trên sẽ gán mã ASCII cho biến mang kiểu ký tự MyChar. Kết 
quả MyChar sẽ chứa ký tự ‘z’ (#122). 
Ta cũng có thể chuyển kiểu của một biến sang kiểu thủ tục (procedural type). Ví dụ 
ta có khai báo: 
 type Func = function(X:Integer): Integer; 
 var F:Func; 
 P:Pointer; 
 N:Integer; 
Ta cũng có thể thực hiện chuyển kiểu cho biến thủ tục như trong các phép gán sau: 
 F := Func(P); { Assign procedural value in P to F } 
 Func(P) := F; { Assign procedural value in F to P } 
 @F := P; { Assign pointer value in P to F } 
 P := @F; { Assign pointer value in F to P } 
 N := F(N); { Call function via F } 
 N := Func(P)(N); { Call function via P } 
Biến có thể được chuyển kiểu thông qua dấu chấm (.) phân định phạm vi như sau: 
type TByteRec = record 
 Lo, Hi: Byte; 
 end; 
 TWordRec = record 
 Low, High: Word; 
 end; 
 PByte = ^Byte; 
var B: Byte; 
 W: Word; 
 L: Longint; 
 P: Pointer; 
begin 
 W := $1234; 
 B := TByteRec(W).Lo; 
 TByteRec(W).Hi := 0; 
 L := $01234567; 
 W := TWordRec(L).Low; 
 B := TByteRec(TWordRec(L).Low).Hi; 
 B := PByte(L)^; 
end; 
Ở ví dụ trên, TByteRec được dùng để truy xuất byte thấp và byte cao của biến kiểu 
Word. TWordRec được dùng để truy xuất word thấp và word cao của biến kiểu LongInt (cách này 
còn có tên gọi khác là record hóa vùng nhớ). Ta có thể gọi hàm Hi và Lo của Pascal để thực hiện 
cùng một chức năng trên. Tuy nhiên, với kỹ thuật chuyển kiểu cho biến, ta có thể sử dụng thêm 
chức năng của phép gán, gán trị cho biến sau khi đã thực hiện phép chuyển kiểu. 
 jishan_vn@msn.com - 72 - 
X. CÁC QUY TẮC ƯU TIÊN CỦA TOÁN TỬ 
Trong một biểu thức phức tạp gồm nhiều toán từ, wuy tắc ưu tiên dành cho toán tử 
được thể hiện như sau: 
Toán tử Độ ưu tiên 
@, ^, not Ưu tiên 1 (cao nhất) 
*, /, div, mod, and, shl, shr Ưu tiên 2 
+, -, or, xor Ưu tiên 3 
=, , , =, in Ưu tiên 4 (thấp nhất) 
Toán tử có độ ưu tiên cao sẽ được định giá trước các toán tử có độ ưu tiên thấp. Các 
toán tử có độ ưu tiên bằng nhau sẽ được định giá từ trái sang phải. 
Ví dụ với biểu thức: X+Y*Z 
 Biểu thức này thực hiện phép nhân Y với Z rồi sau đó cộng với X, toán tử * 
được thực hiện trước vì nó có độ ưu tiên cao hơn toán tử +. 
Ví dụ với biểu thức: X-Y+Z 
 Biểu thức này thực hiện phép trừ giữa X và Y trước rồi mới cộng với Z, toán 
tử + và – có cùng độ ưu tiên nên biểu thức được thực hiện từ trái sang phải. 
Ta có thể sử dụng dấu ngoặc đơn để đặt lại độ ưu tiên cho toán tử. Biểu thức trong 
dấu ngoặc đơn sẽ được định giá trước, sau đó kết quả sẽ được sử dụng như một toán hạng cho các 
toán tử kế tiếp. 
Ví dụ: (X+Y)*Z sẽ cộng X với Y, sau đó nhân tổng cộng được cho Z. 
Trong một số trường hợp dấu ngoặc đôi khi rất cần thiết, nếu không ta có thể nhận 
được kết quả định giá không như mong muốn. 
Ví dụ: X=Y or X=Z 
 Dĩ nhiên biểu thức này muốn so sánh với ý nghĩa (X=Y)or(X=Z). Thế nhưng 
nếu không có dấu ngoặc để phân biệt độ ưu tiên của các nhóm toán tử, trình biên dịch theo quy tắc 
ưu tiên của toán tử sẽ biên dịch với ý nghĩa (X=(Y or Z))=Z, kết quả trình biên dịch sẽ báo lỗi trừ 
phi Z mang kiểu Boolean. Nhưng cho dù Z có mang kiểu Boolean đi chăng nữa thì kết quả so sánh 
vẫn không là những gì mà ta mong muốn. 
Cách tốt nhất là ta nên dùng dấu ngoặc để phân định các nhóm ưu tiên cho toán tử, 
nhất là trong trường hợp không nhớ rõ độ ưu tiên của từng toán tử. Cặp dấu ngoặc cũng làm cho 
biểu thức rõ ràng và dễ đọc hơn là hiểu quy tắc ưu tiên mặc định. 
Ví dụ: X+(Y*Z). 
 Đối với trình biên dịch, dấu ngoặc trong trường hợp này là không cần thiết, 
nhưng lập trình viên và người đọc sẽ dễ dàng hiểu tường minh ý nghĩa của biểu thức mà ta muốn 
thể hiện là thực hiện Y nhân với Z rồi mới cộng với X. 
XI. KIỂM SOÁT LỖI NHẬP XUẤT (I/O ERROR) 
Khi nhập dữ liệu từ bàn phím, nếu giá trị nhập vào không đúng với kiểu của biến thì 
chương trình sẽ bị lỗi xuất nhập không đúng kiểu và bẫy lỗi (error trap) sẽ làm ngưng chương trình. 
Hoặc khi truy xuất tập tin, thư mục, nếu có lỗi xảy ra trong quá trình truy xuất, chương trình cũng sẽ 
bị dừng bởi lỗi xuất nhập. Để tránh việc này, cần phải gỡ bỏ bẫy lỗi kiểm soát xuất nhập. 
Để bật/tắt bẫy lỗi xuất nhập, ta dùng chỉ thị dịch $I: 
+ {$I+} : bật bẫy lỗi kiểm tra xuất nhập. 
+ {$I-} : tắt bẫy lỗi kiểm tra xuất nhập. 
Khi tắt bẫy lỗi xuất nhập, chương trình sẽ không bi dừng nếu có lỗi xảy ra. Để biết 
chương trình có bị lỗi hay không, Pascal cung cấp hàm IOResult để kiểm tra: 
 Function IOResult: Integer; 
Khi xuất nhập dữ liệu đúng, hàm IOResult cho giá trị là 0, ngược lại sẽ trả về số hiệu 
của lỗi. 
 jishan_vn@msn.com - 73 - 
Ví dụ: Cú pháp kiểm tra thao tác nhập dữ liệu: 
{$I-} 
Repeat 
 Write( {} ); 
 Readln( {} ); 
Until IOResult=0; 
{$I+} 
Cú pháp trên sẽ kiểm tra kiểu dữ liệu nhập vào, chương trình chỉ được tiếp tục khi 
kiểu dữ liệu phù hợp với biến. 
Ví dụ: Chương trình kiểm tra sự tồn tại của tập tin: 
Function FileExists(Filename:string):boolean; 
var F:file; 
begin 
 {$I-} 
 Assign(F,Filename); 
 Reset(F); 
 If IOResult0 then FileExists:=false 
 else 
 begin 
 Close(F); 
 FileExists:=true; 
 end; 
 {$I+} 
end; 
XII. TRUY XUẤT VÙNG NHỚ MÁY TÍNH 
XII.1. Biến địa chỉ tuyệt đối 
Các biến khai báo trong chương trình bằng từ khoá Var hay các biến động được tạo 
ra bằng các thủ tục New và GetMem đều mang địa chỉ do sự bố trí sắp xếp của máy tính. Nếu ta muốn 
cố định biến chương trình vào một địa chỉ nhất định thì phải sử dụng cú pháp khai báo biến địa chỉ 
tuyệt đối bằng từ khoá absolute: 
Var : absolute :; 
Hoặc khai báo biến trùng địa chỉ với một biến khác có sẵn: 
Var : absolute ; 
Ví dụ 1: Var St:String; 
Len:byte absolute St; 
 Ta có Len sẽ mang cùng địa chỉ với biến St (hay St[0]), nghĩa là Len luôn 
mang giá trị là chiều dài của chuỗi St. Khi đó, mọi thay đổi trên Len sẽ thay đổi chiều dài chuỗi St. 
Ví dụ 2: Nếu ta muốn lấy mode màn hình hiện tại, ngoài cách sử dụng LastMode của 
thư viện CRT, ta có thể sử dụng biến địa chỉ tuyệt đối truy xuất vào vùng nhớ $0000:$0449 chứa 
giá trị của mode màn hình: 
Var Mode:byte absolute $0000:$0449; 
begin 
 case Mode of 
 0: writeln(’Mode 40x25 BW’); 
 1: writeln(’Mode 40x25 Color’); 
 2: writeln(’Mode 80x25 BW’); 
 3: writeln(’Mode 80x25 Color’); 
 7: writeln(’Mode 80x25 Hercules Mono’); 
 end; 
end; 
Lưu ý rằng vùng nhớ $0000:$0449 chỉ mang giá trị của mode màn hình chứ không 
có tác dụng làm thay đổi mode màn hình nên việc thay đổi giá trị của biến Mode sẽ không làm đổi 
mode màn hình. 
 jishan_vn@msn.com - 74 - 
XII.2. Biến truy xuất vùng nhớ 
Ngoài cú pháp trên, Pascal còn cung cấp cho ta những biến bộ nhớ để truy xuất trực 
tiếp vào bất kỳ địa chỉ nào của bộ nhớ. Đó là 3 biến kiểu mảng MEM, MEMW và MEML. 
 + MEM: Mỗi thành phần của biến này có kiểu byte, dùng để truy xuất vùng 
nhớ 1 byte. 
 + MEMW: Mỗi thành phần của biến này có kiểu word, dùng để truy xuất 
vùng nhớ 2 bytes. 
 + MEML: Mỗi thành phần của biến này có kiểu longint, dùng để truy xuất 
vùng nhớ 4 bytes. 
Chỉ số của các biến mảng này được khai báo bằng cú pháp đặc biệt có dạng 
Segment:Offset, là địa chỉ vùng nhớ mà biến truy xuất đến. 
Ví dụ: 
If Mem[$0000:$0449]=7 then Writeln(’Hercules MonoChrome’) 
Else Writeln(’CGA, EGA or VGA’); 
Khi sử dụng các biến này, ta có thể lấy dữ liệu từ vùng nhớ ra để sử dụng và cũng có 
thể ghi trực tiếp dữ liệu vào vùng nhớ bằng lệnh gán hay các cú pháp làm thay đổi giá trị của biến. 
Nhưng cần phải lưu ý khi sử dụng các biến truy xuất bộ nhớ: 
 + Phải biết rõ địa chỉ, độ lớn và công dụng của dữ liệu trong vùng nhớ. 
 + Phải biết rõ dữ liệu trong vùng nhớ này có được phép sửa đổi hay không vì 
nếu không biết rõ, việc thay đổi giá trị trong vùng nhớ có thể gây sụp đổ chương trình lẫn cả hệ 
thống. 
 + Không được truy xuất MEM, MEMW và MEML mà không có chỉ số kèm 
theo. 
XII.3. Biến truy xuất các cổng dữ liệu 
Ngoài việc sử dụng Assembly thì Pascal còn cung cấp các biến để truy xuất các cổng 
dữ liệu, đó là 2 biến kiểu mảng PORT và PORTW. 
 + PORT: Mỗi thành phần của biến này có kiểu byte, dùng để truy xuất các 
giá trị 1 byte. 
 + PORTW: Mỗi thành phần của biến này có kiểu word, dùng để truy xuất các 
giá trị 2 bytes. 
Chỉ số của các biến mảng này đều mang kiểu word. Ta không thể truy xuất Port và 
PortW mà không có chỉ số đi kèm. 
Khi gán một giá trị vào Port(PortW), giá trị đó sẽ được xuất ra cổng tương ứng, 
ngược lại ta có thể nhận giá trị ở cổng bằng cách đọc từ Port(PortW). 
Ví dụ: Port[$60] là cổng bàn phím, Port[$378] là cổng LPT1, Port[$3F8] là cổng 
COM1, Port[$2F8] là cổng COM2... 
Lưu ý rằng Port và PortW chỉ được giới hạn sử dụng trong phép gán và tham chiếu 
giá trị trong các biểu thức, điều đó có nghĩa là không được sử dụng Port và PortW như tham số biến 
trong lời gọi chương trình con. 

File đính kèm:

  • pdfSystem Programming with Pascal.pdf
Bài giảng liên quan