Skip to main content
  • Home
  • Development
  • Documentation
  • Donate
  • Operational login
  • Browse the archive

swh logo
SoftwareHeritage
Software
Heritage
Archive
Features
  • Search

  • Downloads

  • Save code now

  • Add forge now

  • Help

swh:1:snp:687ac8cdbfab3b78b7f301abee5f451127f135fc
  • Code
  • Branches (1)
  • Releases (0)
    • Branches
    • Releases
    • HEAD
    • refs/heads/master
    No releases to show
  • c6f07c2
  • /
  • lcc
  • /
  • cpp
  • /
  • eval.c
Raw File Download

To reference or cite the objects present in the Software Heritage archive, permalinks based on SoftWare Hash IDentifiers (SWHIDs) must be used.
Select below a type of object currently browsed in order to display its associated SWHID and permalink.

  • content
  • directory
  • revision
  • snapshot
content badge
swh:1:cnt:7061effd3ebab191687d70446584537bb4ab1c32
directory badge
swh:1:dir:43affbc4ca01657cd68187bc417d7e70f6145d21
revision badge
swh:1:rev:dbe4ddb10315479fc00086f08e25d968b4b43c49
snapshot badge
swh:1:snp:687ac8cdbfab3b78b7f301abee5f451127f135fc

This interface enables to generate software citations, provided that the root directory of browsed objects contains a citation.cff or codemeta.json file.
Select below a type of object currently browsed in order to generate citations for them.

  • content
  • directory
  • revision
  • snapshot
(requires biblatex-software package)
Generating citation ...
(requires biblatex-software package)
Generating citation ...
(requires biblatex-software package)
Generating citation ...
(requires biblatex-software package)
Generating citation ...
Tip revision: dbe4ddb10315479fc00086f08e25d968b4b43c49 authored by Travis Bradshaw on 31 January 2012, 19:41:34 UTC
The Quake III Arena sources as originally released under the GPL license on August 20, 2005.
Tip revision: dbe4ddb
eval.c
#include <stdlib.h>
#include <string.h>
#include "cpp.h"

#define	NSTAK	32
#define	SGN	0
#define	UNS	1
#define	UND	2

#define	UNSMARK	0x1000

struct value {
	long	val;
	int	type;
};

/* conversion types */
#define	RELAT	1
#define	ARITH	2
#define	LOGIC	3
#define	SPCL	4
#define	SHIFT	5
#define	UNARY	6

/* operator priority, arity, and conversion type, indexed by tokentype */
struct pri {
	char	pri;
	char	arity;
	char	ctype;
} priority[] = {
	{ 0, 0, 0 },		/* END */
	{ 0, 0, 0 },		/* UNCLASS */
	{ 0, 0, 0 },		/* NAME */
	{ 0, 0, 0 },		/* NUMBER */
	{ 0, 0, 0 },		/* STRING */
	{ 0, 0, 0 },		/* CCON */
	{ 0, 0, 0 },		/* NL */
	{ 0, 0, 0 },		/* WS */
	{ 0, 0, 0 },		/* DSHARP */
	{ 11, 2, RELAT },	/* EQ */
	{ 11, 2, RELAT },	/* NEQ */
	{ 12, 2, RELAT },	/* LEQ */
	{ 12, 2, RELAT },	/* GEQ */
	{ 13, 2, SHIFT },	/* LSH */
	{ 13, 2, SHIFT },	/* RSH */
	{ 7, 2, LOGIC },	/* LAND */
	{ 6, 2, LOGIC },	/* LOR */
	{ 0, 0, 0 },		/* PPLUS */
	{ 0, 0, 0 },		/* MMINUS */
	{ 0, 0, 0 },		/* ARROW */
	{ 0, 0, 0 },		/* SBRA */
	{ 0, 0, 0 },		/* SKET */
	{ 3, 0, 0 },		/* LP */
	{ 3, 0, 0 },		/* RP */
	{ 0, 0, 0 },		/* DOT */
	{ 10, 2, ARITH },	/* AND */
	{ 15, 2, ARITH },	/* STAR */
	{ 14, 2, ARITH },	/* PLUS */
	{ 14, 2, ARITH },	/* MINUS */
	{ 16, 1, UNARY },	/* TILDE */
	{ 16, 1, UNARY },	/* NOT */
	{ 15, 2, ARITH },	/* SLASH */
	{ 15, 2, ARITH },	/* PCT */
	{ 12, 2, RELAT },	/* LT */
	{ 12, 2, RELAT },	/* GT */
	{ 9, 2, ARITH },	/* CIRC */
	{ 8, 2, ARITH },	/* OR */
	{ 5, 2, SPCL },		/* QUEST */
	{ 5, 2, SPCL },		/* COLON */
	{ 0, 0, 0 },		/* ASGN */
	{ 4, 2, 0 },		/* COMMA */
	{ 0, 0, 0 },		/* SHARP */
	{ 0, 0, 0 },		/* SEMIC */
	{ 0, 0, 0 },		/* CBRA */
	{ 0, 0, 0 },		/* CKET */
	{ 0, 0, 0 },		/* ASPLUS */
 	{ 0, 0, 0 },		/* ASMINUS */
 	{ 0, 0, 0 },		/* ASSTAR */
 	{ 0, 0, 0 },		/* ASSLASH */
 	{ 0, 0, 0 },		/* ASPCT */
 	{ 0, 0, 0 },		/* ASCIRC */
 	{ 0, 0, 0 },		/* ASLSH */
	{ 0, 0, 0 },		/* ASRSH */
 	{ 0, 0, 0 },		/* ASOR */
 	{ 0, 0, 0 },		/* ASAND */
	{ 0, 0, 0 },		/* ELLIPS */
	{ 0, 0, 0 },		/* DSHARP1 */
	{ 0, 0, 0 },		/* NAME1 */
	{ 16, 1, UNARY },	/* DEFINED */
	{ 16, 0, UNARY },	/* UMINUS */
};

