Chính xác thì ngôn ngữ lập trình là gì? Điều gì cho phép chúng ta viết bằng ngôn ngữ như vậy?


26

Được rồi tôi mới lập trình và tôi thừa nhận đây là một câu hỏi khá trừu tượng.

Ngôn ngữ tự nhiên chúng ta nói hàng ngày tồn tại bởi vì mọi người có thể hiểu nhau. Làm thế nào máy tính có thể hiểu mã của tôi được viết bằng một ngôn ngữ nhất định?

Hãy nói rằng ông A tạo ra một ngôn ngữ mới. Làm thế nào được chấp nhận bởi máy móc? Người tạo phải giao tiếp với máy bằng ngôn ngữ máy để tạo ngôn ngữ mới? Điều gì đảm bảo rằng chúng ta có thể viết bằng ngôn ngữ trong khi được máy hiểu đúng cách?


1
Điều gì cho phép chúng ta viết bằng một ngôn ngữ như vậy? - "Não bộ: chất làm đầy đầu kỳ diệu mới!" - Spike Milligan.
Stephen C

6
Một chút rộng, nhưng một câu hỏi tốt dù sao. Quá nhiều người chỉ đơn giản sử dụng ngôn ngữ mà không bao giờ tự hỏi làm thế nào họ làm việc. Thật tốt khi bạn tò mò.
riwalk

4
Đây là một câu hỏi tham khảo chung , được Wikipedia trả lời dễ dàng và tầm thường .
Aaronaught

Câu trả lời:


39

Bạn có thể tổng hợp khá nhiều toàn bộ câu trả lời cho bộ câu hỏi của bạn với từ "trình biên dịch" . Trình biên dịch là một chương trình đặc biệt có chức năng lấy mã nguồn làm đầu vào, áp dụng các quy tắc ngôn ngữ được xác định bởi nhà thiết kế ngôn ngữ để tìm ra ý nghĩa của mã và tạo ra mã có cùng ý nghĩa với ngôn ngữ khác là đầu ra. Đây thường là mã máy hoặc một số dạng mã byte ("mã máy" cho máy ảo), mặc dù các trình biên dịch chuyên biệt dịch mã sang các ngôn ngữ cấp cao khác vẫn tồn tại. Tuy nhiên, chúng vượt quá phạm vi của câu hỏi này.

Không phải tất cả các ngôn ngữ đều có trình biên dịch. Một số trong số họ có trình thông dịch thay thế, thực hiện tất cả những điều tương tự trình biên dịch thực hiện, ngoại trừ việc thay vì tạo mã máy sau khi xác định chương trình có nghĩa là gì, nó chỉ đơn giản thực thi chương trình ngay lập tức. Nhưng các nguyên tắc cơ bản của phân tích cú pháp (đọc) mã và xác định ý nghĩa của nó là như nhau.

Trả lời sâu hơn bất kỳ điều gì sẽ đi vào lý thuyết trình biên dịch, đây là một chủ đề rất rộng. Nếu bạn quan tâm đến chủ đề này, bạn nên bắt đầu bằng cách đọc bài viết Wikipedia cho "trình biên dịch" và kiểm tra các liên kết từ nó, và nếu bạn có câu hỏi cụ thể, vui lòng hỏi họ ở đây.


11
+1 - Tôi cũng sẽ nói thêm rằng khi bạn viết một ngôn ngữ mới, bạn phải viết trình biên dịch hoặc trình thông dịch bằng một số ngôn ngữ khác. Các phiên bản sau của trình biên dịch hoặc trình thông dịch có thể được viết bằng các phiên bản trước của ngôn ngữ và được biên dịch với trình biên dịch cũ hơn. Trình biên dịch đầu tiên được viết bằng mã máy. Trình biên dịch C đầu tiên được viết bằng cách lắp ráp (rất có thể), v.v.
Scott Whitlock

1
Tôi sẽ thay đổi định nghĩa của trình biên dịch. Họ không phát ra mã máy. Đặc biệt là ngày nay với rất nhiều trình biên dịch phát ra "mã trung gian", chẳng hạn như MSIL. Thậm chí có trình biên dịch phát ra JavaScript!
Neil N

3
Tôi sẽ do dự khi nói rằng trình biên dịch tạo mã máy theo định nghĩa, ngay cả khi giải thích cho người mới bắt đầu. Điều đó giống như nói các hàm trả về số thực, một sự đơn giản hóa vô nghĩa. Tất cả các cấu trúc trình biên dịch giữ khi tạo mã không phải cho máy tính thực sự được xây dựng từ silicon mà chỉ được định nghĩa một cách trừu tượng (có thể là VM hoặc ngôn ngữ cấp cao; có lý do cho biết tiêu chuẩn C định nghĩa một máy trừu tượng , và ở đó là một trình biên dịch từ LLVM IR cấp độ thấp đến JavaScript của friggin). Người mới bắt đầu cần có được điều đó, càng sớm càng tốt.

