Alright I'm new to programming and I admit this is a fairly abstract question.

The natural language we speak every day exist because people can understand each other. How can computers understand my code written in a certain language?

Let's say Mr. A creates a new language. How is that accepted by machines? Must the creator communicate with the machine using machine language to create a new language? What guarantees that we can written in a language while getting understood by the machine properly?

  • 1
    What enables us to write in such a language? - "Brains: the new wonder head filler!" - Spike Milligan. – Stephen C Oct 24 '11 at 22:14
  • 6
    A bit broad, but a good question nonetheless. Too many people simply use languages without ever wondering how they work. Good that you are curious. – riwalk Oct 24 '11 at 22:17
  • 4
    This is a general reference question, easily and trivially answered by Wikipedia. – Aaronaught Oct 24 '11 at 23:31

You can sum up pretty much the entire answer to your set of questions with the word "compiler". A compiler is a special program whose function is to take source code as input, apply language rules determined by the language designer in order to figure out what the code means, and produce code with the same meaning in another language as output. This is generally machine code or some form of bytecode (the "machine code" for virtual machines), although specialized compilers that translate code into other high-level languages do exist. They're beyond the scope of this question, though.

Not all languages have a compiler. Some of them have an interpreter instead, which does all the same things a compiler does, except that instead of producing machine code after determining what the program means, it simply executes the program immediately. But the basic principles of parsing (reading) the code and determining what it means are the same.