int	evalop(struct pri);
struct	value tokval(Token *);
struct value vals[NSTAK], *vp;
enum toktype ops[NSTAK], *op;

/*
 * Evaluate an #if #elif #ifdef #ifndef line.  trp->tp points to the keyword.
 */
long
eval(Tokenrow *trp, int kw)
{
	Token *tp;
	Nlist *np;
	int ntok, rand;

	trp->tp++;
	if (kw==KIFDEF || kw==KIFNDEF) {
		if (trp->lp - trp->bp != 4 || trp->tp->type!=NAME) {
			error(ERROR, "Syntax error in #ifdef/#ifndef");
			return 0;
		}
		np = lookup(trp->tp, 0);
		return (kw==KIFDEF) == (np && np->flag&(ISDEFINED|ISMAC));
	}
	ntok = trp->tp - trp->bp;
	kwdefined->val = KDEFINED;	/* activate special meaning of defined */
	expandrow(trp, "<if>");
	kwdefined->val = NAME;
	vp = vals;
	op = ops;
	*op++ = END;
	for (rand=0, tp = trp->bp+ntok; tp < trp->lp; tp++) {
		switch(tp->type) {
		case WS:
		case NL:
			continue;

		/* nilary */
		case NAME:
		case NAME1:
		case NUMBER:
		case CCON:
		case STRING:
			if (rand)
				goto syntax;
			*vp++ = tokval(tp);
			rand = 1;
			continue;

		/* unary */
		case DEFINED:
		case TILDE:
		case NOT:
			if (rand)
				goto syntax;
			*op++ = tp->type;
			continue;

		/* unary-binary */
		case PLUS: case MINUS: case STAR: case AND:
			if (rand==0) {
				if (tp->type==MINUS)
					*op++ = UMINUS;
				if (tp->type==STAR || tp->type==AND) {
					error(ERROR, "Illegal operator * or & in #if/#elsif");
					return 0;
				}
				continue;
			}
			/* flow through */

		/* plain binary */
		case EQ: case NEQ: case LEQ: case GEQ: case LSH: case RSH:
		case LAND: case LOR: case SLASH: case PCT:
		case LT: case GT: case CIRC: case OR: case QUEST:
		case COLON: case COMMA:
			if (rand==0)
				goto syntax;
			if (evalop(priority[tp->type])!=0)
				return 0;
			*op++ = tp->type;
			rand = 0;
			continue;

		case LP:
			if (rand)
				goto syntax;
			*op++ = LP;
			continue;

		case RP:
			if (!rand)
				goto syntax;
			if (evalop(priority[RP])!=0)
				return 0;
			if (op<=ops || op[-1]!=LP) {
				goto syntax;
			}
			op--;
			continue;

		default:
			error(ERROR,"Bad operator (%t) in #if/#elsif", tp);
			return 0;
		}
	}
	if (rand==0)
		goto syntax;
	if (evalop(priority[END])!=0)
		return 0;
	if (op!=&ops[1] || vp!=&vals[1]) {
		error(ERROR, "Botch in #if/#elsif");
		return 0;
	}
	if (vals[0].type==UND)
		error(ERROR, "Undefined expression value");
	return vals[0].val;
syntax:
	error(ERROR, "Syntax error in #if/#elsif");
	return 0;
}

