Skip to content

Instantly share code, notes, and snippets.

@iglosiggio
Last active March 29, 2023 18:36
Show Gist options
  • Save iglosiggio/b9f0452123160fe147488bf348047605 to your computer and use it in GitHub Desktop.
Save iglosiggio/b9f0452123160fe147488bf348047605 to your computer and use it in GitHub Desktop.
A simple recursive-descent parser for logic formulas (the precedences are probably wrong)
const nextToken = s => {
// Remove leading spaces
s = s.trim()
if (s.length === 0) return [{ kind: 'eof' }, s.slice(0)]
if (s.startsWith('V')) return [{ kind: 'or' }, s.slice(1)]
if (s.startsWith('^')) return [{ kind: 'and' }, s.slice(1)]
if (s.startsWith('->')) return [{ kind: 'then' }, s.slice(2)]
if (s.startsWith('<->')) return [{ kind: 'iff' }, s.slice(3)]
if (s.startsWith('(')) return [{ kind: 'lparen' }, s.slice(1)]
if (s.startsWith(')')) return [{ kind: 'rparen' }, s.slice(1)]
if (s.startsWith('Posta')) return [{ kind: 'true' }, s.slice(5)]
if (s.startsWith('Chamuyo')) return [{ kind: 'false' }, s.slice(7)]
// Identifier
const ident_pattern = /^[a-z]+/
const match = ident_pattern.exec(s)
if (match != null) {
const ident = match[0]
return [{ kind: 'ident', ident }, s.slice(ident.length)]
}
}
function tokenize(s) {
let tokens = []
let token
do {
[token, s] = nextToken(s)
tokens.push(token)
} while (token.kind !== 'eof')
return tokens
}
function parse(s) {
let tokens = tokenize(s)
function peek() {
return tokens[0]
}
function pop() {
return tokens.shift()
}
return parse_iff()
function parse_iff() {
let expr = parse_then()
while (peek().kind === 'iff') {
pop()
expr = { kind: 'iff', lhs: expr, rhs: parse_then() }
}
return expr
}
function parse_then() {
let expr = parse_or()
while (peek().kind === 'then') {
pop()
expr = { kind: 'then', lhs: expr, rhs: parse_or() }
}
return expr
}
function parse_or() {
let expr = parse_and()
while (peek().kind === 'or') {
pop()
expr = { kind: 'or', lhs: expr, rhs: parse_and() }
}
return expr
}
function parse_and() {
let expr = parse_paren() || parse_var() || parse_lit()
if (expr === undefined) throw new Error('Something somewhere failed!')
while (peek().kind === 'and') {
pop()
expr = { kind: 'and', lhs: expr, rhs: parse_paren() || parse_var() || parse_lit() }
}
return expr
}
function parse_var() {
let token = peek()
if (token.kind === 'ident') {
pop()
return token.ident
}
}
function parse_lit() {
let token = peek()
if (token.kind === 'true') {
pop()
return true
}
if (token.kind === 'false') {
pop()
return false
}
}
function parse_paren() {
if (peek().kind === 'lparen') {
pop()
let result = parse_iff()
if (result !== undefined && peek().kind === 'rparen') {
pop()
return result
}
}
}
}
console.log(JSON.stringify(parse('Posta -> (a -> Chamuyo <-> b ^ c V a^j)'), null, 2))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment