Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 52 additions & 0 deletions Notes/00-introduction.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# Introduction

Programming languages are fundamental tools for software developers. Their
design shapes the way we think about problems, express solutions, and organize
programs into maintainable systems.

## Why study programming languages?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we address AI here, and try to answer the question, "why should I study programming languages at all if AI is going to be the one interacting with them more than me?"

Here are some points that I think we could make:

  • A well designed programming language can make it more efficient to build programs, whether by us or by AI. In the near future, we may need to consider what makes a programming language easier for AI to work with. And you, dear reader, may well be the one doing this work.
  • The abstraction layer that AI is starting to create between us and programming, is not yet complete. At the time of writing, AI doesn't make great design decisions, and so needs us to guide it. But to make good design decisions, we need a deep understanding of how languages work.

These are not polished ideas, and you may have your own. Please feel free to shape, modify, blend, expand, contract, etc., etc., as you see fit.


Every programmer needs a deep understanding of programming languages to learn
them more easily, to use them more effectively, to evaluate their strengths and
weaknesses (particularly when assessing a new language), and to design new ones.

Most programmers think they'll never design a new programming language. However,
programming languages are one important tool of automation and abstraction. You
may never need to create a full-fledged, general-purpose language, but you may
need to design a special-purpose programming language (also called a
domain-specific language) that eases solving a narrow class of problems.

## Methodology

To deepen our understanding of programming languages, we are going to devise
some. We will start with a very simple language, and incrementally build on that
language to study increasingly more sophisticated ones. As we do, we will
explore core concepts that appear in many modern and classic programming
languages.

A programming language consists of two parts: syntax and semantics. **Syntax**
describes the notation we use to write programs in a particular language.
**Semantics** defines the meaning of programs written in a language; that is,
what a program does when we run it.

The syntax of a language is the programmer's interface to a language. From this
perspective, syntax is important. Poor syntax makes programming an onerous task.
An better syntax can make a language less error prone, easier to type, easier
to understand, and easier to maintain.

Semantics is the engine of a language. It establishes the expressive power of a
language. It is where we decide if a language support iterative statements,
conditional statements, exception handling, goto statements, functions,
procedures, closures, type checking, classes and objects, out parameters, in-out
parameters, passing parameters by reference, passing parameters by value,
continuations, parallelism, side-effects, unification, etc.

Because semantics embodies the core of a programming language, it is where we
want to spend most our time in this course. We are going to build many, rather
ugly, languages. But these languages will support important and powerful
features!

To ease this process, we are going to rely on a tool: **PLCC - Programming

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we want to make the distinction that we are using PLCC-ng here? Somewhere else? Or never?

Personally, I think we need to make the distinction so if students start Google-ing/AI-ing (can we us AI as a verb yet?) about PLCC, they get the right variation, and can properly distinguish when they are reading docs, which they are looking at.

Languages Compiler Compiler**. It will allow us to simplify the process of
building languages by automating the generation of their parsers, allowing us to
focus our efforts on implementing their semantics.
126 changes: 126 additions & 0 deletions Notes/01-overview.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
# Overview

## Interpreter

A practical way to study a programming language is to build a program that can
run programs written in that language. Such a program that reads and evaluates a
program is called an **interpreter**. Most interpreters are built around three
phases: lexical analysis, syntactic analysis, and semantic analysis.

```plantuml
@startuml
start
partition interpreter {
partition parser {
partition scanner {
-> string;
:lexical analysis;
-> tokens;
}
:syntactic analysis;
-> parse tree;
}
:semantic analysis;
}
-> (behavior);
stop
@enduml
```

## PLCC

PLCC, first mentioned in the previous section, is a powerful tool that can
generate an interpreter. PLCC generates such an interpreter based on a textual
description of the programming language we wish to design. We refer to the
textual description as a grammar.

The diagram below depicts the relationships among language designers,
programmers, and PLCC. Language designers write a grammar for the language they
are designing. They use PLCC to generate an interpreter for the language from
its grammar. Then programmers write programs in this language and use the
generated interpreter to run these programs.

```plantuml
@startuml
actor designer
actor programmer

artifact grammar [
grammar<sub>lang</sub>
]

storage plcc

storage interpreter [
interpreter<sub>lang</sub>
]

artifact program [
program<sub>lang</sub>
]

label behavior

designer .> grammar : writes
grammar -> plcc
plcc ..> interpreter :generates
program -> interpreter
interpreter -> behavior
programmer .> program : writes
@enduml
```

## Grammar

In this course, you will take on the role of a language designer. As you can see
in the figure below the grammar is broken up in three parts: lexical
specification, syntactical specification, and semantic specification. The next
three sections will over each of these parts.

```plantuml
@startuml
file grammar {
artifact lexspec as "lexical specification (regex)"
artifact synspec as "syntactical specification (BNF)"
artifact semspec as "semantic specification (e.g., Python)"
}

file source

node interpreter {
component parser {
component scanner {
component lexan as "lexical analysis"
}
component synan as "syntactical analysis"
}
component seman as "semantic analysis"
}

label behavior

lexspec -> lexan
synspec -> synan
semspec -> seman

lexspec -[hidden]-> synspec
synspec -[hidden]-> semspec

source --> lexan
lexan --> synan : tokens
synan --> seman : tree
seman --> behavior
@enduml
```

## Going Beyond

Any program processing any input expressed in a text-based programming language
must perform lexical analysis, syntactic analysis, and semantic analysis. Such
programs include compilers, interpreters, and static analyzers (i.e., linters).
So the concepts in this section apply to all such tools.

We will see that the programming language specification articulated in a grammar
is itself a small programming language. We could, in principle, write a
grammar for the PLCC specification and ask PLCC to generate an alternate version
of itself.
10 changes: 10 additions & 0 deletions Notes/style-guide.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Style guide

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds good.


This is the style guide for the notes appearing in this folder.

- Use the first voice ("we").
- Capitalize only the first word of titles
- Avoid unnecessary empty lines and trailing spaces
- Format paragraphs in 80 columns
- Let markdown applications autonumber items in ordered lists
- Use PlantUML for drawings