2
Đơn giản hóa mà hầu hết các sách biên dịch sử dụng là trình biên dịch áp dụng các quy tắc ngôn ngữ để chuyển đổi từ ngôn ngữ nguồn sang ngôn ngữ đích làm đầu ra. (Chẳng hạn, việc biên dịch sang C chẳng hạn, đặc biệt là đối với khóa học giới thiệu).
JasonTrue

4
@delnan, thậm chí nhiều hơn - mỗi ngôn ngữ là một mã máy , cho máy trừu tượng của riêng nó. Cho dù ngôn ngữ có trình độ cao đến đâu.
SK-logic

11

Như bạn đã chỉ ra, con người giao tiếp qua một ngôn ngữ "tự nhiên" như tiếng Anh, tiếng Pháp, tiếng Đức, với nhau. Chúng được gọi là tự nhiên bởi vì chúng ta tự nhiên có được chúng chứ không phải cố ý phát minh ra chúng (Esperanto là một ngoại lệ).

Một ngôn ngữ chính thức được phát minh cho mục đích này hay mục đích khác. Ví dụ, một ngôn ngữ lập trình như C là ngôn ngữ chính thức được phát minh cho mục đích lập trình máy tính.

Tất cả các ngôn ngữ, có thể được mô tả bằng cách sử dụng một ngữ pháp. Một hệ thống phân cấp ngữ pháp được mô tả bởi Noam Chomsky vào năm 1956. Nó bao gồm các cấp độ sau:

Loại-0 ngữ pháp (ngữ pháp không hạn chế). Chúng là chung nhất và tương đương với Máy Turing. Như vậy, vấn đề quyết định xem một chuỗi đã cho có phải là một phần của ngữ pháp không hạn chế hay không là không thể giải quyết được.

Loại ngữ pháp 1 (ngữ pháp nhạy cảm ngữ cảnh). Hầu như tất cả các ngôn ngữ tự nhiên như tiếng Anh đều nhạy cảm với ngữ cảnh. Một ví dụ về độ nhạy ngữ cảnh trong tiếng Anh là hai cụm từ: "Thời gian trôi nhanh như một mũi tên". và "Trái cây bay như một quả chuối." Nói chung, rất khó để máy tính có thể hiểu các ngôn ngữ nhạy cảm theo ngữ cảnh.

Loại 2 ngữ pháp (không ngữ cảnh). Ngôn ngữ không ngữ cảnh là cơ sở lý thuyết cho cú pháp của hầu hết các ngôn ngữ lập trình.

Loại 3 ngữ pháp (ngữ pháp thông thường). Họ ngôn ngữ thông thường có thể thu được bằng cách diễn đạt thông thường. Các ngôn ngữ thông thường thường được sử dụng để xác định các mẫu tìm kiếm và cấu trúc từ vựng của các ngôn ngữ lập trình.

Các loại ngữ pháp loại 2 (không ngữ cảnh) và loại 3 (thông thường) thường được sử dụng bởi các máy tính vì trình phân tích cú pháp cho chúng có thể được thực hiện một cách hiệu quả.

BNF (Backus Normal Form hoặc BackusTHER Naur Form) là một kỹ thuật ký hiệu cho các ngữ pháp không ngữ cảnh, thường được sử dụng để mô tả cú pháp của các ngôn ngữ được sử dụng trong điện toán.

Ví dụ: một định danh có thể được mô tả là:

<identifier> ::= <letter> { <letter> | <digit> }

có nghĩa là nó phải bắt đầu bằng một chữ cái và có thể chứa các chữ cái hoặc chữ số bổ sung.

Trước đó, một chữ cái được định nghĩa là 'a' | 'b' | 'c', v.v. và chữ số được định nghĩa là '0' đến '9' bằng cách sử dụng cùng loại ký hiệu.

Câu lệnh AC "for" có thể được định nghĩa là:

 <for_statement> ::=
    'for' '(' <expression> ';' <expression> ';' <expression> ')' <statement> 

Sau đó, các máy phân tích và phân tích cú pháp (giai đoạn đầu tiên của trình biên dịch hoặc trình thông dịch) được xây dựng để chấp nhận ngữ pháp cụ thể được mô tả bởi BNF cho một ngôn ngữ cụ thể. Các trình phân tích từ điển hình thường được sử dụng để phân tách các mã thông báo khác nhau của ngôn ngữ (chẳng hạn như từ khóa, mã định danh hoặc số) và trình phân tích cú pháp được sử dụng để tìm ra cách các mã thông báo hoạt động cùng nhau, chẳng hạn như cách tạo câu lệnh "for" .