Answering any more in-depth than this would get into compiler theory, which is a very broad subject. If you're interested in the topic, you should start by reading the Wikipedia article for "compiler" and checking the links from it, and if you have specific questions, feel free to ask them on here.

  • 11
    +1 - I would also add that when you're writing a new language, you have to write the compiler or interpreter in some other language. Later versions of the compiler or interpreter can then be written in earlier versions of the language and compiled with the older compiler. The very first assembler was written in machine code. The first C compiler was written in assembly (most likely) etc. – Scott Whitlock Oct 24 '11 at 20:48
  • 1
    I would change the definition of compiler. They don't all emit machine code. Especially nowadays with so many compilers emitting "intermediate code", such as MSIL. There are even compilers that emit JavaScript! – Neil N Oct 24 '11 at 21:16
  • 3
    I'd be hesitant to state that compilers produces machine code by definition, even when explaining to a beginner. That's like saying functions return real numbers, a pointless oversimplification. All of compiler construction holds when producing code that isn't for a computer actually built from silicon but only defined abstractly (be it a VM or a high-level language; there's a reason it's said the C standard defines an abstract machine, and there is a compiler from the very low-level LLVM IR to friggin' JavaScript). Beginners need to get that, the sooner the better. – user7043 Oct 24 '11 at 21:42
  • 2
    The simplification that most compiler books use is that a compiler applies language rules to convert from a source language to a target language as output. (It's not uncommon to compile to C, for example, especially for an introductory course). – JasonTrue Oct 24 '11 at 21:51
  • 4
    @delnan, even more - every language is a machine code, for its own abstract machine. No matter how high level the language is. – SK-logic Oct 24 '11 at 23:10

As you pointed out, humans communicate via a "natural" language such as English, French, German, between each other. They are called natural because we naturally acquire them rather than intentionally invent them (Esperanto being an exception).

A formal language is one invented for some purpose or other. A programming language such as C, for instance, is a formal language invented for the purpose of programming computers.

All languages, can be described using a grammar. A hierarchy of grammars was described by Noam Chomsky in 1956. It consists of the following levels:

Type-0 grammars (unrestricted grammars). They are the most general, and are equivalent to a Turing Machine. As such, the problem of deciding whether a given string is part of an unrestricted grammar is undecidable.

Type-1 grammars (context-sensitive grammars). Almost all natural languages such as English are context-sensitive. An example of context-sensitivity in English are the two phrases: "Time flies like an arrow." and "Fruit flies like a banana." In general, it is difficult for computers to understand context-sensitive languages.

Type-2 grammars (context-free). Context-free languages are the theoretical basis for the syntax of most programming languages.

Type-3 grammars (regular grammars). The family of regular languages can be obtained by regular expressions. Regular languages are commonly used to define search patterns and the lexical structure of programming languages.

Type 2 (context-free) and type 3 (regular) grammars are most often by computers because parsers for them can be efficiently implemented.

BNF (Backus Normal Form or Backus–Naur Form) is a notation technique for context-free grammars, often used to describe the syntax of languages used in computing.

For example an identifier might be described as:

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

which means it must starts with a letter and can contain additional letters or digits.

Earlier, a letter is defined a 'a' | 'b' | 'c' etc., and digit is defined as '0' through '9' using the same type of notation.

A C "for" statement might be defined as:

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

Lexical analyzers and parsers (the first stages of a compiler or interpreter) are then constructed to accept the specific grammar described by the BNF for a particular language. Lexical analyzers are typically used to separate out the various tokens of a language (such as a keyword, identifier or a number), and the parser is used to figure out how the tokens work together, such as how a "for" statement is constructed.

  • +1 great write-up. But I'm not surprised this wasn't accepted as the answer. This is what I thought OP was asking, but based on the answer they chose, it seems they wanted something much higher level. – Matthew Rodatus Oct 25 '11 at 13:36

First, let's define "language" in terms of what it is. Language requires first a vocabulary (a list of words that define concepts that are the objects of communication), and then a syntax (a "primer" or set of rules that define the structure of the communication).

At this most basic level, C# isn't all that different from English. What makes C# a "programming language" is its intent, and therefore its design; it is designed to be digested into individual low-level commands. As such, the predefined vocabulary is limited, the syntax is very rigidly enforced, and the entire language is designed to be consumed in a very well-known predefined way by its "audience" (the computer; more accurately the compiler, which will digest the source code into an "intermediate language" of simple commands that can then be further translated into machine code by the "runtime"). You don't write prose or poetry in C#; you tell the computer to do a job in the most unambiguous way possible.

For computers, yes, a tool, usually called the compiler, is needed to take what you write in code and convert it to the instructions that the computer can use. Computer science, like most technology, is an inherently iterative, "layered" process. When computers were first invented, they were programmed by manually entering the binary instructions. Those instructions became standardized for each processor into hexadecimal "machine codes"; the difference is only in how the binary digits are grouped for display to humans. Then, in assembler code, the list of commands and some basic identifiers like register names were substituted for their hexadecimal codes when writing programs; ASM can still be converted 1:1 into native machine code. The quantum leap was to 3rd-generation "imperative" programming, which basically takes more human-understandable, abstract concepts like variables and logic loops and digests them into the native instructions, using patterns based on keywords and syntax. Early languages like COBOL, FORTRAN, Pascal, and C can still be "translated" by a human into a particular machine language (usually 8086 ASM). Then came the revolution of object-oriented programming, which is basically additional syntax rules that define code as being conceptually encapsulated in "objects" that have some combination of state and logic.

Nowadays, we are well into the "4th-generation" of languages, which are languages written to define communication with other programs instead of directly to the machine. Widely defined, this includes "markup" languages like XML/HTML, "scripting" languages like JavaScript and SQL, and most of the "sandbox" languages like Java and the .NET Framework (which compile into an IL that is then interpreted further by a runtime that abstracts away machine and platform-specific details). You could also say it encompasses the realm of functional programming languages, which are HEAVILY dependent upon a runtime to provide abstraction of not just machine-specific details, but of operation-specific details. These 4th-generation languages are more or less infeasible for a human to translate into native machine instructions, and the point is that it wouldn't be a worthwhile endeavor; the strength of these languages is the layered process in which they are used to eventually tell a computer what to do at the low levels.

  • Thanks. I have a glimpse at the history of programming language evolvement. – Erica Xu Oct 24 '11 at 21:47
  • 2
    @KeithS: You may want to reformat the last paragraph to make it a bit more readable. – Ivan Vučica Oct 25 '11 at 9:15

It is a good question. A proper answer forms a good half of what is called "Computer Science".

For starter, I'd recommend skimming through denotational and operational semantics, and then reading this book. It will give you a more or less solid understanding of what the programming language is, and how it can be formally defined.

If the above is a bit too academic, you can start with Petzold, "Code", and then come back to the semantics.

  • 2
    You really expect an 18 yo noob to read some heavy theory just to answer this question? – Job Oct 24 '11 at 20:50
  • 2
    @Job, according to his previous question, he's getting doses of Scheme (and, presumably, SICP) in the university. Should be fine with a bit of semantics then. Anyway, there is no proper answer to this question without heavy theory. – SK-logic Oct 24 '11 at 21:09
  • +1 for mentioning "Code". That book should be required reading for every entry-level CS student. – Daniel Pryden Oct 24 '11 at 23:05

If you write a program in a programming language, a different program will convert the symbols in your program into symbols the computer understands. Sometimes this takes several steps. For example in C:

  1. User writes program in high-level language (C) which is not understood by CPU, but is directly understood by the programmer (we hope!).

  2. Compiler convertes C into Assmebly language, which is not directly understood by the CPU but is easy to convert into something else that is.

  3. Assempler converts Assembly into sequence of binary codes that are directly understood by the CPU. Some compilers skip the above step (step 2) and produce the compiled binary directly from the source code.

To guarantee that the computer understands your program, the compiler or interpreter will give you an error and usually halt if it encounters something that is not compilable, such as a syntax error. If your program cannot be compiled, it can never get to the stage where your program will try to run it and fail because it did not "understand" it.

To create a new language, you first design your high-level language and then you have to find a way to map the symbols of your new language to the assembly language commands that your CPU understands.

  • 2
    Not really; modern compilers don't do step 2 and just produce binary code directly. But assembly and binary code are almost equivalent anyway; you can disassemble (convert binary code back to assembly) with very high fidelity. – MSalters Oct 25 '11 at 8:21

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.