int
evalop(struct pri pri)
{
	struct value v1, v2;
	long rv1, rv2;
	int rtype, oper;

	rv2=0;
	rtype=0;
	while (pri.pri < priority[op[-1]].pri) {
		oper = *--op;
		if (priority[oper].arity==2) {
			v2 = *--vp;
			rv2 = v2.val;
		}
		v1 = *--vp;
		rv1 = v1.val;
/*lint -e574 -e644 */
		switch (priority[oper].ctype) {
		case 0:
		default:
			error(WARNING, "Syntax error in #if/#endif");
			return 1;
		case ARITH:
		case RELAT:
			if (v1.type==UNS || v2.type==UNS)
				rtype = UNS;
			else
				rtype = SGN;
			if (v1.type==UND || v2.type==UND)
				rtype = UND;
			if (priority[oper].ctype==RELAT && rtype==UNS) {
				oper |= UNSMARK;
				rtype = SGN;
			}
			break;
		case SHIFT:
			if (v1.type==UND || v2.type==UND)
				rtype = UND;
			else
				rtype = v1.type;
			if (rtype==UNS)
				oper |= UNSMARK;
			break;
		case UNARY:
			rtype = v1.type;
			break;
		case LOGIC:
		case SPCL:
			break;
		}
		switch (oper) {
		case EQ: case EQ|UNSMARK:
			rv1 = rv1==rv2; break;
		case NEQ: case NEQ|UNSMARK:
			rv1 = rv1!=rv2; break;
		case LEQ:
			rv1 = rv1<=rv2; break;
		case GEQ:
			rv1 = rv1>=rv2; break;
		case LT:
			rv1 = rv1<rv2; break;
		case GT:
			rv1 = rv1>rv2; break;
		case LEQ|UNSMARK:
			rv1 = (unsigned long)rv1<=rv2; break;
		case GEQ|UNSMARK:
			rv1 = (unsigned long)rv1>=rv2; break;
		case LT|UNSMARK:
			rv1 = (unsigned long)rv1<rv2; break;
		case GT|UNSMARK:
			rv1 = (unsigned long)rv1>rv2; break;
		case LSH:
			rv1 <<= rv2; break;
		case LSH|UNSMARK:
			rv1 = (unsigned long)rv1<<rv2; break;
		case RSH:
			rv1 >>= rv2; break;
		case RSH|UNSMARK:
			rv1 = (unsigned long)rv1>>rv2; break;
		case LAND:
			rtype = UND;
			if (v1.type==UND)
				break;
			if (rv1!=0) {
				if (v2.type==UND)
					break;
				rv1 = rv2!=0;
			} else
				rv1 = 0;
			rtype = SGN;
			break;
		case LOR:
			rtype = UND;
			if (v1.type==UND)
				break;
			if (rv1==0) {
				if (v2.type==UND)
					break;
				rv1 = rv2!=0;
			} else
				rv1 = 1;
			rtype = SGN;
			break;
		case AND:
			rv1 &= rv2; break;
		case STAR:
			rv1 *= rv2; break;
		case PLUS:
			rv1 += rv2; break;
		case MINUS:
			rv1 -= rv2; break;
		case UMINUS:
			if (v1.type==UND)
				rtype = UND;
			rv1 = -rv1; break;
		case OR:
			rv1 |= rv2; break;
		case CIRC:
			rv1 ^= rv2; break;
		case TILDE:
			rv1 = ~rv1; break;
		case NOT:
			rv1 = !rv1; if (rtype!=UND) rtype = SGN; break;
		case SLASH:
			if (rv2==0) {
				rtype = UND;
				break;
			}
			if (rtype==UNS)
				rv1 /= (unsigned long)rv2;
			else
				rv1 /= rv2;
			break;
		case PCT:
			if (rv2==0) {
				rtype = UND;
				break;
			}
			if (rtype==UNS)
				rv1 %= (unsigned long)rv2;
			else
				rv1 %= rv2;
			break;
		case COLON:
			if (op[-1] != QUEST)
				error(ERROR, "Bad ?: in #if/endif");
			else {
				op--;
				if ((--vp)->val==0)
					v1 = v2;
				rtype = v1.type;
				rv1 = v1.val;
			}
			break;
		case DEFINED:
			break;
		default:
			error(ERROR, "Eval botch (unknown operator)");
			return 1;
		}
/*lint +e574 +e644 */
		v1.val = rv1;
		v1.type = rtype;
		*vp++ = v1;
	}
	return 0;
}