+1 bài viết tuyệt vời. Nhưng tôi không ngạc nhiên khi điều này không được chấp nhận là câu trả lời. Đây là những gì tôi nghĩ OP đang hỏi, nhưng dựa trên câu trả lời họ đã chọn, có vẻ như họ muốn thứ gì đó cao hơn nhiều.
Matthew Rodatus

5

Đầu tiên, hãy định nghĩa "ngôn ngữ" theo nghĩa của nó. Ngôn ngữ trước tiên cần có một từ vựng (một danh sách các từ xác định các khái niệm là đối tượng của giao tiếp), sau đó là một cú pháp (một "mồi" hoặc bộ quy tắc xác định cấu trúc của giao tiếp).

Ở cấp độ cơ bản nhất này, C # không khác gì tiếng Anh. Điều khiến C # trở thành "ngôn ngữ lập trình" là mục đích của nó, và do đó thiết kế của nó; nó được thiết kế để được tiêu hóa thành các lệnh cấp thấp riêng lẻ. Như vậy, từ vựng được xác định trước bị hạn chế, cú pháp được thi hành rất cứng nhắc và toàn bộ ngôn ngữ được thiết kế để được sử dụng theo cách được xác định trước rất nổi tiếng bởi "đối tượng" của nó (máy tính; chính xác hơn là trình biên dịch, sẽ tiêu hóa mã nguồn thành một "ngôn ngữ trung gian" của các lệnh đơn giản sau đó có thể được dịch sang mã máy bằng "thời gian chạy"). Bạn không viết văn xuôi hoặc thơ bằng C #; bạn bảo máy tính thực hiện một công việc theo cách rõ ràng nhất có thể.

Đối với máy tính, vâng, một công cụ, thường được gọi là trình biên dịch, là cần thiết để lấy những gì bạn viết trong mã và chuyển đổi nó thành các hướng dẫn mà máy tính có thể sử dụng. Khoa học máy tính, giống như hầu hết công nghệ, là một quá trình "lặp đi lặp lại" vốn có. Khi máy tính được phát minh lần đầu tiên, chúng được lập trình bằng cách nhập thủ công các hướng dẫn nhị phân. Các hướng dẫn đó đã được chuẩn hóa cho mỗi bộ xử lý thành "mã máy" thập lục phân; sự khác biệt chỉ là cách các chữ số nhị phân được nhóm lại để hiển thị cho con người. Sau đó, trong mã trình biên dịch mã, danh sách các lệnh và một số định danh cơ bản như tên đăng ký đã được thay thế cho mã thập lục phân của chúng khi viết chương trình; ASM vẫn có thể được chuyển đổi 1: 1 thành mã máy gốc. Bước nhảy vọt lượng tử là lập trình "bắt buộc" thế hệ thứ 3, về cơ bản cần nhiều khái niệm trừu tượng, dễ hiểu hơn về con người như các biến và vòng lặp logic và tiêu hóa chúng thành các hướng dẫn riêng, sử dụng các mẫu dựa trên từ khóa và cú pháp. Các ngôn ngữ ban đầu như COBOL, FORTRAN, Pascal và C vẫn có thể được "dịch" bởi một người sang một ngôn ngữ máy cụ thể (thường là 8086 ASM). Sau đó là cuộc cách mạng của lập trình hướng đối tượng, về cơ bản là các quy tắc cú pháp bổ sung xác định mã là được gói gọn trong các "đối tượng" có sự kết hợp giữa trạng thái và logic. bởi một người thành một ngôn ngữ máy cụ thể (thường là 8086 ASM). Sau đó là cuộc cách mạng của lập trình hướng đối tượng, về cơ bản là các quy tắc cú pháp bổ sung xác định mã là được gói gọn trong các "đối tượng" có sự kết hợp giữa trạng thái và logic. bởi một người thành một ngôn ngữ máy cụ thể (thường là 8086 ASM). Sau đó là cuộc cách mạng của lập trình hướng đối tượng, về cơ bản là các quy tắc cú pháp bổ sung xác định mã là được gói gọn trong các "đối tượng" có sự kết hợp giữa trạng thái và logic.

