Software, Programming Languages and Translators
Hardware and Software
Hardware is the physical equipment that makes up a computer. Software is the set of instructions that tells the hardware what to do. Neither is useful without the other: the most powerful processor in the world does nothing without software to direct it, and the cleverest program needs hardware to run on.
All software falls into one of two categories: system software, which manages the computer’s resources and provides a platform for other software to run, and application software, which performs tasks directly for the end user.
System Software
System software sits between the hardware and the user. It handles the low-level work that applications rely on. The three main types are the operating system, utility programs, and device drivers.
An operating system (OS) manages five key areas: the processor (deciding which programs get CPU time), memory (allocating RAM to programs as they open), input/output devices (communicating with keyboards, screens, printers), applications (providing services applications need, such as file access), and security (managing user accounts and access permissions). Without the OS, every application would need to include its own code for all of these — an impossible duplication of effort.
Utility programs carry out maintenance tasks. A file compression tool reduces the size of files before they are transferred; a disk cleanup tool removes temporary files to free up space; encryption software scrambles data so it cannot be read if intercepted. These are distinct from applications because they serve the system itself rather than the user’s primary tasks.
Application Software
Application software is what most people think of when they think of a program: a web browser, a word processor, a banking app, a game. Applications depend entirely on system software — they request services from the OS rather than communicating with hardware directly. This separation keeps development manageable: a game developer writes code to draw a window and play sound, and the OS handles the rest.
A common exam error is to describe an antivirus program as application software. It is a utility (system software) because its purpose is to maintain the health of the system, not to help the user complete a personal task. Similarly, a device driver is system software — the user never directly interacts with it, but the OS uses it to communicate with a printer or graphics card. Application software, by contrast, is always directly task-facing: photo editing, messaging, spreadsheets.
Programming Languages: Low-Level and High-Level
Processors can only execute instructions written in machine code — patterns of 0s and 1s. Writing in machine code directly is extremely difficult and error-prone. Programming languages were developed to give programmers a more human-readable way to express instructions.
Low-level languages are close to the hardware. They offer fine control over exactly how the processor operates, but they are difficult to read, write, and maintain. High-level languages use English-like syntax, hide the complexity of the hardware, and can run on many different types of processor without modification.
High-level languages are easier to write and debug, portable across hardware, and closer to natural language. Low-level languages give precise hardware control and can produce faster, more efficient code, but they are harder to write and specific to one processor type.
Machine Code and Assembly Language
Machine code is the only language a processor can execute directly. It is expressed entirely in binary and is specific to a processor or family of processors — code written for one architecture will not run on a different one without modification.
Assembly language replaces raw binary with short, memorable codes called mnemonics (for example, MOV to move data, ADD to add two values). Each line of assembly corresponds to exactly one machine code instruction — this is called a 1:1 correspondence. Assembly language is still tightly bound to the processor’s architecture and is most commonly used when developing software for embedded systems or when direct control over specific hardware is needed.
Translators: Compiler, Interpreter, Assembler
Because processors only understand machine code, any program written in a high-level or assembly language must be translated before it can run. There are three types of translator: the compiler, the interpreter, and the assembler.
A compiler reads the entire source code of a program and translates it all into machine code at once. The output is an executable file that can be run as many times as needed without the compiler being present. Errors are only reported after the whole program has been analysed, which makes them easier to review together. Once compiled, the program runs quickly because no further translation is needed at run time.
An interpreter translates and executes a program one line at a time. It does not produce a standalone machine code file; instead, it calls appropriate machine code subroutines within its own code to carry out each statement. If the program encounters an error mid-way, it stops at that line — making it easier to spot exactly where a mistake occurred. The downside is that the interpreter must be present every time the program runs, and execution is generally slower because translation happens at run time.
An assembler converts assembly language into machine code. Because each assembly mnemonic maps directly to one machine code instruction (the 1:1 correspondence), this translation is straightforward. Like a compiler, an assembler translates its input into machine code directly — the output is machine code that the processor can execute.
Key distinction for your exam: both assemblers and compilers translate their input directly into machine code. Interpreters do not generate machine code directly — they call machine code subroutines to carry out each statement.
Most modern high-level languages are typically run using an interpreter during development (easier debugging, immediate feedback) and compiled for the final product (faster execution, no dependency on the interpreter). Some languages use a combination of both approaches, compiling to an intermediate form before interpreting.