struct value
tokval(Token *tp)
{
	struct value v;
	Nlist *np;
	int i, base, c;
	unsigned long n;
	uchar *p;

	v.type = SGN;
	v.val = 0;
	switch (tp->type) {

	case NAME:
		v.val = 0;
		break;

	case NAME1:
		if ((np = lookup(tp, 0)) != NULL && np->flag&(ISDEFINED|ISMAC))
			v.val = 1;
		break;

	case NUMBER:
		n = 0;
		base = 10;
		p = tp->t;
		c = p[tp->len];
		p[tp->len] = '\0';
		if (*p=='0') {
			base = 8;
			if (p[1]=='x' || p[1]=='X') {
				base = 16;
				p++;
			}
			p++;
		}
		for (;; p++) {
			if ((i = digit(*p)) < 0)
				break;
			if (i>=base)
				error(WARNING,
				  "Bad digit in number %t", tp);
			n *= base;
			n += i;
		}
		if (n>=0x80000000 && base!=10)
			v.type = UNS;
		for (; *p; p++) {
			if (*p=='u' || *p=='U')
				v.type = UNS;
			else if (*p=='l' || *p=='L')
				;
			else {
				error(ERROR,
				  "Bad number %t in #if/#elsif", tp);
				break;
			}
		}
		v.val = n;
		tp->t[tp->len] = c;
		break;

	case CCON:
		n = 0;
		p = tp->t;
		if (*p=='L') {
			p += 1;
			error(WARNING, "Wide char constant value undefined");
		}
		p += 1;
		if (*p=='\\') {
			p += 1;
			if ((i = digit(*p))>=0 && i<=7) {
				n = i;
				p += 1;
				if ((i = digit(*p))>=0 && i<=7) {
					p += 1;
					n <<= 3;
					n += i;
					if ((i = digit(*p))>=0 && i<=7) {
						p += 1;
						n <<= 3;
						n += i;
					}
				}
			} else if (*p=='x') {
				p += 1;
				while ((i = digit(*p))>=0 && i<=15) {
					p += 1;
					n <<= 4;
					n += i;
				}
			} else {
				static char cvcon[]
				  = "b\bf\fn\nr\rt\tv\v''\"\"??\\\\";
				for (i=0; i<sizeof(cvcon); i+=2) {
					if (*p == cvcon[i]) {
						n = cvcon[i+1];
						break;
					}
				}
				p += 1;
				if (i>=sizeof(cvcon))
					error(WARNING,
					 "Undefined escape in character constant");
			}
		} else if (*p=='\'')
			error(ERROR, "Empty character constant");
		else
			n = *p++;
		if (*p!='\'')
			error(WARNING, "Multibyte character constant undefined");
		else if (n>127)
			error(WARNING, "Character constant taken as not signed");
		v.val = n;
		break;

	case STRING:
		error(ERROR, "String in #if/#elsif");
		break;
	}
	return v;
}

int
digit(int i)
{
	if ('0'<=i && i<='9')
		i -= '0';
	else if ('a'<=i && i<='f')
		i -= 'a'-10;
	else if ('A'<=i && i<='F')
		i -= 'A'-10;
	else
		i = -1;
	return i;
}

back to top

Software Heritage — Copyright (C) 2015–2026, The Software Heritage developers. License: GNU AGPLv3+.
The source code of Software Heritage itself is available on our development forge.
The source code files archived by Software Heritage are available under their own copyright and licenses.
Terms of use: Archive access, API— Content policy— Contact— JavaScript license information— Web API