Ngày nay, chúng ta đã đi sâu vào "thế hệ thứ 4" của các ngôn ngữ, đó là các ngôn ngữ được viết để xác định giao tiếp với các chương trình khác thay vì trực tiếp với máy. Được định nghĩa rộng rãi, điều này bao gồm các ngôn ngữ "đánh dấu" như XML / HTML, ngôn ngữ "scripting" như JavaScript và SQL và hầu hết các ngôn ngữ "hộp cát" như Java và .NET Framework (sẽ biên dịch thành IL sau đó được giải thích thêm bởi một thời gian chạy trừu tượng đi máy và chi tiết cụ thể nền tảng). Bạn cũng có thể nói nó bao gồm lĩnh vực ngôn ngữ lập trình chức năng, vốn phụ thuộc vào thời gian chạy để cung cấp sự trừu tượng hóa không chỉ các chi tiết cụ thể của máy, mà cả các chi tiết cụ thể về hoạt động. Các ngôn ngữ thế hệ thứ 4 này ít nhiều không khả thi để con người dịch sang các hướng dẫn máy gốc, và vấn đề là nó sẽ không phải là một nỗ lực đáng giá; sức mạnh của các ngôn ngữ này là quá trình phân lớp trong đó chúng được sử dụng để cuối cùng cho máy tính biết phải làm gì ở mức độ thấp.


Cảm ơn. Tôi có một cái nhìn thoáng qua về lịch sử phát triển ngôn ngữ lập trình.
Erica Xu

2
@KeithS: Bạn có thể muốn định dạng lại đoạn cuối để làm cho nó dễ đọc hơn một chút.
Ivan Vučica

4

Đó là một câu hỏi hay. Một câu trả lời thích hợp tạo thành một nửa tốt của cái gọi là "Khoa học máy tính".

Đối với khởi động, tôi khuyên bạn nên lướt qua denotationalhoạt động ngữ nghĩa, và sau đó đọc cuốn sách này . Nó sẽ cung cấp cho bạn một sự hiểu biết ít nhiều vững chắc về ngôn ngữ lập trình là gì và làm thế nào nó có thể được định nghĩa chính thức.

Nếu ở trên là một chút quá hàn lâm, bạn có thể bắt đầu với Petzold, "Code" , và sau đó quay trở lại ngữ nghĩa.


1
Bạn thực sự mong đợi một 18 yo noob để đọc một số lý thuyết nặng nề chỉ để trả lời câu hỏi này?
Công việc

2
@Job, theo câu hỏi trước đây của anh ấy, anh ấy đang nhận được liều Scheme (và, có lẽ là SICP) trong trường đại học. Nên ổn với một chút ngữ nghĩa rồi. Dù sao, không có câu trả lời thích hợp cho câu hỏi này mà không có lý thuyết nặng nề.
SK-logic

+1 để đề cập đến "Mã". Cuốn sách đó nên được yêu cầu đọc cho mọi sinh viên CS cấp nhập cảnh.
Daniel Pryden

4

Nếu bạn viết chương trình bằng ngôn ngữ lập trình, một chương trình khác sẽ chuyển đổi các ký hiệu trong chương trình của bạn thành các ký hiệu mà máy tính hiểu được. Đôi khi điều này mất vài bước. Ví dụ trong C:

  1. Người dùng viết chương trình bằng ngôn ngữ cấp cao (C) không được hiểu bởi CPU, nhưng được lập trình viên hiểu trực tiếp (chúng tôi hy vọng!).

  2. Trình biên dịch chuyển đổi C thành ngôn ngữ Assmebly, không được CPU hiểu trực tiếp nhưng rất dễ chuyển đổi thành một thứ khác.

  3. Bộ lắp ráp chuyển đổi hội thành chuỗi mã nhị phân được CPU hiểu trực tiếp. Một số trình biên dịch bỏ qua bước trên (bước 2) và tạo tệp nhị phân được biên dịch trực tiếp từ mã nguồn.

Để đảm bảo rằng máy tính hiểu chương trình của bạn, trình biên dịch hoặc trình thông dịch sẽ cung cấp cho bạn một lỗi và thường dừng lại nếu nó gặp phải lỗi không thể biên dịch được, chẳng hạn như lỗi cú pháp. Nếu chương trình của bạn không thể được biên dịch, nó không bao giờ có thể đến giai đoạn mà chương trình của bạn sẽ cố chạy nó và thất bại vì nó không "hiểu" nó.

Để tạo một ngôn ngữ mới, trước tiên bạn thiết kế ngôn ngữ cấp cao của mình và sau đó bạn phải tìm cách ánh xạ các ký hiệu của ngôn ngữ mới của mình sang các lệnh ngôn ngữ lắp ráp mà CPU của bạn hiểu được.


2
Không thực sự; trình biên dịch hiện đại không làm bước 2 và chỉ tạo mã nhị phân trực tiếp. Nhưng lắp ráp và mã nhị phân gần như tương đương; bạn có thể tháo rời (chuyển đổi mã nhị phân trở lại lắp ráp) với độ trung thực rất cao.
MSalters
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.